JavaScript-原型&原型鏈&原型繼承&組合函數

小小的芝麻之旅:javascript

今天學習了js的原型,要說原型,咱們先簡單說一下函數建立過程。html

原型

每一個函數在建立的時候js都自動添加了prototype屬性,這就是函數的原型,原型就是函數的一個屬性,相似一個指針。原型在函數的建立過程當中由js編譯器自動添加。java

<script type="text/javascript">
        function Flower(name,area) {
            this.name=name;
            this.area=area;
            this.showName=myName;
        }
        //全局對象,瀏覽器 解析器 代碼
        function myName() {
            alert(this.name);
        };
        //建立出一個flower對象
        var f1=new Flower("好季節","待機時間苦咖啡");
         f1.showName();
        var f2=new Flower("接電話","你的那份你看到");
        f2.showName();
        if(f1.showName==f2.showName){
             alert("==");
        }else{
            alert("!=");
        }
    <
/script>

 

原型鏈

在JavaScript中,每一個對象都有一個[[Prototype]]屬性,其保存着的地址就構成了對象的原型鏈
[[Prototype]]屬性是js編譯器在對象被建立時自動添加的,其取值由new運算符的右側參數決定。字面量的方式可轉化爲new Obejct();web

var x =new Flower();
vae o = {};  //var o = new Obejct();

經過對象的[[Prototype]]保存對另外一個對象的引用,經過這個引用往上進行屬性的查找,這就是原型鏈查找機制瀏覽器

對象在查找某個屬性的時候,會首先遍歷自身的屬性,若是沒有則會繼續查找[[Prototype]]引用的對象,若是再沒有則繼續查找[[Prototype]].[[Prototype]]引用的對象,依次類推,直到[[Prototype]].….[[Prototype]]undefinedapp

 

prototype自己是一個Object對象的實例,因此其原型鏈指向的是Object的原型。函數

 

<script type="text/javascript">

        function HUmens(){
            this.foot=2;
        }
//寫一個關於Humens的一個原型上的方法,獲取到foot
        HUmens.prototype.getFoot=function () {
            return this.foot;
        };
        //寫一個子類Man
        function Man() {
            this.head=1;
        }
         Man.prototype=new HUmens();
        Man.prototype,getHead=function () {
            return this.head;
        };
        var man1=new Man();
        alert(man1.foot);

    </script>

 

基於原型鏈的繼承

繼承屬性

JavaScript 對象是動態的屬性「包」(指其本身的屬性)。JavaScript 對象有一個指向一個原型對象的鏈。當試圖訪問一個對象的屬性時,它不只僅在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依此層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。post

prototype 和 Object.getPrototypeOf

對於從 Java 或 C++ 轉過來的開發人員來講 JavaScript 會有點讓人困惑,由於它所有都是動態的,都是運行時,並且不存在類(classes)。全部的都是實例(對象)。即便咱們模擬出的 「類(classes)」,也只是一個函數對象。學習

你可能已經注意到,咱們的函數 A 有一個特殊的屬性叫作原型。這個特殊的屬性與 JavaScript 的 new 運算符一塊兒工做。對原型對象的引用會複製到新實例內部的 __proto__ 屬性。例如,當你這樣: var a1 = new A(), JavaScript 就會設置:a1.__proto__ = A.prototype(在內存中建立對象後,並在運行 this 綁定的函數 A()以前)。而後在你訪問實例的屬性時,JavaScript 首先檢查它們是否直接存在於該對象中(便是否是該對象的自身屬性),若是不是,它會在 __proto__ 中查找。也就是說,你在原型中定義的元素將被全部實例共享,甚至能夠在稍後對原型進行修改,這種變動將影響到全部現存實例。this

像上面的例子中,若是你執行 var a1 = new A(); var a2 = new A(); 那麼 a1.doSomething 事實上會指向Object.getPrototypeOf(a1).doSomething,它就是你在 A.prototype.doSomething 中定義的內容。好比:Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething。

