基于javascript的对象继承

谈到继承,javascript在ES6出现之前,是不提供原生的继承机制的,这里我们将通过几种方法,来实现功能上的继承。

1.基于原型链的继承

function SuperType(){
    this.colors=["red", "blue", "green"]
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}
function SubType(){
}
SubType.prototype = new SuperType();
SubType.prototype.getSuperValue = function(){
    return this.subproperty;
}
SubType.prototype.getSuperValue = function(){
    return false;
}
var instance1 = new SubType();
instance1.colors.push("black");
var instance2 = new SubType();
console.info(instance2.colors)

result:  [ 'red', 'blue', 'green', 'black' ]
console.info(instance1.hasOwnProperty("colors"), "colors" in instance1)
result: false true           //说明colors这个属性不是子类的实例属性,而是原型属性

着重看第9行,子类的原型指向父类的实例,同样也就继承了父类实例后的所有属性,追着父类实例的原型链走,同样也继承到了父类的方法。

缺点:虽然得到了父类的属性和方法,但是都是在原型上的,当某一个实例对其属性进行更改时,会直接反应到原型上,如果这时实例化另外一个实例的话,就将接受这种更改,这往往是不能接受的,这在倒数。


2.借用构造函数来实现继承

function SuperType(){
    this.colors=["red", "blue", "green"]
}
function SubType(){
   SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
console.info(instance1.colors)  //red, blue, green, black

var instance2 = new SubType();
console.info(instance2.colors)  //red, blue, green

console.info(instance1.hasOwnProperty("colors"), "colors" in instance1)
result: true true

着重看第五行,用了构造函数的call方法, call方法作用在与改变函数执行的作用域,第五行传入的this.也就是子类运行时的作用域,我们把子类作用域传入父类作用域,导致父类定义的那些属性会直接挂载到子类的作用域里,这个时候我们对子类进行实例化后得到的属性为实例属性。这个时候对各种对属性进行操作就不会影响到其他实例了。

缺点:如果方法也按照借用构造函数进行继承的话,那么方法他在每一个实例都会有一个拷贝,显然如果每个实例方法都是一样的话,会造成大量资源的浪费。


3.组合继承

组合继承: 我们把想要继承的属性通过借用构造函数的方法,把方法通过原型链进行继承。

function SuperType(name){
    this.name = name;
    this.colors=["red", "blue", "green"]
}
SuperType.prototype.sayName = function(){
    console.info(this.name);
}
//借用构造函数完成属性的继承
function SubType(name, age){
    SuperType.call(this, name); //添加公共属性
    this.age = age;  //添加自有属性
}
//借用原型链实现方法的继承
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    console.info(this.age);
}

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
console.info(instance1.colors)  //red, blue, green, black
instance1.sayName();  //"Nicholas"
instance1.sayAge()    //29
var instance2 = new SubType("Greg", 27);
console.info(instance2.colors) //red, blue, green
instance2.sayName()  //"Greg"
instance2.sayAge()   //27

但是细心的你会发现我们在借用原型链实现方法的继承时,不仅把父类的方法挂载到原型上,父类的属性也挂载到了原型上,但是我们也借用构造函数实现实例属性的继承,而原则上是不需要挂载属性的,这就造成了原型上属性的冗余。

那么如何规避这种冗余呢?

function SuperType(name){
    this.name = name;
    this.colors=["red", "blue", "green"]
}
SuperType.prototype.sayName = function(){
    console.info(this.name);
}
//借用构造函数完成属性的继承
function SubType(name, age){
    SuperType.call(this, name); //添加公共属性
    this.age = age;  //添加自有属性
}
//借用原型链实现方法的继承
function F(){}
//这样就只继承到了父类原型上的方法。
F.prototype = SuperType.prototype;
SubType.prototype = new F();

// SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
    console.info(this.age);
}

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
console.info(instance1.colors)  //red, blue, green, black
instance1.sayName();  //"Nicholas"
instance1.sayAge()    //29
var instance2 = new SubType("Greg", 27);
console.info(instance2.colors) //red, blue, green
instance2.sayName()  //"Greg"
instance2.sayAge()   //27

这是javascript实现继承的终极方法,很多流行的前端框架内部继承的实现也是基于这一方法的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 5,276评论 3 12
  • 继承是 OO 语言中的一个最为人津津乐道的概念。许多 OO 语言都支持两种继承方式:接口继承 和 实现继承。接口继...
    threetowns阅读 3,165评论 0 0
  • 五十年代夜店里, 蹦迪的年轻人现在都已老去, 可是他们蹦迪的热情不减。 Golden Oldies,黄金年代的老人...
    自由岛设计阅读 2,953评论 2 1
  • 就是这么神奇,一个不经意的选择,就能带给人生不同的变化。脑图特训营让我感觉到自己潜力的变化,变得更加清晰,...
    雪米糍文字搬砖工阅读 1,794评论 0 0
  • 文章结构 1.由“有限无法追求无限”引出养生应该放弃妄想,追求合乎自然。 2.举例“庖丁解牛”说明合乎自然之理的境...
    295442de7134阅读 4,066评论 0 0