1. 程式人生 > >我對JS的繼承的理解

我對JS的繼承的理解

js的原型繼承

原型鏈是實現js繼承的主要方法,他的原理是讓利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。如果我們讓一個原型物件等於一個例項,那麼,此時的原型物件將包含指向另一個原型的指標假如另一個原型又等於一個物件的例項,如此一層套一層,這就是原型鏈的基本概念。

下邊是一個簡單的例子

    var Parent = function(){
        this.name = 'parent' ;
    } ;
    Parent.prototype.getName = function(){
        return this.name ;
    } ;
    Parent.prototype.obj = {a : 1
} ; var Child = function(){ this.name = 'child' ; } ; Child.prototype = new Parent() ; var parent = new Parent() ; var child = new Child() ; console.log(parent.getName()) ; //parent console.log(child.getName()) ; //child

以上程式碼定義了兩個型別:parent和chiled。每個型別都有一個屬性和方法,他們主要的區別就是child繼承了parent,繼承是通過建立parent的例項,並把這個例項賦給child.prototype實現的
實現的本質是重寫了原型鏈物件,取代他的是新的例項。直接把父類的物件賦值給子類建構函式的原型,這樣子類的物件就可以訪問到父類以及父類建構函式的prototype中的屬性。
我們可以用instanceof操作符判斷,用這個操作符測試例項和原型鏈中出現過的建構函式,就返回true

借用建構函式

什麼是建構函式

JavaScript的建構函式並不是作為類的一個特定方法存在的;當任意一個普通函式用於建立一類物件時,它就被稱作建構函式,或構造器。一個函式要作為一個真正意義上的建構函式,需要滿足下列條件:

1、 在函式內部對新物件(this)的屬性進行設定,通常是新增屬性和方法。

2、 建構函式可以包含返回語句(不推薦),但返回值必須是this,或者其它非物件型別的值。
關於JavaScript的建構函式,有一個容易混淆的地方,那就是原型的constructor屬性。在JavaScript中,每一個函式都有預設的原型物件屬性prototype,該物件預設包含了兩個成員屬性:constructor和proto

。關於原型的細節就不在本文贅述了,我們現在關心的是這個constructor屬性。

按照面向物件的習慣性思維,我們說建構函式相當於“類”的定義,從而可能會認為constructor屬性就是該類實際意義上的建構函式,在new表示式建立一個物件的時候,會直接呼叫constructor來初始化物件,那就大錯特錯了。new表示式執行的實際過程已經在上文中介紹過了(四個步驟),其中用於初始化物件的是第三步,呼叫的初始化函式正是“類函式”本身,而不是constructor

    function CO(){
    this.p = “I’m in constructed object”;
    this.alertP = function(){
        alert(this.p);
        }
    }
    var o2 = new CO();

借用建構函式繼承

這個基本思想很簡單,也就是在子型別建構函式的內部呼叫超型別建構函式。因為函式只不過是在特定環境中執行程式碼的物件,因此可以通過使用apply()和call()方法也可以在新建立的物件上執行的建構函式。

   function superType(){
       this.colors = ["red","blue","green"];
   }
   function subtype(){
       superType.call(this);
   }
   var instance1 = new subtype();
   instance1.colors.push("black");
   alert(instance1.colors);//"red,blue,green,black"
   var instance2 = new subtype();
   alert(instance2.colors);//"red,blue,green"

通過使用call(),我們實際上是在新建立的subtype例項環境下呼叫了supertype()建構函式,這樣一來,就會在新subtype物件上執行supertype建構函式,因此就會在subtype物件上執行supertype()函式中定義的所有物件初始化程式碼

   function superType(name){
       this.name = name;
   }
   function subtype(){
       superType.call(this,"Marry");
       this.age = 29;
   }
   var instance = new subtype();
   alert(instance.name);//"Marry"
   alert(instance2.age);//"29"

這是建構函式的一個很大的優勢,可以在子型別建構函式中向超型別建構函式傳遞引數。