首页 Javascript 正文
196

Javascript之原型链

Javascript将数据分为两大类型:原生类型和对象类型。
原生类型包括number, string, boolean, undefined, null五种,除此之外都是对象类型,比如Object,  Function, Array。

Javascript中所有的对象类型都具有一个隐藏属性__proto__(仅在firefox中暴露了此属性), 它就是原型链的指针。默认情况下,__proto__指向的是构造函数的prototype, 即:var obj = new XX(); obj.__proto__ === XX.prototype成立。
我们知道创建对象有两种方式,一种是字面量创建,另一种是利用构造函数创建。

一、字面量创建的对象 或者 由 new Object()创建
var a = {a:1}, b = {b:2};
此时对象a,b的原型都是默认指向了Object.prototype,即:
a.__proto__  => Object.prototype
b.__proto__  => Object.prototype
Object.prototype.__proto__ => null
我们可以手动将对象b的原型替换掉,如下:
var a = {a:1}, b = {b:2, __proto__:a};//直接给__proto__赋值并不是每个浏览器都支持,所以ES5标准化了一个实现原型继承的可选方法,即使用Object.create函数,比如此处可以换成:b = Object.create(a, {b: {value: 2}});
此时的原型链如下:
b.__proto__ => a
a.__proto__ => Object.prototype
Object.prototype.__proto__ => null

二、使用构造函数创建的对象
相对于字面量创建对象有一点不同的是,构造函数创建一个实例对象的时候,会额外地做一个处理,那就是将实例对象的__proto__指向到构造函数的属性prototype上(prototype相当于上面例子中对象a的角色)。这里有一点要说明的是,构造函数具有一个默认的属性prototype, 它的值也是一个对象,此构造函数创建的实例都会通过各自的__proto__属性指向到这个prototype对象上,也就是说,构造函数的prototype对象为所有实例共享,在构建对象继承关系时,要特别注意这种共享原型对象所带来的数据污染。
构造函数除了具有prototype之外,也有__proto__属性,它指向的是Function.prototype(可以将构造函数视为Function的实例)。思考以下代码
function Foo(y) {
  this.y = y;
}
Foo.prototype.x = 10;
Foo.prototype.calculate = function (z) {
  return this.x + this.y + z;
};

var b = new Foo(20);
var c = new Foo(30);
b.calculate(30); // 60
c.calculate(40); // 80
console.log(
  b.__proto__ === Foo.prototype, // true
  c.__proto__ === Foo.prototype, // true

  b.constructor === Foo, // true
  c.constructor === Foo, // true
  Foo.prototype.constructor === Foo // true

  b.calculate === b.__proto__.calculate, // true
  b.__proto__.calculate === Foo.prototype.calculate // true
);


我们可以手动将构造函数的prototype对象替换成另一个对象,但是替换了这个对象之后,一定要记得将constructor正确的补上。
比如:
Foo.prototype = {};//将Foo的默认prototype替换成了另外一个空对象。此时,constructor这个默认属性也消失了,我们必须补回来。
Foo.prototype.constructor = Foo;
参考:http://weizhifeng.net/javascript-the-core.html#prototype-chain

正在加载评论...