您的位置:首页 > Web前端 > JavaScript

javascript 六种继承方式

2018-02-27 17:47 465 查看
1原型链
2 借用构造函数
3组合继承
4原型式继承
5寄生式继承
6寄生组合式继承
 
注:
prototype
1 每个函数都有一个prototype的对象属性,对象内有一个constructor属性,默认指向函数本身
2每个对象都有一个__proto__的属性,属相指向其父类型的prototype
 
1原型链
 
使用原型是让一个引用类型继承另一个引用类型的属性和方法
构造函数,原型,实例之间的关系:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内容指针
 例function SuperType() {
    this.property=true
    this.name='Eden'
}
SuperType.prototype.getSuperVal=function () {
    return this.property
}
SuperType.prototype.getSuperName=function () {
    return this.name
}
function SubType() {
    this.property=500
}
//继存
SubType.prototype=new SuperType()
SubType.prototype.getSuperVal=function () {
    return this.property
}
var instance=new SubType()
console.log(instance.getSuperVal())//500
console.log(instance.getSuperName())//eden  例2function Super(){
    this.val = 1;
    this.arr = [1];
}
function Sub(){
    // ...
}
Sub.prototype = new Super();    // 核心

var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val);    // 2
alert(sub2.val);    // 1

alert(sub1.arr);    // 1, 2
alert(sub2.arr);    // 1, 2
 
原型方法查找方式:如果当前new对象中方法不存在则向上一级查找直到查找到object=null为止
 
重点:拿父类实例来充当子类原型对象
 
优点:
简单,易于实现
缺点:
1修改sub1.arr 后sub2.arr也变了。因为来自原型对象的引用属笥是所有实例共享的
执行sub.arra.push(2);先对sub1进行属性查找,找遍了实例属性,没有找到,就开始顺着原型链向上找,拿到sub1的原型对象,有arr属性,于是给arr push了2 所以sub2.arr也变了
2创建子类实例时,无法向父类构造函数传参
 
1修改
2借用构造函数
 
在子类型构造函数的内部调用超类构造函数,通过使用call()和apply()方法可以在新创建的对象上执行构造函数
 function SuperType() {
    this.colors=['red','blue','yellow']
}
function SubType() {
    SuperType.call(this)//
}
var instance=new SubType()
instance.colors.push('black')
console.log(instance.colors)
var instanceOne=new SubType()
console.log(instanceOne.colors)
 
核心:
借父类的构造函数来增强子类实例,等于把父类的实例属性复制了一份给子类实例装上了(完全没有用到原型)
 
优点
1解决了子类实例共享父类引用属性的问题
2 创建子类实例时,可以向父类构造函数传参
缺点:
1无法实现函数复用,每个子类实例都持有一个新的fun函数,太多了就会影响性能
 
 
3组合继承(最常用)
将原型和借用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式
 

 function SuperType(name) {
    this.name=name
    this.colors=['red','black']
}
SuperType.prototype.sayName=function () {
    console.log(this.name)
}
function SubType(name,age) {
    //借用构造函数
    SuperType.call(this,name)
    this.age=age
}
//继承方法
SubType.prototype=new SuperType()
SubType.prototype.sayAge=function () {
    console.log(this.age)
}
var instance1=new SubType('Eden',20)
instance1.colors.push('yellow')
console.log(instance1.colors)
instance1.sayName()//eden
instance1.sayAge()//20
 
核心
把实例函数都放在原型对象上,以实现函数复用,同时还要保留借用构造涵数方式的优点,通过SuperType.call(this);继顾父类的基本属性和引用属性并保留能传参的优点,通过SubType.prototype=new SuperType() 继承父类函数,实现函数复用
 
优点:
1 不存在用引属性共享问题
2可传参
3函数可复用
缺点
1子类原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成两份,而子类实例上的那份屏蔽了子类原型上的,内存浪费。
 
 
4 原型式继承
 借助原型可以基于已有的对象创建新的对象,同时还不必须因些创建自定义的类型var person={
    name:'Eden zhang',
    friends:['lee','squall','nina']
}
var anotherPerson=Object.create(person)
anotherPerson.name='Lukiya';
anotherPerson.friends.push('Rob')
var newPerson=Object.create(person)
newPerson.name='Linda';
newPerson.friends.push('lane')
console.log(person.friends)
 
6寄生组合式继承(最佳方案)
创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增编辑器对象,最后再像真正是它做了所有工作一样返回对象例function Car(color) {
    //构造函数 constructor
    this.color = color
}
Car.prototype.go = function () {
    console.log(this.color)
}Car.prototype.start=function(){  this.go()}
function BMW(color) {
    Car.call(this,color)
}
//BMW.prototype=Car.prototype//prototype按引用传递父类将会被破坏
//BMW.prototype=new Car();//整个car构造函数执行二次 call一次 new一次
var _proto=Object.create(Car.prototype)
_proto.constructor=BMW;
BMW.prototype=_proto
var cars=new BMW('red')
console.log(cars)
cars.go()
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: