function Person(name, age, job) {
this.name   = name;
this.age    = age;
this.job    = job;
this.friends = ['Shelby', 'Court'];

if (typeof this.sayName != 'function') {
Person.prototype = {
constructor: Person,
sayName: function() {
alert(this.name);
}
};
}
}

var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 29, 'Doctor');

alert(person1.sayName === person2.sayName);但书中这种写法却返回true:function Person(name, age, job) {
this.name   = name;
this.age    = age;
this.job    = job;
this.friends = ['Shelby', 'Court'];

if (typeof this.sayName != 'function') {
Person.prototype.sayName = function() {
alert(this.name);
};
}
}

var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 29, 'Doctor');

alert(person1.sayName === person2.sayName);
为什么会这样??

解决方案 »

  1.   


    alert(person1.sayName);
    alert(person2.sayName);
    看看就知道了
      

  2.   

    Person.prototype = {
                    constructor: Person,
                    sayName: function() {
                        alert(this.name);
                    }
                };你new的时候 改变或者说 新建了 Person.prototype
    那么 new的时候的这个object.prototype 指向你当前新建的Person.prototype
    Person.prototype.sayName = function() {
                    alert(this.name);
                };
    书上的写法 Person.prototype 一直没变过 你永远指向这个Person.prototype
    当你访问 sayName的时候 才开始从 prototype上开始查找sayName
    那么 是一个地方
      

  3.   

    (1)第一种方式属于重写原型对象,这种方式定义的原型对象 只有在定义后的下一次new时才能生效。在你的代码中就是:
    第一次new时,只是完成了新原型对象的定义,但是新的原型对象的属性方法并没有赋给person1,person1的原型对象仍然是原生的Person.prototype。因为原生的原型对象中并没有sayName这个方法,所以person1.sayName的值是“undefined”。
    等到第二次new的时候,此时Person.prototype已被重写,所以person2会拥有重写后的原型对象中所有属性方法的,person2.sayName的值是“function(){alert(this.name)}”。(2)第二种就不用说了,~~直接在原生的原型对象上追加,person1和person2有着共同的原型对象,自然共享原型里的属性和方法。
      

  4.   


    但为什么第二次new时才生效?
      

  5.   

    有趣的例子。
    这个估计要从new到底干了什么说起吧。new操作先创建空对象,然后链接对象的原型到构造器的原型上,然后再运行构造器。chrome下有个东东叫__proto__,这个家伙就是prototype的具体实现。var person1 = new Person();
    //翻译一下new
    var person1 = new Object();
    person1.__proto__ = Person.prototype;
    Person.call(person1);这俩是等价的。
    接着看这个:var o = {};
    var a = o;
    o = {c:1};
    b = o;
    alert(a.c === b.c); //自然是false对照下来是这样:person1.__proto__ = Person.prototype;
    Person.prototype = {sayName:function(){}};
    person2.__proto__ = Person.prototype;
    alert(person1.__proto__.sayName === person2.__proto__.sayName); //自然也是false但如果是这样:person1.__proto__ = Person.prototype;
    Person.prototype.sayName = function(){};
    person2.__proto__ = Person.prototype;
    alert(person1.__proto__.sayName === person2.__proto__.sayName); //那就是true了我觉得引入__proto__更能帮助理解prototype原型链。
      

  6.   


    但为什么第二次new时才生效?
    Person.prototype是在声明函数Person后就默认存在的,只不过是个没有添加属性和方法的空对象而已。为什么第二次才有效?因为第一次new之前,重写的原型对象还不存在,Person.prototype是原生的空原型对象。在第二次new之前,重写的原型对象Person.prototype(因为第一次new)已经存在,而且包含一个属性一个方法。
    person1和person2各自的原型对象是不一样的,一个是空对象,一个是包含一个属性和一个方法的对象。
      

  7.   

    楼主可以参考一下 EcmaScript 的规范 http://ecmascript.cn/ 里面 13.2.2 节关于 Construct 的描述。一个完整的 new 构造过程是首先构造一个原始的 obj,然后指定一个原型的指针,以该 obj 作为参数调用构造器的 call 方法。也就是说,在 person1 调用构造器之前,已经设置了该原型的指针,在构造器中重新指定了构造器的 prototype 对象的话,不会影响当前 person1 对原型对象的引用。换句话说,按照第一种写法,person1 和 person2 实际上引用了不同的原型对象。