一、Object.create()方法
Object.cerate()
方法用于从原型对象生成新的实例对象,可以替代new
命令。它接受一个对象作为参数,返回一个新对象,返回对象完全继承参数对象的属性,即作为参数的对象成为返回的新对象的原型。
var A = {
print: function () {console.log('hello');}
};
var B = Object.create(A);
B.print() // hello
B.print === A.print // true
//等同于以下代码
var A = function () {};
A.prototype = {
print: function () {console.log('hello');}
};
var B = new A();
B.print === A.prototype.print // true
上面的代码中,Object.create
方法在A
的基础上生成了B
。此时,A
就成了B
的原型,B
就继承了A
的所有属性和方法。
除了对象的原型,Object.create
方法还可以接受第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到新对象。
var o = Object.create({}, {
p1: { value: 123, enumerable: true },
p2: { value: 'abc', enumerable: true }
});
// 等同于
var o = Object.create({});
o.p1 = 123;
o.p2 = 'abc';
此外,Object.create
方法生成的对象,继承了它的原型对象的构造函数。
function A() {}
var a = new A();
var b = Object.create(a);
b.constructor === A // true
b instanceof A // true
实际上,如果老浏览器不支持Object.create
方法,可以用以下代码自己部署:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
上述代码表示,Object.create
方法实质是新建一个构造函数F
,然后让F
的prototype
属性指向作为原型的对象o
(这个o
是带输入的参数),最后返回一个F
的实例。整体来看,这就实现了Object.create
的功能:接收一个对象作为参数(原型对象),同时返回一个新对象(实例对象)`
以下三种方式生成新的对象时等价的:
var o3 = new Object();
var o1 = Object.create({});
var o2 = Object.create(Object.prototype);
Object.create
方法生成的新对象,动态继承了原型。在原型上添加或者修改任何方法,会立刻反应在子对象之上。
var o1 = { p: 1 };
var o2 = Object.create(o1);
var o3 = Object.create(o1);
console.log(o3.p);//1
console.log(o2.p);//1
o1.p = 2;
console.log(o1.p);//2
console.log(o2.p);//2
console.log(o3.p);//2
二、Object.prototype.isPrototypeOf()方法
Object.prototype.isPrototypeOf()
方法,用来判断一个对象是否是另一个对象的原型。
var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
o2.isPrototypeOf(o3) // true
o1.isPrototypeOf(o3) // true
上面代码表明,只要某个对象处在原型链上,isPrototypeOf
都返回true。
Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
上面代码中,由于Object.prototype
处于原型链的最顶端,所以对各种实例都返回true
,只有继承null
的对象除外。
三、Object.prototype.__proto__
__proto__
属性(前后各两个下划线)可以改写某个对象的原型对象。
var obj = {};
var p = {};
obj.__proto__ = p;
Object.getPrototypeOf(obj) === p // true
上面代码通过__proto__
属性,将p对象设为obj对象的原型。
根据语言标准,__proto__
属性只有浏览器才需要部署,其他环境可以没有这个属性,而且前后的两根下划线,表示它本质是一个内部属性,不应该对使用者暴露。因此,应该尽量少用这个属性,而是用Object.getPrototypeof()
(读取)和Object.setPrototypeOf()
(设置),进行原型对象的读写操作。此外,还可以使用Object.getPrototypeOf
方法,检查浏览器是否支持__proto__
属性,老式浏览器不支持这个属性。
Object.getPrototypeOf({ __proto__: null }) === null
上面代码将一个对象的__proto__
属性设为null
,然后使用Object.getPrototypeOf
方法获取这个对象的原型,判断是否等于null
。如果当前环境支持__proto__
属性,两者的比较结果应该是true。
Object.getPrototypeOf()方法
Object.getPrototypeOf()方法返回一个对象的原型。这是获取原型对象的标准方法。
Object.getPrototypeOf(Object.prototype)// null
通过这个例子,我们可以看出来,最顶层的原型对象——Object.prototype
对象,其原型是null
,由于null
没有任何属性,所以原型链到此为止。如果想要生成一个不继承任何属性(比如没有toString
和valueOf
方法)的对象,可以将Object.create
的参数设置为null
。
var o = Object.create(null);
o.valueOf()
// TypeError: Object [object Object] has no method 'valueOf'
上面代码表示,如果对象o的原型是null,它就不具备一些定义在Object.prototype
对象上面的属性,比如valueOf
方法。
下面代码展示了空对象、函数对象以及以F
为构造函数的实例对象f,它们的原型对象
// 空对象的原型是Object.prototype
Object.getPrototypeOf({}) === Object.prototype// true
// 函数的原型是Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype// true
// f 为 F 的实例对象,则 f 的原型是 F.prototype
var f = new F();
Object.getPrototypeOf(f) === F.prototype// true
四、Object.setPrototypeOf()方法
Object.setPrototypeOf()
方法可以为现有对象设置原型,返回一个新对象。
Object.setPrototypeOf()
方法接收两个参数,第一个是现有对象,第二个是新设置的原型对象。
var a = {x: 1};
var b = Object.setPrototypeOf({}, a);
// 等同于
// var b = {__proto__: a};
b.x // 1
上面代码中,b对象是Object.setPrototypeOf
方法返回的一个新对象。该对象本身为空、原型为a
对象,所以b
对象可以拿到a
对象的所有属性和方法。b
对象本身并没有x
属性,但是JavaScript
引擎找到它的原型对象a
,然后读取a
的x
属性。
new
命令通过构造函数新建实例对象,实质就是将实例对象的原型,指向构造函数的prototype
属性,然后在实例对象上执行构造函数。
var F = function () {
this.foo = 'bar';
};
var f = new F();
// 等同于
var f = Object.setPrototypeOf({}, F.prototype);
F.call(f);