javascript 原型问题

function Person(name) {
    this.name = name;
}

var p1 = new Person("张三");

Person.prototype.greeting = function () {
    return "你好,我叫" + this.name;
};

p1.name;                      // 张三
p1.greeting();                // 你好,我叫张三
p1.constructor === Person;    // true

/* so far so good, but... */

Person.prototype = {
    say: function () {
        return "你好,我叫" + this.name;
    }
};

p1.say();                    // TypeError: Object #<Person> has no method 'say'
p1.constructor.prototype;    // Object { say: function }

Person 的原型属性里明明有 say 方法,为什么访问不到,求解释,谢谢!

阅读 4.7k
4 个回答

咦?这个例子好眼熟的说……

因为你在实例化 p1 以后覆盖了原型对象(用一个新的对象字面量赋值了),而 p1 拥有的是指向旧的原型对象的指针。

另外,p1.constructor 指向的是构造器本身,所以它可以获取到新的原型对象。如果你用 Person.prototype.say = function () {...} 的方式去追加方法(这就不是覆盖了),那么 p1.say() 就会正常访问。

BTW,在覆盖的前提下也可以这样访问到:

p1.constructor.prototype.say.call(p1); // 绑定上下文为 p1,this.name 指向 p1.name
function Person() {...}
Person.prototype.greeting = function() {...};
var p1 = new Person();
p1.__proto__ === Person.prototype; // true

Person.prototype = {say: function() {...}}; // 这是一个新创建的对象
p1.__proto__ === Person.prototype; // false

解释:

Person的prototype被新创建的{say: function() {...}}覆盖后,
p1引用的原型对象仍然指向Person之前旧的那个prototype对象。
所以调用p1.say();在原型链找不到这个方法

new Person()的过程实际上执行了3步操作

var o = {__proto__: Person.prototype};
Person.apply(o);
return o;

然后o被赋值给了p1,p1实际上是通过__proto__属性来访问Person.prototype,p1在访问一个属性的时候,会先在自己的属性里查找,如果没有的话会查找p1.__proto__指向的原型对象,后来Person.prototype被改写了,但是p1.__proto__还是指向了原先的原型对象,所以访问不到say方法

因为p1new的时候Person.prototype指向X(这里X是代称).
其中, X.greeting是一个你自定义的函数.
这个时候p1.__proto__ === X, 所以p1.greeting可以正常访问.

然后, 你改Person.prototype指向Y(这里Y是代称), 这里就是关键!
其中, Y.say是一个你自定义的函数.
但这个时候p1.__proto__ === X仍然为真(也就是说p1.__proto__ !== Y), 所以此时p1.greeting仍可以正常执行, 但p1.say是不可以(因为X里面没有say这个函数).

另外, 如果最后你再做一个p2 = new Person("李四");, p2.say是可以的(因为p2.__proto__ === Y), 但是p2.greeting是不可以的.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题