blog icon indicating copy to clipboard operation
blog copied to clipboard

JavaScript 常用继承方式总结

Open waltcow opened this issue 8 years ago • 0 comments

基于prototype方式

function Super(){
    this.val = 1;
    this.arr = [];
}
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);    // 2
alert(sub2.arr);    // 2

优缺点

  • 简单,易于实现

  • 原型对象的引用属性是所有实例共享

执行sub1.arr.push(2);先对sub1进行属性查找,找遍了实例属性(在本例中没有实例属性),没找到,就开始顺着原型链向上找,拿到了sub1的原型对象,发现有arr属性。于是给arr末尾插入了2,所以sub2.arr也变了 创建子类实例时,无法向父类构造函数传参

借用构造函数

function Super(val){
    this.val = val;
    this.arr = [];
    this.say = function() { alert(1) }
}
function Sub(val){
    Super.call(this, val); 
    // ...
}

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

alert(sub1.arr);    // [2]
alert(sub2.arr);    // []

alert(sub1.say === sub2.say);   // false

优缺点

  • 解决了子类实例共享父类引用属性的问题
  • 创建子类实例时,可以向父类构造函数传参
  • 无法实现函数复用,每个子类实例都持有一个新的say函数,会影响性能,内存增加

组合继承

function Super(){
    this.val = 1;
    this.arr = [];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};

function Sub(){
    Super.call(this);   
    // ...
}
Sub.prototype = new Super();   

var sub1 = new Sub(1);
var sub2 = new Sub(2);
alert(sub1.fun === sub2.fun);   // true

优缺点

  • 不存在引用属性共享问题
  • 可传参
  • 函数可复用
  • 父类构造函数被调用了两次,子类原型上有一份多余的父类实例属性

寄生组合继承

function create(obj) {   
    var F = function(){};
    F.prototype = obj;
    return new F();
}

function Super(){
    this.val = 1;
    this.arr = [1];
}

Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};

function Sub(){
    Super.call(this);  
    // ...
}
var proto = create(Super.prototype); 
proto.constructor = Sub;             
Sub.prototype = proto;               

var sub = new Sub();
alert(sub.val);
alert(sub.arr);

优缺点

  • 最佳方式

原型式继承

function create(obj){  
    var F = function(){};
    F.prototype = obj;
    return new F();
}
function Super(){
    this.val = 1;
    this.arr = [];
}

// 拿到父类对象
var sup = new Super();

var sub = create(sup); 
// 增强
sub.attr1 = 1;
sub.attr2 = 2;
//sub.attr3...

alert(sub.val);     // 1
alert(sub.arr);     // 1
alert(sub.attr1);   // 1

优缺点

  • create函数得到得到一个“纯洁”的新对象(“纯洁”是因为没有实例属性),再逐步增强之(填充实例属性), ES5提供了Object.create()函数,内部就是原型式继承
  • 无法实现函数复用
  • 原型引用属性会被所有实例共享

waltcow avatar Feb 10 '17 07:02 waltcow