prototype
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
function Animal(name) {
this.name = name;
}
原型链
js中所有对象都有自己的prototype。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个prototype chain
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。
那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
constructor
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数
function P() {}
P.prototype.constructor === P // true
constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的。
function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr //true
constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。
function Person(name) {
this.name = name;
}
Person.prototype.constructor === Person // true
Person.prototype = {
method: function () {}
};
Person.prototype.constructor === Person // false
Person.prototype.constructor === Object // true
所以,修改原型对象时,一般要同时修改constructor属性的指向。
// 好的写法
C.prototype = {
constructor: C,
method1: function (...) { ... },
// ...
};
// 更好的写法
C.prototype.method1 = function (...) { ... };
instanceof
instanceof 运算符返回一个布尔值,表示对象是否为某个构造函数的实例
var v = new Vehicle();
v instanceof Vehicle //true
// 等同于
Vehicle.prototype.isPrototypeOf(v)
由于任意对象(除了null)都是Object的实例,所以instanceof运算符可以判断一个值是否为非null的对象
var obj = {foo: 123};
obj instanceof Object //ture
null instanceof Object //false
instanceof的原理是检查右边构造函数的prototype属性,是否在左边对象的原型链上。有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。
var obj = Object.create(null);
typeof obj // "object"
Object.create(null) instanceof Object //false
网友评论