Created
November 2, 2017 06:24
JavaScript继承方式总结
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//javascript的继承方式 | |
/** | |
简单原型链: | |
拿父类的实例对象充当子类的原型对象 | |
优点:简单易实现 | |
缺点:1.来自原型对象的引用属性在实例中是共享的 | |
2.无法向父类构造函数传参 | |
*/ | |
function Person() { | |
this.name = 'parent'; | |
this.arr = [1]; | |
} | |
Person.prototype.say =function(){ | |
console.log(this.name); | |
} | |
function Student(){ | |
} | |
Student.prototype = new Person(); | |
var s1 = new Student(); | |
var s2 = new Student(); | |
s1.name = 's1'; | |
s1.arr.push(234); | |
console.log(s1.name);// s1 | |
console.log(s2.name);// parent | |
console.log(s1.arr);// [1,234] | |
console.log(s2.arr);// [1,234] | |
/** | |
借用构造函数:借父类的构造函数来增强子类实例,等于是把父类的实例属性复制了一份给子类实例装上了 | |
优点:1.解决了子类实例共享父类引用属性的问题; | |
2.可以向父类传参 | |
缺点:无法实现函数复用,每一个实例都含有一份父类的方法 | |
*/ | |
function Parent(name){ | |
this.name = name || 'parant'; | |
this.arr = [1]; | |
this.say = function () { | |
console.log(this.name) | |
} | |
} | |
function Child(name){ | |
//核心 | |
Parent.call(this,name); | |
//... | |
} | |
var c1 = new Child('c1'); | |
var c2 = new Child('c2'); | |
c1.name = 'new c1'; | |
c1.arr.push(234); | |
console.log(c1.name);//"new c1" | |
console.log(c2.name);//"c2" | |
console.log(c1.arr);//[1,234] | |
console.log(c2.arr);//[1] | |
/** | |
组合继承:把实例函数都放在原型对象上,以实现函数复用。同时还要保留借用构造函数方式的优点, | |
通过Super.call(this);继承父类的基本属性和引用属性并保留能传参的优点; | |
通过Sub.prototype = new Super();继承父类函数,实现函数复用 | |
优点:1.不存在引用属性共享问题 | |
2.可传参 | |
3.方法可复用 | |
缺点:子类原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次, | |
生成了两份,而子类实例上的那一份屏蔽了子类原型上的。。。内存浪费 | |
*/ | |
function NewParent(name){ | |
//只声明基本属性和引用属性 | |
this.name = name||'parent'; | |
this.arr = [1]; | |
} | |
//方法都放在原型对象上 | |
NewParent.prototype.say = function(){ | |
console.log(this.name) | |
} | |
//NewParent.prototype.... | |
function NewChild(name){ | |
//核心:继承父类的基本属性和引用属性 | |
NewParent.call(this,name); | |
//... | |
} | |
//继承父类函数,实现函数复用 | |
NewChild.prototype = new NewParent(); | |
var nc1 = new NewChild('nc1'); | |
var nc2 = new NewChild('nc2'); | |
nc1.arr.push(234); | |
console.log(nc1.name);//"nc1" | |
console.log(nc2.name);//"nc2" | |
console.log(nc1.arr);//[1,234] | |
console.log(nc2.arr);//[1] | |
/** | |
寄生组合式继承:切掉了原型对象上多余的那份父类实例属性 | |
*/ | |
//借用空对象作为中间媒介:空对象几乎不占内存 | |
function extend(Child,Parent){ | |
var F = function(){}; | |
//改变F的原型对象的指向 | |
F.prototype = Parent.prototype; | |
//子类的原型对象指向F的实例 | |
Child.prototype = new F(); | |
//重新指定Child的constructor指向自身 | |
Child.prototype.constructor = Child; | |
//为子对象设一个uber属性,这个属性直接指向父对象的prototype属性,备用属性 | |
Child.uber = Parent.prototype; | |
} | |
function Super(name){ | |
//只声明基础属性和引用属性 | |
this.name = name||'super'; | |
this.arr = [1]; | |
} | |
//声明方法 | |
Super.prototype.say = function(){ | |
console.log(this.name); | |
} | |
//Super.prototype.... | |
function Sub(name){ | |
//核心:继承父类基础属性和引用属性 | |
Super.call(this,name); | |
} | |
extend(Sub, Super); | |
var sb1 = new Sub('sb1'); | |
var sb2 = new Sub('sb2'); | |
sb1.name = 'new sb1'; | |
sb1.arr.push(234); | |
console.log(sb1.name);//"new sub1" | |
console.log(sb2.name);//"sub2" | |
console.log(sb1.arr);//[1,234] | |
console.log(sb2.arr);//[1] | |
/** | |
拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象, | |
**/ | |
function extend2(Child,Parent){ | |
var p = Parent.prototype; | |
var c = Child.prototype; | |
for(var k in p){ | |
c[k] = p[k] | |
} | |
c.uber = p; | |
} | |
function Animal(name){ | |
this.name = name || 'animal'; | |
} | |
Animal.prototype.say = function(){ | |
return this.name; | |
} | |
function Cat(name,color){ | |
Animal.call(this,name); | |
this.color = color; | |
} | |
extend2(Cat,Animal); | |
var cat = new Cat('猫','黄色'); | |
console.log(cat.say());//"猫" | |
console.log(cat.name);//"猫" | |
console.log(cat.color);//"黄色" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment