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 方法,为什么访问不到,求解释,谢谢!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
咦?这个例子好眼熟的说……
因为你在实例化
p1以后覆盖了原型对象(用一个新的对象字面量赋值了),而p1拥有的是指向旧的原型对象的指针。另外,
p1.constructor指向的是构造器本身,所以它可以获取到新的原型对象。如果你用Person.prototype.say = function () {...}的方式去追加方法(这就不是覆盖了),那么p1.say()就会正常访问。BTW,在覆盖的前提下也可以这样访问到:
Person的prototype被新创建的{say: function() {...}}覆盖后,
p1引用的原型对象仍然指向Person之前旧的那个prototype对象。
所以调用p1.say();在原型链找不到这个方法
new Person()的过程实际上执行了3步操作然后o被赋值给了p1,p1实际上是通过
__proto__属性来访问Person.prototype,p1在访问一个属性的时候,会先在自己的属性里查找,如果没有的话会查找p1.__proto__指向的原型对象,后来Person.prototype被改写了,但是p1.__proto__还是指向了原先的原型对象,所以访问不到say方法因为
p1在new的时候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是不可以的.