您的位置:首页 > Web前端 > JavaScript

JavaScript继承机制之prototype, __proto__, constructor

2013-02-18 16:05 585 查看
每个函数都自动具有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里面添加.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: