原形链继承
function Person(name, age) {
this.name = name;
this.age = age;
this.sleeping = function() {
console.log(`${this.name} is sleeping.`)
}
}
function Student(name, age) {
Person.call(this, name, age);
this.studying = function() {
// ...
}
}
Student.prototype = new Person();
这种继承方法的主要缺点有:
- Person 构造函数被调用多次
- 无法打印原形上的属性
寄生式继承
对象的寄生式继承
先来看直接赋值 prototype
的情况:
Student.prototype = Person.prototype;
Student.prototype.running = function() {
// ...
}
这会导致添加在 Student
原型上的属性被添加到其父类 Person
上,且后面所有 Person
的子类都会有添加在 Student
原形上的属性,显然这种做法是错误的。
既然直接指向 prototype
不可取,那么我们可以添加一个中间对象,这个对象的 prototype
指向我们要继承的父类,然后父类的子类的 prototype
指向我们创建出来的中间对象。这样当我们给子类的 prototype
添加属性时,实际上上是添加到我们创建出来的中间对象上了,不会影响父类的 prototype
,这种方法被称为寄生式继承。
先来看对象的寄生式继承:
const person = {
name: 'xxx',
age: 18
}
function createObject(o) {
const newObj = {};
// 获取 o 的原形对象
const pt = Object.getPrototypeOf(o);
// 设置创建出来的空对象的原形为 o 的原形
Object.setPrototypeOf(newObj, pt);
return newObj;
}
const stu = createObject(person);
stu.name = '1111';
console.log(stu.name, stu.age) // 1111 18
console.log(person.name, person.age) // xxx 18
值得一提的是,现在 JS 已经提供一个 Object.create
方法实现上面代码中 createObject
方法的功能。
构造函数的寄生组合式继承
Student.prototype = Object.create(Person.prototype)
// 不会影响到 Person 的 prototype
Student.prototype.name = 'xxxx'