首先什么是继承
简单来说就是 儿子可以拥有爸爸的属性和方法
有哪些常见继承
原型链继承 构造函数实现继承 组合继承 寄生式组合继承 class继承
原型链继承
代码
function farther() {
this.wealth = ['汤臣一品','拉法','股票']
}
farther.prototype.getWealth = function () {
return this.wealth
}
function son() {}
son.prototype = new farther()
var son1 = new son()
son1.wealth.push('汤臣一栋')
var son2 = new son()
console.log(son2.wealth) // ['汤臣一品', '拉法', '股票', '汤臣一栋']
问题
- 1:原型中的引用类型属性会被所有实例共享
- 2:子类在实例化的时候不能给父类构造函数传参
构造函数继承
代码
function farther(wealth) {
this.wealth = wealth
this.getWealth = function() {
return this.wealth
}
}
function son(wealth) {
farther.call(this, wealth)
}
son.prototype = new farther()
var son1 = new son(['汤臣一品','拉法','股票'])
son1.wealth.push('汤臣一栋')
console.log(son1.wealth,'son1.wealth')
var son2 = new son(['小房子'])
console.log(son2.wealth,'son2.wealth')
问题
- 1:子类无法对父类的方法和属性进行扩展
组合继承
使用原型链继承原型上的属性和方法,将原型上的构造函数指向自身。
就可以实现子类对属性和方法扩展的功能。
代码
function father(wealth) {
this.wealth = wealth
}
father.prototype.getWealth = function() {
return this.wealth
}
function son(wealth, name) {
father.call(this, wealth)
this.name = name
}
son.prototype = new father()
son.prototype.constructor = son
let son1 = new son(['天空'],'张三')
son1.wealth.push('大地')
console.log(son1)
let son2 = new son(['悬空城'],'李四')
console.log(son2)
问题
- 1:调用了 2 次父类构造函数,第一次是在 new father(),第二次是在 father.call() 这里。会有一定的性能消耗。
寄生式组合继承
不直接调用父类构造函数给子类原型赋值,而是通过创建空函数fn获取父类原型的副本
两种写法
第一种写法
function father(wealth) {
this.wealth = wealth
}
father.prototype.getWealth = function() {
return this.wealth
}
function son(wealth, name) {
father.call(this, wealth)
this.name = name
}
function createObj(obj) {
function fn() {}
fn.prototype = obj
return new fn()
}
function extend(child, parent) {
let prototype = createObj(parent.prototype)
prototype.constructor = child
child.prototype = prototype
}
extend(son, father)
第二种写法
function farther(wealth) {
this.wealth = wealth
}
farther.prototype.getWealth = function() {
return this.wealth
}
function son(wealth, name) {
farther.call(this, wealth)
this.name = name
}
son.prototype = Object.create(farther.prototype)
son.prototype.constructor = son
class继承
代码
class farther {
constructor(wealth) {
this.wealth = wealth
}
getWealth() {
return this.wealth
}
}
class son extends farther {
constructor(wealth, name) {
super(wealth)
this.name = name
}
}
实战面试题
代码
function fn() {
fn.a = function() {console.log(1)}
this.a = function() {console.log(2)}
}
fn.prototype.a = function() {console.log(3)}
fn.a = function() {console.log(4)}
fn.a()
var obj = new fn()
obj.a()
fn.a()
执行结果
分析
为什么是4-2-1
首先我们看代码执行顺序
fn.a()
显然执行 fn.a = function() {console.log(4)} 打印4
var obj = new fn() 实例化的时候执行
fn.a = function() {console.log(1)}
this.a = function() {console.log(2)}
obj.a()
this.a = function() {console.log(2)} 这个this就是obj
显然执行 2
fn.a()
在之前 var obj = new fn() 实例化的时候执行
外部fn.a {console.log(1)}
先找自身上面的属性方法才会去找原型链上面的属性方法
所以执行结果 4
如果没有 fn.a = function() {console.log(1)}
那执行结果就是 fn.prototype.a = function() {console.log(3)}