簡而言之, prototype 是用於類型的,而 Object.getPrototypeOf() 是用於實例的(instances),二者功能一致。

__proto__ 看起來就像遞歸引用, 如a1.doSomethingObject.getPrototypeOf(a1).doSomethingObject.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething 等等等, 直到它找到 doSomething 這個屬性或者 Object.getPrototypeOf 返回 null。

關於javascript中apply()和call()方法的區別

若是沒接觸過動態語言,以編譯型語言的思惟方式去理解javaScript將會有種神奇而怪異的感受,由於意識上每每不可能的事恰恰就發生了,甚至以爲不可理喻.若是在學JavaScript,先理解JavaScrtipt動態變換運行時上下文特性,這種特性主要就體如今applycall兩個方法的運用上.

區分apply,call就一句話,

foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

 call, apply都屬於Function.prototype的一個方法,它是JavaScript引擎內在實現的,由於屬於Function.prototype,因此每一個Function對象實例,也就是每一個方法都有call, apply屬性.既然做爲方法的屬性,那它們的使用就固然是針對方法的了.這兩個方法是容易混淆的,由於它們的做用同樣,只是使用方式不一樣.

相同點:兩個方法產生的做用是徹底同樣的

不一樣點:方法傳遞的參數不一樣

 javascript繼承有幾種繼承方式,如今來講說其中的組合繼承。

    組合繼承是結合了原型借用構造函數這兩種技術的繼承方式,分別利用它們的長處,避免了短處。

原型鏈 

        原型鏈就是實例與原型之間的鏈條。

         子類型構造函數     超類型構造函數  之間沒有關聯,只需將   子類型構造函數的原型  做爲  超類型構造函數的實例。這樣,子類型構造函數的實例   就能夠共享    超類型構造函數原型的方法  以及  超類型構造函數的屬性。              

  如:

var subType.prototype = new superType();

原型鏈的短處在於:當subType.prototype做爲實例時擁有的superType構造函數裏的屬性,在它做爲subType的原型時,這些屬性就做爲原型的屬性被subType的實例共享;還有,由於兩個類型的構造函數之間沒有關聯,在建立subType的實例時,不能向superType構造函數傳遞參數。

借用構造函數

             在  子類型構造函數裏  調用  超類型構造函數,使用   call()      或   apply()  方法。

如:

superType.call(this);   或   superType.call(this,參數);

 經過這樣能夠將superType構造函數裏的屬性做爲特定的,即subType的實例調用時,這些屬性也是特屬於每個實例,而不是共享的。同時,還能夠向superType構造函數傳遞參數。

         然而,定義在superType.prototype裏的方法,對subType是不可見的。

         這兩個方法都有其所長,也有其所短。因此將它們組合起來,這就有了組合繼承。瞭解了原型鏈與借用構造函數就不難理解組合繼承了。

 組合繼承

         組合繼承是經過原型鏈繼承原型的方法,經過借用構造函數繼承屬性。這樣就能夠將屬性與方法分開繼承,方法被全部實例共享,而屬性則是特屬於每個實例。

固然,組合繼承也有其缺點,那就是超類型的屬性被繼承了兩次,一次是子類型原型繼承,另外一次是子類型實例繼承,只是實例繼承的屬性屏蔽了原型繼承的屬性。

加例子:

    <script type="text/javascript">
        function  Flower() {
            //空模板
        }
        Flower.prototype.name="大開殺戒";
        Flower.prototype.area="服抗生素世界世界";
        Flower.prototype.showName=function () {
            alert(this.name);
        };
        var flag=Flower.prototype.constructor==Flower;
        alert(flag);
        var flower1=new Flower();
        if(flower1.__proto__==flower1.prototype) {
            alert("---===---");
        }
    </script>

 

 

                                                                                                                                                                             地獄裏的鐮刀====欣欣

相關文章
相關標籤/搜索