初始化
function Person(name) {
this.name = name
this.type = ["css", "js", "html"]
this.sum = function () {
alert(this.name)
}
}
Person.prototype.age = 10
一 原型链继承(ES5)
function Per() {
this.name = 'ker'
}
Per.prototype = new Person()
var Per1 = new Per()
var Per2 = new Per()
Per1.type.push("vue")
Per1.sum() // ker
console.log(Per1.age) //10
console.log(Per2.type) //"css","js","html","vue"
//instanceof 判断元素是否是另一个元素原型链上
//Per1继承了Person的属性,返回为true
console.log(Per1 instanceof Person) //true
优点:简单明了
缺点:
1、新实例无法向父类构造函数传参
2、继承单一
3、 所有新实例都会共享父类实例属性(一个实例修改了原型属性,另一的原型属性也会随之更改)
二 借用构造函数继承(ES5)
function Con() {
Person.call(this, 'nima')
}
var Con1 = new Con()
var Con2 = new Con()
Con1.type.push("haha")
console.log(Con1.age) // underfined 没有继承父类原型的属性,只继承父类构造函数的属性
console.log(Con1.name) //nima
console.log(Con1.type) // 'css', 'js', 'html', 'haha'
console.log(Con2.type) // 'css', 'js', 'html'
优点:
1、解决了子类实例共享父类引用属性的问题
2、创建子类实例时,可以向父类构造函数传参
缺点:
1、没有继承父类原型的属性,只继承父类构造函数的属性
2、无法实现构造函数的复用
3、每个新实例都有父类构造函数的副本(臃肿)
三 组合继承(ES5)
function SubType(name) {
Person.call(this, name) //构造函数继承
}
SubType.prototype = new Person() //原型链继承
var Sub = new SubType('铃铛')
console.log(Sub.name) //铃铛
console.log(Sub.age) // 10
优点:
1、可以继承父类原型上的属性,可以传参可以复用
2、 每一个构造函数属性都是私有的
缺点:
用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数
四 原型式继承(ES5)
//先封装一个函数容器,用于输出对象和承载继承的原型
function Conent(obj) {
var f = function () { }
f.prototype = obj //继承了传入的参数
return new f() //返回函数对象
}
var sup = new Person('naonao') // 拿到父类的实例
var sup1 = Conent(sup)
console.log(sup1.name) //naonao 继承父类函数的属性
重点: 用一个函数包装一个对象然后返回这个函数的调用,这个函数就变成了可是随意增添属性的实例或对象。object.create()就是这个原理
缺点:
1、所有的实例都会继承原型的属性
2、无法实现复用(新实例属性都是后面添加的)
五 寄生式继承(ES5)
function Conent(obj) {
var f = function () { }
f.prototype = obj //继承了传入的参数
return new f() //返回函数对象
}
var sup = new Person() // 拿到父类的实例
//以上是原型式继承,给原型式继承再套一个壳子传递参数
function subObject(obj) {
var sub = Conent(obj)
sub.name = 'yvan'
return sub
}
var sup2 = subObject(sup) //这个函数声明之后就成了可增添属性的对象
console.log(sup2.age) //10
console.log(typeof subObject) //function
console.log(typeof sup2) //Object
重点 :就是给原型式继承再套一个壳子
优点:
没有创建自定义类型,只是套了一个壳子返回对象。所以就顺理成章就创建了新对象
缺点:
没有用到原型无法复用
六:寄生组合式继承(ES5)
function Conent(obj) { //寄生
function F() { }
F.prototype = obj
return new F()
}
var con = Conent(Person.prototype)
//con实例(F实例)继承了父类函数的原型
//更像原型链继承只不过继承了原型属性
function SUb() {
Person.call(this) //这个继承了父类构造函数的属性
} //解决了组合式两次调用构造函数属性的缺点
//重点
SUb.prototype = con //继承了con实例
con.constructor = SUb // 修改实例
var sub1 = new SUb()
console.log(sub1.age) // 10
特点 :修复了组合继承的问题
ES5继承总结:
继承这些知识点与其说是对象的继承,更像是函数的功能用法,如何用函数做到复用,组合,这些和使用继承的思考是一样的。上述几个继承的方法都可以手动修复他们的缺点,但就是多了这个手动修复就变成了另一种继承模式。
ES6的继承
class Parent {
constructor (name,age){
this.name = name
this.age = age
};
tack(){
console.log( '姓名:' + this.name)
console.log( '年龄:' + this.age)
}
}
class Son extends Parent{
constructor (name , age ,sex){
super(name,age); //super必须在子类的this之前调用
this.sex = sex;
}
disp(){
console.log('性别:' + this.sex)
}
zonghe(){
console.log( this.name + '年龄:' + this.age +'性别:' + this.sex)
}
}
var c1 = new Son('闹闹',1,'男')
c1.tack() // 姓名:闹闹 年龄:1
c1.disp() // 性别:男
c1.zonghe() // 闹闹年龄:1性别:男
重点:父类不能调用子类的方法和属性,也就是说子类的变化不会影响到父类
es6继承与与es5继承的区别:
1、es5的构造函数是普通函数,可以使用关键词new也可以直接用。es6的class不能当做浦东函数用必须要用new关键词。
2、es5的原型方法和静态方法可以枚举,class默认不可枚举,要想获取不可枚举属性可以使用Object.getOwnPropertyNames方法。
3、es5的继承,实质是先创造子类的实例对象this,再执行父类的构造函数向其添加实例方法和属性(也可不执行),而es6的继承机制是先创造父类的实例对象this,再用子类的构造函数修改this。