前言
最近碰到一个题,大家可以试下。
Object.prototype.a = function() {
console.log("aaa "+this.name);
};
Function.prototype.b = function() {
console.log("bbb "+this.name);
};
function Person(name) {
this.name = name;
}
var person = new Person("China");
问:person.a() person.b()分别返回什么?
资料引用
上述题目考察的是JavaScript原型链的问题。我们引用《JavaScript高级程序设计(第三版)》中关于原型对象的相关叙述。
- 列表内容
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个指针叫[[Prototype]]。脚本中没有标准的方式访问[[Prototype]],但浏览器在每个对象上都支持一个属性__proto__。该连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。
分析问题
通过上面的说明,我们再来看下那个题目。构造函数Person有个prototype属性,指向Person的原型对象。而Person.prototype也是一个对象,则内部有[[Prototype]]指针,指向构造函数的原型对象,而该对象的构造函数则是Object()。Person.prototype.__proto__ -----> Object.prototype
。而实例person的内部指针[[Prototype]]则指向构造函数Person的原型Person.prototype。
解决问题
通过上面的分析,我们就构造了一条原型链:
person.\__ptoto__ -----> Person.prototype
所以person.a()通过原型链查找,最终找到Object.prototype中的方法a,控制台输出aaa China,而没有找到方法b,所以会报错,显示TypeError: undefined is not a function
深入理解
在问题中,构造函数Person同样也是Function的一个实例,所以Person.__proto__ —–> Function.prototype。而构造函数继承的是Prerson.prototype,而不是Person.\__proto__。
可以通过isPrototypeOf()确定某个对象是否是另一个对象的原型。
Person.prototype.isPrototypeOf(person); //true
另外,ECMA5增加了一个方法Object.getPrototypeOf()来代替__proto__,返回[[Prototype]]的值。
对于操作符instanceof,判断某个对象是否属于某个构造函数,就是通过判断该构造函数的prototype属性是否存在对象的原型链上。
Person instanceof Function; //true
而虽然Object.getPrototypeOf(Function)返回结果是function Empty(){},但
Function instanceof Object仍然返回true,则只能算是甲鱼的臀部——规定啦。
另外,ECMA5提供了一个继承方法Object.create(proto, [ propertiesObject ]),创建一个拥有指定原型和若干个指定属性的对象。
// 只继承Person.prototype 而不实例化name属性
var person = Object.create(Person.prototype);
//但下面仍为true
person instanceof Person;