JavaScript继承机制之prototype, __proto__, constructor

每个函数都自动具有prototype属性, 每个对象都自动有__proto__, 它们的关系就是是同一个对象. 看下面的代码:

function A(){

}

var a = new A();

alert(a.__proto__===A.prototype);//结果是 true .

实际上每个函数的 prototype 是一个最基本的 Object 对象. 我们知道 prototype 的意义是使用这个函数创建的对象(var a = new A();)会被赋予函数 prototype 对象的全部属性(包括函数属性), JavaScript 正是利用这个特性来完成基础功能的. 例如:

function B(){

}

B.prototype = a;

var b = new B();//则b会被赋予a对象的属性.

利用这个特性可以形成一个继承链, 需要指出的是, 所谓的继承来的属性, 最初是不存在的, 我们读取这个属性的时候, 实际上是从__proto__属性里去查找的, 因为__proto__也有__proto__属性, 所以是一个继承链.__proto__属性的终点是null, 每一个最原始的Object对象的__proto__是一个全局Object对象, 此对象的__proto__是null, 是区别于普通Object的.

JavaScrip的 null 是一个全局常数对象, 但是JavaScript并没有提供这个全局__proto__对象的访问, 因为这意味着我们可以给全局的Object添加属性, 只要给这个全局__proto__添加属性就行了.  JavaScript没有把普通Object的__proto__指向null而是指向一个特殊的全局对象, 这或许有某种原因, 但是不得而知.

当我们修改一个对象的属性的时候, 即使这属性是它原型上(__proto__)的, 实际上是添加或修改自身的属性, 而不会改变原型对象. 当然, 这是必须的, 这样做是为了平衡性能资源消耗和完成继承功能的内部优化.

一般情况下, 对象的constructor属性就是生成它的函数, 比如:

alert(a.constructor===A)//true

但是对于有继承的情况就不同了, b的constructor实际上也是A, 也就是说, constructor属性是会追随原型链的.

alert(b.constructor===A)//true

每个对象还有一个基本函数 isPrototypeOf , 这个函数用来检测对象是否是另一个对象的原型, 本质上就是

c.__proto__.isPrototypeOf(c);//返回true.

可以利用这个函数检测对象是否是某个类型, 而避免使用constructor导致的追溯继承链干扰. 比如要检测b是否是B生成的对象, 可以这样调用:

B.prototype.isPrototypeOf(b);

返回值可以判断 b 是否是由 new B() 生成的.

Google V8 引擎下的 PrototypeTemplate()就是函数的prototype属性, 而InstanceTemplate() 用来给每个实例添加属性, 所以这个两个方法上添加的属性, 实例都具有, 而且都可以继承, 因为继承函数的prototype就是一个父类对象.

但是PrototypeTemplate的效率更高, 因为InstanceTemplate()是在每个实例上添加属性, 而前者是在原型上添加一次. 需要注意的是, 如果InstanceTemplate()上添加的属性是一个对象, 实际上对象的引用特性, 所有实例的这个属性是指向同一个对象的. 而我们使用InstanceTemplate的目的就是要让对象的这个属性彼此独立(否则用PrototypeTemplate就行了), 所以如果需要这个属性不同, 就必须在对象生成后添加. (init_inst()里面). 值类型的属性可以在InstanceTemplate里面添加.



你可能感兴趣的:(JavaScript继承机制之prototype, __proto__, constructor)