对象的原型
如机制和原理(对象基于原型)里所记述的那样,JavaScript是一个基于原型的面向对象的语言。 本文着重于对原型的实现机制进行剖析和说明。
原型链的实现
JavaScript里所有的对象都有一个名为__proto__的属性,这个属性里面存放的就是对象所参照的原型对象的引用。
__proto__中的对象连在一起就构成了一个原型链,链的顶端就是Object.prototype对象,Object.prototype的__proto__属性值则是null
__proto__属性被包含在ECMAScript6之中,但之前基本上已被大多数浏览器厂商所支持。
通过Object.getPrototypeOf()可以获得指定对象的原型对象,这也是被推荐的使用方法。但__proto__属性是可读写的,这也意味着程序可以通过该属性动态的改变对象的原型对象。
__proto__属性被包含在ECMAScript6之中,但之前基本上已被大多数浏览器厂商所支持。
通过Object.getPrototypeOf()可以获得指定对象的原型对象,这也是被推荐的使用方法。但__proto__属性是可读写的,这也意味着程序可以通过该属性动态的改变对象的原型对象。
原型的自动设置
当通过构造函数创建新对象时,JavaScript会自动将构造函数的prototype属性值设置到新对象的__proto__属性里。
作为示例,我们首先声明一个类(构造函数)Person
var Person = function(name) { this.name = name; }; Person.prototype.getName = function() { return this.name; };
然后我们创建一个Person的对象。
var tom = new Person("Tom");
上面创建Person对象的代码与下面的程序逻辑是等价的,事实上JavaScript也是这样执行的。
var tom = new Object(); tom.__proto__ = Person.prototype; tom = Person.call(tom,"Tom");
属性的继承
当访问对象的属性时,JavaScript会通过遍历原型链进行查找,直到找到给定名称的属性为止。
如果查找进行到原型链的顶部-Object.prototype仍然没有找到指定名称的属性时,就会返回undefined。
由于这个查值过程是一个遍历过程,所以当属性的值越靠近顶层,查找性能就会越低,而当值靠近底层时,查找性能就会高很多,所以在编写复杂的应用时,一定要提防原型链过长而带来的性能问题。
而设值对象属性则不会遍历原型链,而是直接将属性添加到该对象自身,并不影响到原型链中的对象。
//接上面的例子 //下面这条语句直接取的是tom对象的属性值 console.log(tom.name); // 输出:Tom //下面这条语句执行的是tom.__proto__(引用的是Person.prototype)的getName方法 tom.getName(); // 输出:Tom