JavaScript的六种继承方式
2017-04-01 13:48
519 查看
我们知道JavaScript并不是传统的面向对象语言,而是面向原型对象的,在JavaScript中并不存在与传统面向对象语言中的传统类的概念。在JavaScript中,原型对象是其核心,如果在JavaScript中想要实现继承,那么,就不得不借助原型。今天,就来尝试的介绍JavaScript中的几种继承方式,以及他们的优缺点。
1.原型链继承
原理:创建每一个构造函数都有一个__proto__属性,是一个指针,会指向一个prototype属性,是一个对象类型 。当一个对象属性找不到的时候,会默认在原型链上向上查找,直到为null。我们可以通过将一个实例对象赋给原型对象,从而得到该对象的属性和方法,实现继承。
优点:1.简单,容易实现。
缺点: 1.来自原型的属性是共享的,当child往family添加了新的元素,child2的family也发生了改变。
2.创建子类实例时,不能往父类中传参数。
2.借用构造函数继承
原理:通过call方法借用父类的构造函数来实现子类。
function Father(name){//父类 基类
this.name = name;
this.family = ["Kingsley","Sally","Clara"];
this.say = function(){
return "I am Dad";
}
}
function Child(name){//子类
Father.call(this,name); //对象冒充继承 可以传参
}
var child = new Child("Clara");
var child2 = new Child("Kingsley");
child.family.push('Kim');
alert(child.name);//Clara
alert(child2.name);//Kingsley
alert(child.family);//Kingsley,Sally,Clara,Kim
alert(child2.family);//Kingsley,Sally,Clara
alert(child.say === child2.say);//false
优点:1.解决了子类实例共享父类属性引用的问题。
2.创建子类实例时,可以向父类传递参数。
缺点:1.无法实现函数的复用。我们发现每创建一个子类的实例,都会创建一个新的say方法。这样对于内存消耗非常大,影响性能。
3.组合继承(构造函数+原型链)最常用的一种
原理:把需要共享的方法放在prototype上,实现了继承,同时保留了借用构造函数的优势。该独立的独立,该共享的共享。
function Father(name){//父类 基类
this.name = name;
this.family = ["Kingsley","Sally","Clara"];
}
Father.prototype.say = function(){
return "I am Dad";
}
Child.prototype = new Father();//一次
function Child(name){//子类
Father.call(this,name); //对象冒充继承 可以传参
}
var child = new Child("Clara");//两次
var child2 = new Child("Kingsley");
child.family.push('Kim');
alert(child.name);//Clara
alert(child2.name);//Kingsley
alert(child.family);//Kingsley,Sally,Clara,Kim
alert(child2.family);//Kingsley,Sally,Clara
alert(child.say === child2.say);//true
优点:1.不存在属性引用上的问题
2.可以向父类传递参数
3.可以将方法复用,解决了重复创建影响性能的问题
缺点:每次创建子类,原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成了两份,而子类实例上的那一份屏蔽了子类原型上的,又是造成了内存浪费。
4.原型式继承
原理:利用一个中转函数,创建一个没有属性方法空的对象,然后传入父类实例,实现继承。
优点:1.现买现用。
缺点:1.用整个父类对象来充当了子类原型对象,原型引用属性会被所有实例共享。
2.新对象是现取的,属性是现添的,无法实现代码复用。
5.寄生式继承
原理:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。
缺点:1.无法复用,内存浪费。
6.寄生组合继承(最佳方式)
原理:通过借用函数来继承属性,通过原型链的混成形式来继承方法
优点:1.解决了上述继承遇到的所有问题。
缺点:2.麻烦。
到这里,就介绍完了所有的继承方式。
1.原型链继承
原理:创建每一个构造函数都有一个__proto__属性,是一个指针,会指向一个prototype属性,是一个对象类型 。当一个对象属性找不到的时候,会默认在原型链上向上查找,直到为null。我们可以通过将一个实例对象赋给原型对象,从而得到该对象的属性和方法,实现继承。
function Father(){//父类 基类 this.name = "Dad"; this.family = ["Kingsley","Sally","Clara"]; this.say = function(){ return "I am Dad"; } } function Child(){//子类 this.age = 24; } Child.prototype = new Father();//通过原型链继承 var child = new Child(); var child2 = new Child(); child.family.push("Kim"); alert(child.name);//Dad。得到父类的属性 alert(child.say());//I am Dad 得到父类的方法 alert(child.constructor);//指针已经指向了父类 alert(child.family);//Kingsley,Sally,Clara,Kim alert(child2.family);//Kingsley,Sally,Clara,Kim
优点:1.简单,容易实现。
缺点: 1.来自原型的属性是共享的,当child往family添加了新的元素,child2的family也发生了改变。
2.创建子类实例时,不能往父类中传参数。
2.借用构造函数继承
原理:通过call方法借用父类的构造函数来实现子类。
function Father(name){//父类 基类
this.name = name;
this.family = ["Kingsley","Sally","Clara"];
this.say = function(){
return "I am Dad";
}
}
function Child(name){//子类
Father.call(this,name); //对象冒充继承 可以传参
}
var child = new Child("Clara");
var child2 = new Child("Kingsley");
child.family.push('Kim');
alert(child.name);//Clara
alert(child2.name);//Kingsley
alert(child.family);//Kingsley,Sally,Clara,Kim
alert(child2.family);//Kingsley,Sally,Clara
alert(child.say === child2.say);//false
优点:1.解决了子类实例共享父类属性引用的问题。
2.创建子类实例时,可以向父类传递参数。
缺点:1.无法实现函数的复用。我们发现每创建一个子类的实例,都会创建一个新的say方法。这样对于内存消耗非常大,影响性能。
3.组合继承(构造函数+原型链)最常用的一种
原理:把需要共享的方法放在prototype上,实现了继承,同时保留了借用构造函数的优势。该独立的独立,该共享的共享。
function Father(name){//父类 基类
this.name = name;
this.family = ["Kingsley","Sally","Clara"];
}
Father.prototype.say = function(){
return "I am Dad";
}
Child.prototype = new Father();//一次
function Child(name){//子类
Father.call(this,name); //对象冒充继承 可以传参
}
var child = new Child("Clara");//两次
var child2 = new Child("Kingsley");
child.family.push('Kim');
alert(child.name);//Clara
alert(child2.name);//Kingsley
alert(child.family);//Kingsley,Sally,Clara,Kim
alert(child2.family);//Kingsley,Sally,Clara
alert(child.say === child2.say);//true
优点:1.不存在属性引用上的问题
2.可以向父类传递参数
3.可以将方法复用,解决了重复创建影响性能的问题
缺点:每次创建子类,原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成了两份,而子类实例上的那一份屏蔽了子类原型上的,又是造成了内存浪费。
4.原型式继承
原理:利用一个中转函数,创建一个没有属性方法空的对象,然后传入父类实例,实现继承。
function obj(o){//中转函数 function F(){} F.prototype = o; return new F(); } var Father = { name:"Dad", age:28, say:function(){ return "I am " + this.name; } } var child = obj(Father); alert(child.say());//I am Dad
优点:1.现买现用。
缺点:1.用整个父类对象来充当了子类原型对象,原型引用属性会被所有实例共享。
2.新对象是现取的,属性是现添的,无法实现代码复用。
5.寄生式继承
原理:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。
function obj(o){//中转函数 function F(){} F.prototype = o; return new F(); } function create(o){//寄生函数 var f = obj(o); f.run = function(){ return this.name + " " + "function"; } return f; } var Father = { name:"Dad", age:28 } var child = create(Father); alert(child.name);//Dad alert(child.run());//Dad function
缺点:1.无法复用,内存浪费。
6.寄生组合继承(最佳方式)
原理:通过借用函数来继承属性,通过原型链的混成形式来继承方法
function obj(o){ function F(){} F.prototype = o; return new F(); } function create(Father,Child){//寄生函数 var f = obj(Father.prototype); f.constructor = Child; Child.prototype = f; } function Father(name,age){ this.name = name; this.age = age; } Father.prototype.say = function(){ return this.name + " " + "say"; } function Child(name,age){ Father.call(this,name,age); } create(Father,Child); var child = new Child("Lee",100); alert(child.say());//Lee say alert(child.constructor);//function Child(name,age){Father.call(this,name,age);}
优点:1.解决了上述继承遇到的所有问题。
缺点:2.麻烦。
到这里,就介绍完了所有的继承方式。
相关文章推荐
- JavaScript继承(六种方式)(二)
- JavaScript 六种继承方式
- JavaScript继承的六种方式
- JavaScript是如何实现继承的(六种方式)
- javascript 中实现继承的六种方式
- JavaScript的六种继承方式(推荐)
- JavaScript 六种继承方式
- 重新理解JavaScript的六种继承方式
- JavaScript是如何实现继承的(六种方式)
- JavaScript六种继承方式
- javascript实现继承的六种方式
- JavaScript六种继承方式
- JavaScript的六种继承方式
- JavaScript的六种继承方式
- javascript 六种继承方式
- JavaScript是如何实现继承的(六种方式)
- JavaScript实现继承的六种方式
- JavaScript的六种继承方式
- JavaScript的六种继承方式(推荐)
- JavaScript实现继承(六种方式)