js繼承的幾種方式

NO IMAGE

定義一個父類:

// 定義一個動物類function Animal (name) {  // 屬性  this.name = name || 'Animal';  // 實例方法  this.sleep = function(){    alert(this.name + '正在睡覺!');  }}// 原型方法Animal.prototype.eat = function(food) {  alert(this.name + '正在吃:' + food);};

1、原型鏈繼承

核心:將父類的實例作為子類的原型;

function Cat(){}Cat.prototype = new Animal();Cat.prototype.name = 'cat'; // Test Codevar cat = new Cat();alert(cat.name);alert(cat.eat('fish'));alert(cat.sleep());alert(cat instanceof Animal); //truealert(cat instanceof Cat); //true

特點:

(1)非常純粹的繼承關係,實例是子類的實例,也是父類的實例;

(2)父類新增原型方法/原型屬性,子類都能訪問到;

缺點:

(1)要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行,不能放到構造器中;

(2)無法實現多繼承;

(3)來自原型對象的引用屬性是所有實例共享的;

(4)創建子類實例時,無法向父類構造函數傳參。

2、借用構造函數繼承

核心:使用父類的構造函數來增強子類實例,等於是複製父類的實例屬性給子類(沒用到原型)

function Cat(name){  Animal.call(this);  this.name = name || 'Tom';} // Test Codevar cat = new Cat();alert(cat.name);alert(cat.sleep());alert(cat instanceof Animal); // falsealert(cat instanceof Cat); // true

特點:

(1)解決了1中,子類實例共享父類引用屬性的問題;

(2)創建子類實例時,可以向父類傳遞參數;

(3)可以實現多繼承(call多個父類對象)(不完美,沒有父類方法)

缺點:

(1)實例並不是父類的實例,只是子類的實例;

(2)只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法;

(3)無法實現函數複用,每個子類都有父類實例函數的副本,影響性能。

3、組合繼承

核心:通過調用父類構造函數,繼承父類的屬性並保留傳參的優點,然後通過將父類實例作為子類原型,繼承父類屬性和方法,實現函數複用;

function Cat(name){  Animal.call(this);  this.name = name || 'Tom';}Cat.prototype = new Animal(); // Test Codevar cat = new Cat();alert(cat.name);alert(cat.sleep());alert(cat instanceof Animal); // truealert(cat instanceof Cat); // true

特點:

(1)彌補了方式2的缺陷,可以繼承實例屬性/方法,也可以繼承原型屬性/方法;

(2)既是子類的實例,也是父類的實例;

(3)不存在引用屬性共享問題;

(4)可傳參;

(5)函數可複用;

(6)可以實現多繼承(同上)

缺點:

(1)調用了兩側父類構造函數,生成了兩份實例(子類實例將子類原型上的那份屏蔽了)(僅僅多消耗了一點內存)

4、原型式繼承

核心:繼承已有的對象而不是函數

//對傳入的對象執行一次淺複製function object(o){      function F(){}      F.prototype = o;      return new F();}//例子var Animal = {      name:"cat",      friend:["aaron","cassic"]}var cat=object(Animal);cat.name="sss";cat.friend.push("aseaff");alert(cat.name);alert(cat.friend);

特點:

(1)沒有必要創建構造函數,只是想讓一個對象與另一個對象保持類似;

(2)與原型模式一樣,包含引用類型的屬性值會共享。

5、寄生式繼承

核心:與原型式繼承緊密相關,只是多了方法;

//對傳入的對象執行一次淺複製function object(o){      function F(){}      F.prototype = o;      return new F();}//增強對象function createobject(o){     var clone=object(o);     clone.sayname=function(){        alert("hi");};    return clone;}//例子var Animal = {      name:"cat",      friend:["aaron","cassic"]}var cat=createobject(Animal);cat.sayname();

特點:

(1)沒有必要創建構造函數,只是想讓一個對象與另一個對象保持類似;

(2)與原型式繼承相比,有了自己的方法;

缺點:

(1)與原型式繼承一樣,包含引用類型的屬性值會共享;

6、寄生組合繼承

核心:通過寄生方式,創建空函數,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實力你方法/屬性,避免了組合繼承的缺點。

function Cat(name){  Animal.call(this);  this.name = name || 'Tom';}function aaron(o,y){ var Super = function(){}; Super.prototype=y.prototype; o.prototype=new Super(); o.prototype.constructor=o; }aaron(Cat,Animal);// Test Codevar cat = new Cat();alert(cat.name);cat.sleep();alert(cat instanceof Animal); // truealert(cat instanceof Cat); //true

特點:

  1. 堪稱完美

缺點:

  1. 實現較為複雜
  2. 不能實現多繼承(不完美,同上)

## 多繼承

7、拷貝繼承

function Cat(name){  var animal = new Animal();  for(var p in animal){    Cat.prototype[p] = animal[p];  }  Cat.prototype.name = name || 'Tom';} // Test Codevar cat = new Cat();alert(cat.name);cat.sleep();alert(cat instanceof Animal); // falsealert(cat instanceof Cat); // true

特點:

支持多繼承

缺點:

效率較低,內存佔用高(因為要拷貝父類的屬性)(使用 for in 能遍歷原型方法)

8、組合使用構造函數和拷貝實現多繼承

function Parent1(name,age){    this.name = name;    this.age = age;    this.height=180;}Parent1.prototype.say = function(){    alert('hi');}function Parent2(name,age,weight){    this.name = name;    this.age = age;    this.weight = weight;    this.height = 170;    this.skin='yellow';}Parent2.prototype.walk = function(){    alert('walk');}  function Child(name,age,weight){    Parent1.call(this,name,age);    Parent2.call(this,name,age,weight);}  for(var i in Parent1.prototype){Child.prototype[i] = Parent1.prototype[i]}for(var i in Parent2.prototype){Child.prototype[i] = Parent2.prototype[i]}  var c1 = new Child('xiaoming',10,8);console.log(c1); //Child { name="xiaoming", age=10, height=170, 更多...}console.log(c1.constructor);//Child(name,age,weight)

特點:

javascript的多繼承其實就是前面介紹的js循環拷貝繼承的多次使用

總結:

javascript是可以利用call方法和prototype屬性來實現多繼承的。繼承方法與單繼承相似,只是將需要繼承的多個父類依次實現,另外對於屬性或共有方法重命的時候,以最後繼承的屬性和方法為主。因為會覆蓋前面的繼承。

最好的兩個繼承是寄生組合繼承和循環拷貝繼承,但是寄生組合繼承不能完美實現多繼承,會漏掉父類原型方法,只有循環拷貝繼承可以完美實現多繼承。

原文鏈接:www.cnblogs.com/aaronchu/p/…

相關文章

瀏覽器兼容性js

前端性能優化的方法

原型鏈

js中的事件委託(事件代理)