在JS中,我们常常会遇见new操作符以及Object.create()方法。在本文中,我们来理清用new及Object.create()在创建对象时原型链的状态。
原型链
当我们创建对象时,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)。
举个例子:
var obj = { // 创建一个对象
a: 1,
b: 2
};
// 看看obj的原型对象
// obj对象继承了Object.prototype的属性和方法
Object.getPrototypeOf(obj); // Object{}
// 再看看obj的原型对象的原型对象
Object.getPrototypeOf( Object.getPrototypeOf(obj) ); // null
// 综上,对象obj的原型链如下:
// obj ---> Object.prototype ---> null
new操作符
在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时,它就可以被称为构造方法(构造函数)。下面我们使用构造器来创建对象:
// 我们的构造函数Foo
function Foo() {
this.a = [];
this.b = [];
}
// 改变Foo的prototype对象
Foo.prototype = {
addNum: function(x) {
this.a.push(x);
}
};
// 一个新对象被创建,它继承自foo.prototype,即bar.[[Prototype]] = Foo.prototype
// 构造函数 Foo 被执行,上下文(this)被指定为新实例
// 对象bar具有两个属性a和b,均为空数组,继承了addNum方法
var bar = new Foo();
// 对象bar的原型链如下:
// bar ---> Foo.prototype ---> Object.prototype ---> null
总结如下:
// 当你执行:
var o = new Foo();
// JavaScript 实际上执行的是:
// var o = new Object();
// o.[[Prototype]] = Foo.prototype;
// Foo.call(o);
Object.create()
Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。
PS:IE9以下不兼容
语法:Object.create(proto, [ propertiesObject ])
其中参数proto为一个对象,作为新创建对象的原型。
同样地,举个例子:
var a = {a: 1};
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继承而来)
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 因为d没有继承Object.prototype
此时来看看用new和Object.create()的区别在哪:
function Constructor(){}
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);