/**
* JavaScript继承:
* 首先JavaScript是一门基于对象的语言,在ES6之前,JavaScript没有类的概念
* 为什么说JavaScript是一门基于对象的语言?
* 很多人都知道OO(Object Oriented)语言都支持接口继承和实现继承,接口继承只继承方法签名,而实现继承则只继承实际的方法,
* 而JavaScript函数没有签名,也就是没有重载,这也决定了JavaScript在OOP程序设计中,无法实现多态这一特性
* 在EMCAscript中无法实现接口继承,ECMAScript只支持实现继承,而实现继承则是依靠原型链,其基本核心是利用了原型让一个引用类型
* 继承另一个引用类型的属性和方法
*
*/
// 原型继承
function Person (weight, height) {
this.weight = weight
this.height = height
}
Person.prototype = {
constructor: Person,
say: function () {
},
eat: function () {
}
}
function Student (school, address) {
this.school = school
this.address = address
}
// 实现继承
Student.prototype = new Person('60', '160')
/**
* 原型继承的优势:
* 代码少,可以使用之前对象的全部属性,可以使用它的原型方法
* 缺陷:
* 创建继承对象时,其原型对象属性是相同的,需要手动修改
* 注意问题:
* 通过原型链继,不能使用对象字面量创建原型方法,这样会重写原型链!
*
**/
var beautifulGirl = new Student('nanda', '江西')
console.log(beautifulGirl)
// 借用构造函数继承
function Animal (weight, height, type) {
this.type = type
this.weight = weight
this.height = height
}
Animal.prototype = {
constructor: Animal,
eat: function () {
}
}
function Dog (dogType, bg) {
this.dogType = dogType
this.bg = bg
Animal.call(this, '20', '15', '宠物') // Animal.apply(this, [ ])
}
Dog.prototype = {
constructor: Dog,
scratch: function () {
}
}
var myDOg = new Dog('哈士奇', 'black')
console.log(myDOg)
/**
* 总结:
* 借用构造函数的缺陷:
* 不能继承构造函数的原型,他的原型对象(没有进行 new运算),其原型对象依然是自己的原型对象
* 由于不能达到函数、共有数据复用,导致效率变低,这与构造函数模式类似
* 本质
* 其实就是用call和apply实现继承
**/
// 组合继承
function Tree (treeType) {
this.treeType = treeType
}
Tree.prototype = {
constructor: Tree,
gateway: function () {
console.log(this.treeType)
}
}
function Willow (height, year, size) {
this.height = height
this.year = year
this.size = size
Tree.call(this)
}
Willow.prototype = new Tree()
var willowObj = new Willow(170, 12, 15)
console.log(willowObj)
/**
* 优势:
* 即可以解属性问题,又可以解决方法问题;
* 缺陷:代码增加, 无论什么情况下都会调用两次超类型函数,一次是实现子类型原型继承的时候,一次实现
* 是子类型的构造函数内部,继承实例时,虽然子类型能够最终包含超类型的所有原型,但是,不得不
* 通过子类型中的实例属性属性的更新
*
**/
// 寄生继承
function object (original) {
function F () {
}
F.prototype = original // 构造函数 -> original的构造函数
// 实例化对象
return new F()
}
// 得到返回的实例
function createAnother (original) {
var clone = object(original)
// 增强对象时无法共享方法
clone.prototype.sayName = function () {
alert('android Stdudio')
}
return clone
}
/**
* 1、使用寄生式继承的思路和工程模式有类似,即创建一个仅仅用来封装的函数,该函数在内部以某种
* 方式去增强对象,最后返回一个实例,original是当前的原型对象
* 缺点:
* 使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率
**/
// 组合寄生继承
function object (original) {
function F (){}
F.prototype = original // F.prototype.constructor -> original.prototype
return new F()
}
function SuperType (age) {
this.age = age
}
function SubType () {
SuperType.call(this, 10)
}
// superType为父类,SubType为子类
function inheritPrototype (subType, superType) {
var prototype = object(superType.prototype)
prototype.constructor = subType // 此时, 弥补因为重写原型丢失构造属性
subType.prototype = prototype
}
var subObj = new SubType(20)
/**
* 无疑,组合继承时JavaScript常用的继承方式之一,但是之前说了他的缺点,需要调用两次函数和更新
* 属性,所以寄生组合寄生便完善了这点,使之成为目前最为标准和流行的继承方式
*
**/
// 继承的总结:
/**
* 1、在ES6之前,js没有类的概念,js实现继承依靠原型链,在OOP中,js只能实现继承和封装,不能实现多态,因为JavaScript没有函数签名
* 2、js的原型链
* 每个构造函数中都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例对象包含一个指向原型对象的
* 内部指针,JavaScript继承核心就是让原型对象等于一个类型的实例,那么此时的原型对象将包含着一个指向另一个原型
* 的指针,相应的,另一个原型对象也是另一个类型的实例,通过这样的层层递进,就构成了实例与原型的链条!
* 最终有构造函数的事情吗? 在原型链中并没有构造函数的参与!
* 3、默认的原型
* 记住!所有的原型对象都继承自Object,而这个继承也是通过原型链式实现的,这也是为什么所有自定义方法都具有toString、valueOf、
* 4、继承的优点:
* 节省内存,实现OOP的编程模式,共享数据
*/
// 运用继承进行的数据共享
function Animate (name, age, sex) {
this.r = name
this.a = age
this.c = sex
}
// 如果你的对象原型继承了其他原型,你最好不要这样做,这样你将重写原型链
Animate.prototype = {
constructor: Animal,
arr: []
}
var objOne = new Animal('dog', 6, 1)
var objTwo = new Animal('zu', 1, 0)
objOne.arr.push(this.name)
objTwo.arr.push(this.age.toString())