前言
.前面我们已经介绍了JavaScript的三种继承方式:原型链,借用构造函数已经二者的组合继承。其中第三种组合继承最为常用。因为我们知道它结融合了原型链和借用构造函数的有点,隐藏了自己各自的缺点,最终实现了相对比较完美的继承方式。接下来我们要介绍js中的第四中继承方式——原型式继承。
原型式继承
曾经有人提出了另一种实现继承的方法,这种方法并没有使用严格意义上的构造函数,而是借助原型可以基于已有的对象来创建一个新对象, 同时还不必因此创建自定义类型。下面我们来看一段代码
function object(o){
function F(){}
F.prototype = 0;
return new F();
}
以上代码在object函数内部,先创建了一个临时的构造函数,然后将传入的对象作为该构造函数的原型,最后返回了这个临时类型的新实例。从本质上讲,object() 对传入其中的对象执行了一次浅复制。来看下面的例子
var person = {
name: 'Alvin',
friends: ['Yannis','Ylu']
}
var p1 = object(person);
p1.name = 'Bob';
p1.friends.push('Lucy');
var p2 = object(person);
p2.name = 'Lilei';
p2.friends.push('Hanmeimei');
console.log(person.friends);//Yannis, Ylu, Lucy, Hanmeimei
这种原型式继承要求必须有一个对象可以作为另一个对象的基础。如果有这么一个对象的话, 可以把它传递给object函数,然后再根据具体需求对得到的对象加以修改。在这个例子中可以作为另一个对象基础的是person对象,于是我们把它传入到object函数中,然后该函数就会返回一个新对象,这个新对象将person作为原型,所以它的原型中就包含了一个基本类型属性name和一个引用类型属性friends。这就意味着person.friends不仅属于person所有,而且也会被p1和p2共享。实际上就相当于创建了person对象的两个副本。
在ECMAScript5中新增了Object.create()方法,该方法规范了原型式继承。这个方法接收两个参数:一个用作新对象原型的对象,另一个是可选的,用于新对象定义额外的属性的对象。在只传入一个参数的情况下,Object.create()与上面的object()方法行为相同。看下面示例:
var person = {
name: 'Alvin',
friends: ['Yannis','Ylu']
}
var p1 = Object.create(person);
p1.name = 'Bob';
p1.friends.push('Lucy');
var p2 = Object.create(person);
p2.name = 'Lilei';
p2.friends.push('Hanmeimei');
console.log(person.friends);//Yannis, Ylu, Lucy, Hanmeimei
Object.create()方法的第二个参数与Object.defineProperties()方法的第二个参数格式相同:每个属性都是通过自己的描述符定义。以 这种方式指定任何属性都会覆盖原型对象上的同名属性。如:
var person = {
name: 'Alvin',
friends: ['Yannis','Ylu']
}
var p1 = Object.create(person,{
name:{
value:'Lucy'
}
})
console.log(p1.name);//Lucy
使用场景
在没有必要兴师动众的创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式继承是完全可以考虑的。当然同样的问题就是:包含的所有引用类型的属性始终都会共享相应的值。