JavaScript繼承的六種方式

這是 最近在學習js繼承時看了多篇文章以及自我總結的學習筆記。數組

目錄:
一:原型鏈
二:構造函數
三:原型鏈和構造函數組合繼承
四:原型式
五:寄生式
六:寄生組合式函數

一、原型鏈

function Super(){
  this.name = 'lily';
  this.age = 21;
  this.arr = [1,2,3]
}
function Sub(){}
Sub.prototype = new Super();//核心 拿父類實例來充當子類原型對象
var l1 = new Sub();
var l2 = new Sub();
l1.name = 'gan';
l1.arr.push(4)
l(l1.name)//'gan'
l(l2.name)//'lily'
l(l1.arr)//[1, 2, 3, 4]
l(l2.arr)//[1, 2, 3, 4]

優勢:easy
缺點: 1,原型對象的引用屬性是全部實例共享的, l2.arr跟着 l1.arr一塊兒變化學習


2,構造函數

function Super(name,age){
  this.name = name;
  this.age = age;
  this.arr = [1,2,3];
  this.foo = function(){
  //..
  }
}
function Sub(name,age){
  Super.call(this,[name,age])//核心 在子類型構造函數中調用超類型構造函數
}
var l1 = new Sub('lily',21);
var l2 = new Sub('gan',22);
l1.arr.push(4)
l(l1.name)//["lily", 21]
l(l2.name)//["gan", 22]
l(l1.arr)//[1, 2, 3, 4]
l(l2.arr)//[1, 2, 3]
l(l1.foo === l2.foo)//false

優勢: 解決了子類實例共享父類引用屬性的問題 可傳參
缺點:方法都在構造函數中定義,浪費內存還不能複用。在超類型的原型中定義的方法對子類型而言不可見:this

Super.prototype.sayName = function(){
  l(this.name)
}
l(l1.sayName)//undefined

3,組合式(最經常使用)

function Super(name){
  this.name = name;
  this.age = 21;
  this.arr = [1,2,3];
}
Super.prototype.sayName = function(){
  return this.name
}
function Sub(name){
  Super.call(this,name)//核心
}
Sub.prototype = new Super();//核心
Sub.prototype.constructor = Sub;
var l1 = new Sub('lily');
l(l1.sayName())//lily

優勢:從已有對象衍生新對象,不須要建立自定義類型(更像是對象複製,而不是繼承)
缺點:原型引用屬性會被全部實例共享,由於是用整個父類對象來充當了子類原型對象,因此這個缺陷無可避免;沒法實現代碼複用prototype


4,原型式

function object(o){
  function F(){}
  F.prototype = o;
  return new F();
}
function Super(){
  this.name = 'lily';
  this.age = 21;
  this.arr = [1,2,3,4]
}
Super.prototype.sayName = function(){
  return this.name
}
var Sub = new Super();
l(Sub)//Super {name: "lily", age: 21}
var sup = object(Sub)
l(sup)//F {__proto__: Super}獲得一個「純潔」的新對象(「純潔」是由於沒有實例屬性),再逐步加強之(填充實例屬性)
sup.sex = 'girl'
l(sup)//F {sex: "girl",__proto__: Super}
l(sup.arr) //[1,2,3,4]
l(sup1.arr)//[1,2,3,4]

優勢:從已有對象衍生新對象,不須要建立自定義類型(更像是對象複製,而不是繼承)
缺點:原型引用屬性會被全部實例共享,由於是用整個父類對象來充當了子類原型對象,因此這個缺陷無可避免;沒法實現代碼複用code


5,寄生式

function object(o){
  function F(){}
  F.prototype = o;
  return new F();
}
function Super(){
  this.name = 'lily';
  this.age = 21;
  this.arr = [1,2,3,4]
}
Super.prototype.sayName = function(){
  return this.name
}
function getSubObject(obj){
  // 建立新對象
  var clone = object(obj); // 核心
  // 加強
  clone.attr1 = 1;
  clone.attr2 = 2;
  //clone.attr3...
  return clone;
}
var Sub = getSubObject(new Super());
l(Sub)//Super {name: "lily", age: 21}
var sup = object(Sub)
var sup1 = object(Sub)
l(sup)//F {__proto__: Super}獲得一個「純潔」的新對象(「純潔」是由於沒有實例屬性),再逐步加強之(填充實例屬性)
l(sup.arr)
l(sup1.arr)

6,寄生組合式

function object(o){
  function F(){}
  F.prototype = o;
  return new F();
}
function Super(){
  this.name = 'lily';
  this.age = 21;
  this.arr = [1,2,3,4]
}
Super.prototype.sayName = function(){
  return this.name
}
function Sub(){
  Super.call(this)
}
var proto = object(Super.prototype); // 核心
proto.constructor = Sub; // 核心
Sub.prototype = proto; // 核心

var sub = new Sub();
l(sub.name);
l(sub.arr);

用object(Super.prototype);切掉了原型對象上多餘的那份父類實例屬性對象

相關文章
相關標籤/搜索