我们可以从最初的混合继承模式,慢慢说起
Object.create()
的前因后果。
1.混合模式实现原型式继承
一般来说,使用构造函数结合原型的混合模式,可以为特定的实例共享属性和方法。
比较常见的是下面的形式,也是最基本的使用:
function Person(name){
this.name = name;
};
Person.prototype.sayName = function(){
alert(this.name);
}
Person.prototype.XXX = XXXXX;
......
var p1 = new Person('mike');
var p2 = XXXXX;
......
如果只是想达到实例共享属性,不想噼里啪啦的创建构造函数,懒得定义一大堆原型属性,,完全可以用更简洁的方法去实现。
比如,这么做:
定义于一个
create
函数,来对传入的
obj
对象加工,使
obj
对象作为构造函数
Person
的原型,最后返回一个临时的新实例。
function create(obj){
function Person(){};
Person.prototype = obj;
return new Person();
}
var people = {
name:'mike'
}
var p1 = create(people);
console.log(p1.name); //mike
故事还在继续。。。
上面方法证明是可行的,不过有一个坑,那就是
原型的引用类型属性会共享相应的值
,举个栗子:
function create(obj){
function Person(){};
Person.prototype = obj;
return new Person();
}
var people = {
name:'mike',
arr:[,,,,]
}
var p1 = create(people);
var p2 = create(people);
p1.name = 'jake';
p1.arr.push('hahaha');
console.log(p1.name); //jake
console.log(p2.name); //mike
console.log(p1.arr); //[1, 2, 3, 4, 5, "hahaha"]
console.log(p2.arr); //[1, 2, 3, 4, 5, "hahaha"]
由于原型中的
arr
属性是引用类型,所以它是被实例所共享,上面可以看到原型中,基本类型属性和引用类型属性的差异。
2.Object.create()实现原型式继承
ES5新增了一个
Object.create()
方法,用于规范原型式继承。
Object.create(prototype, descriptors)
- prototype:必需。 要用作原型的对象。 可以为 null。
- descriptors:可选。 包含一个或多个属性描述符的 JavaScript 对象。 “数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。 如果未指定最后三个特性,则它们默认为 false。【这很重要,意味着如果不显式声明属性的
,它在某些方法下是不可枚举遍历的】enumerable=true
在只传入一个参数的情况下,
Object.create()
与上面的
create()
用法相同:
var person = {
name:'mike',
arr:[,,,,]
}
var p1 = Object.create(person);
var p2 = Object.create(person);
p1.name = 'jake';
p1.arr.push('hahaha');
console.log(p1.name) //jake
console.log(p2.name) //mike
console.log(p1.arr) //[1, 2, 3, 4, 5, "hahaha"]
console.log(p2.arr) //[1, 2, 3, 4, 5, "hahaha"]
注意了,还是那个坑,包含引用类型的属性始终会共享相应的值。
Object.create()
接收的第二个参数,是为新对象定义额外的属性,指定的任何属性都会覆盖原型上的同名属性。
var person = {
name:'mike',
arr:[,,,,]
}
var p1 = Object.create(person,{
name:{
value:'jake'
},
arr:{
value:[,,]
}
});
var p2 = Object.create(person);
p1.arr.push('hahaha');
console.log(p1.name) //jake
console.log(p2.name) //mike
console.log(p1.arr) //[7, 8, 9, "hahaha"]
console.log(p2.arr) //[1, 2, 3, 4, 5]
以下补充于2018-09-12。
Object.create()还可以用于完整克隆一个对象,包括它的原型属性。
Object.create(
Object.getPrototypeOf( obj ),
Object.getOwnPropertyDescriptors( obj )
)
3.proto
改变对象的原型链指针
__proto__
也可以实现继承另一个对象。
不推荐使用这个属性,
__proto__
属性只有浏览器必须部署,在非浏览器的环境不一定部署。
function Person(){
this.sex = 'man';
}
Person.prototype.name = 'hello';
var p = new Person();
var obj = {
addr:'china',
__proto__:new Person
}
console.log(obj.name) //hello
console.log(obj.sex) //man
4.Object.setPrototypeOf()
ES6新增API,Object.setPrototypeOf()
Object.setPrototypeOf 方法的作用与
__proto__
相同,用来设置一个对象的 prototype 对象,返回参数对象本身。
Object.setPrototypeOf(object, prototype)
function Person(){
this.sex = 'man';
}
Person.prototype.name = 'hello';
var p = new Person();
var obj = {
addr:'china'
}
Object.setPrototypeOf( obj, new Person )
console.log(obj.name) //hello
console.log(obj.sex) //man