主题
原型和继承
原型
js
function People(name) {
this.name = name;
}
People.prototype.say = function(){ console.log(this.name) }
const xiaoming = new People('xiaoming');
以上代码完成了这些事
- 创建一个构造函数(People),并同时创建一个原型对象(People.prototype)
- 构造函数的 _proto_ 指向原型对象,原型对象的 constructor 指向构造函数
- 创建一个实例(xiaoming),实例的 _proto_ 会指向原型对象
原型链继承
通过原型继承多个引用类型的属性和方法,构建原型链,搜索属性就可以通过原型链一直向上搜索
所有引用类型的继承都是 Object
js
function Super() {}
Super.prototype.getName = function() {
return 'Super'
}
function Sub() {}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
Sub.prototype.getName = function() {
return 'Sub'
}
const sub = new Sub()
sub.getName() // 'Sub'
以上代码构成下列原型链
默认原型链继承有两个问题
原型中包含的引用值会在所有实例上共享
jsfunction Super() { this.colors = ['red', 'blue'] } function Sub(){} Sub.prototype = new Super() const sub1 = new Sub() sub1.colors.push('yellow') console.log(sub1.colors) // ['red', 'blue', 'yellow'] const sub2 = new Sub() console.log(sub2.colors) // ['red', 'blue', 'yellow']
子类型在实例化时不能给父类型的构造函数传参
组合继承
- 解决原型链继承的两个问题
js
function Super(name) {
this.name = name
this.colors = ['red', 'blue']
}
Super.prototype.sayName = function() {
console.log(this.name)
}
function Sub(name, age){
Super.call(this, name) // 重点代码 !!!!!
this.age = age
}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
const sub = new Sub('kingmusi', 22)
sub.sayName() // 'kingmusi'
// 也解决了共享引用值的问题
sub.push('yellow')
console.log(sub.colors) // ['red', 'blue', 'yellow']
const otherSub = new Sub('kingmusi', 22)
console.log(otherSub.colors) // ['red', 'blue']
从以下两行代码可以看到,
Super()
执行了两次,有以下问题
- 产生了性能上的开销
- 在 Sub 上和 Sub.prototype 上产生了同样的变量,在实例上删除某个变量时,只会删除 Sub 层次上的,Sub.prototype 上的仍不能被删除
jsSuper.call(this, name) Sub.prototype = new Super()
寄生式组合继承(最佳模式)
- 基本模式
js
function inheritPrototype(sub, super) {
sub.prototype = Object.create(super.prototype)
sub.prototype.constructor = sub
}
- 使用
js
function Super(name) {
this.name = name
this.colors = ['red', 'blue']
}
Super.prototype.sayName = function() {
console.log(this.name)
}
function Sub(name, age){
Super.call(this, name) // 重点代码 !!!!!
this.age = age
}
inheritPrototype(Sub, Super)
判断原型和继承的关系
- instanceof:只要原型链中包含此原型,则返回 true
- isPrototypeOf():只要原型链中包含此原型,则返回 true
js
function Super() {}
function Sub() {}
Sub.prototype = new Super()
Sub.prototype.constructor = Sub
const sub = new Sub()
console.log(sub instanceof Sub) // true
console.log(sub instanceof Super) // true
console.log(sub instanceof Object) // true
console.log(Sub.prototype.isPrototypeOf(sub)) // true
console.log(Super.prototype.isPrototypeOf(sub)) // true
console.log(Object.prototype.isPrototypeOf(sub)) // true
constructor 是不可靠的
jsfunction Super() {} function Sub() {} Sub.prototype = new Super() const sub = new Sub() console.log(sub.constructor === Sub) // false console.log(sub.constructor === Super) // true console.log(sub instanceof Sub) // true