“继承”是JavaScript面向对象设计的重要一环,愿你认真读完本文,吃透继承的概念。app
在js中,继承主要是依靠原型链实现的,原型链是通往继承的必经之路。你能够参考《一张图完全KO原型链(prototype,__proto__)》这篇博文,相信它必定能很好地帮助你原型链。函数
原型链是实现继承最原始的模式,即经过prototype属性实现继承。post
//父级-构造函数
function Father() {
this.fatherProp = true
}
//父级-原型属性
Father.prototype.getFatherValue = function() {
return this.fatherProp
}
//子级-构造函数
function Son() {
this.sonProp = false
}
//子级-原型属性:继承父级
//即__proto__指向父级的prototype
//若不理解请阅读《一张图完全KO原型链(prototype,__proto__》
Son.prototype = new Father()
//子级-添加原型方法
Son.prototype.getSonValue = function() {
return this.sonProp
}
//建立子级的实例对象
var son = new Son()
console.log(son.getFatherValue()) //true
复制代码
若是到最后都没找到,会发生什么呢?学习
//一个不存在的方法
console.log(son.getValue()) //ERROE:not a function
复制代码
重写父级原型链的方法或者添加父级原型链不存在的方法,必须在父级原型链代码以后。(这个很好理解,不放代码演示了)ui
经过原型链实现继承后,不能再使用字面量的方式建立原型对象,由于会覆盖原型链。this
//子级-原型属性:继承父级
Son.prototype = new Father()
//不能像下面这样,这样会使得上面的代码无效
//由于这至关于从新建立了一个原型对象
Son.prototype = {
getSonValue: function() {
return this.sonProp
}
}
复制代码
世间万事万物都不可能十全而十美,原型链虽然强大,但也存在缺陷。spa
function Father() {
this.arr = [1,2,3]
}
function Son() {
}
Son.prototype = new Father()
var son1 = new Son()
console.log(son1.arr) //1,2,3
var son2 = new Son()
son2.arr.push(4)
console.log(son2.arr) //1,2,3,4
console.log(son1.arr) //1,2,3,4
复制代码
方式一中引用类型带来的问题可借用构造函数的方式解决。其核心思想是:在子级构造函数中调用父级构造函数。prototype
如何实如今一个构造函数中调用另外一个函数?——call()和apply()设计
function Father() {
this.arr = [1,2,3]
}
function Son() {
//call的第一个函数是this指向的对象,即构造函数的实例对象
Father.call(this)
/*上面代码等同于下面这段代码: (function() { this.arr = [1,2,3] }).call(this) */
}
var son1 = new Son()
console.log(son1.arr) //1,2,3
var son2 = new Son()
son2.arr.push(4)
console.log(son2.arr) //1,2,3,4
console.log(son1.arr) //1,2,3
复制代码
//解决传参问题:
function Father(name) {
this.name = name
}
function Son(name) {
Father.call(this, name)
}
var son1 = new Son("小名")
console.log(son1.name) //小名
var son2 = new Son("一灯")
console.log(son2.name) //一灯
复制代码
这种方式是经过构造函数实现的,固然也把构造函数自身的问题带过来了——破坏了复用性。由于每一个实例都建立了一份副本。code
组合继承 = 原型链 + 借用构造函数。取其长避其短:共享的用原型链,各自的借用构造函数
function Father(name) {
this.name = name
this.arr = [1,2,3]
}
Father.prototype.getName = function() {
console.log(this.name)
}
function Son(name, age) {
Father.call(this, name)
this.age = age
}
Son.prototype = new Father()
Son.prototype.constructor = Son
Son.prototype.getAge = function() {
console.log(this.age)
}
var son1 = new Son("小名", 23)
son1.arr.push(4)
console.log(son1.arr) //1,2,3,4
son1.getName() //小名
son1.getAge() //23
var son2 = new Son("一灯", 24)
console.log(son2.arr) //1,2,3
son1.getName() //一灯
son1.getAge() //24
复制代码
Father.call(this, name)——name来自Father
this.age = age; Son.prototype.constructor = Son——age来自Son
Father.prototype.getName——getName方法来自Father.prototype
Son.prototype.getAge——getAge来自Son.prototype
继续学习继承的后三种方式