前言
写本《JavaScript简餐》系列文章的目的是记录在阅读学习《JavaScript高级程序设计(第4版)》一书时出现的各个知识点。虽是对读书的笔记和总结,但是希望它轻量、简洁、犀利,不会引起阅读疲劳,可以在碎片化时间和闲暇之余轻巧地沐浴一下知识点。每篇文章只针对一个小部分进行讲解式的梳理,来达到个人复习总结和分享知识的目的。
一、什么是原型式继承?
2006年,Douglas Crockford写了一篇文章:《JavaScript中的原型式继承》。这篇文章介绍了一种不涉及严格意义上的构造函数的继承方法。他的出发点是即使不自定义类型也可以通过原型实现对象之间的信息共享。直接来看下面的例子:let person = {
name: 'Lucy',
friends: ['Bob', 'Jack', 'Tim']
};
let anotherPerson = Object(person);
anotherPerson.name = 'Leo';
anotherPerson.friends.push('Lisa');
let yetAnotherPerson = Object(person);
yetAnotherPerson.name = 'Micheal';
yetAnotherPerson.friends.push('Sue');
console.log(person.name); // Micheal
console.log(person.friends); // [ 'Bob', 'Jack', 'Tim', 'Lisa', 'Sue' ]
这个例子中定义了person对象,其中有原始值name和引用值friends,把它传给Object()之后会返回一个新的对象。这个新对象的原型是person,意味着它的原型上既有原始值属性又有引用值属性。从最后的打印结果也可以看到其原始值属性被改成了最后赋值的Micheal,引用值属性friends确实被后来定义的anotherPerson和yetAnotherPerson这两个对象push进了两个新的元素('Lisa'和'Sue')。所以原型式继承适用于这种情况:你有一个对象,想在它的基础上再创建一个新对象。你需要把这个对象先传给Object(),然后再对返回的对象进行适当修改。遵循上述模式的继承方式就是我们所说的原型式继承。
二、ECMAScript5中的原型式继承
ECMAScript5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:1.作为新对象原型的对象(例如上面的person对象)、2.给新对象定义额外属性的对象(例如上面的anotherPerson对象,第二个参数是可选的)。在只有一个参数的时候,Object.create()与上面的Objcet()方法效果相同。Object.create()的第二个参数与Object.defineProperties()的第二个参数一样:每个新增属性都通过各自的描述符来描述。以这种方式添加的属性会遮蔽原型对象上的同名属性。例如:let person = {
name: 'Lucy',
friends: ['Bob', 'Jack', 'Tim']
};
let anotherPerson = Object.create(person, {
name: {
value: 'Laura'
}
});
console.log(anotherPerson.name); //Laura
可见,anotherPerson 的name属性覆盖掉了person中的name属性,打印的是Laura而不是Lucy。