1. 程式人生 > >JavaScript-原型&原型鏈&原型繼承&組合函數

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

傳遞參數 style alt isp one ans () bject .cn

小小的芝麻之旅:

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

原型

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

<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();

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

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

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

技術分享

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 對象有一個指向一個原型對象的鏈。當試圖訪問一個對象的屬性時,它不僅僅在該對象上搜尋,還會搜尋該對象的原型,以及該對象的原型的原型,依此層層向上搜索,直到找到一個名字匹配的屬性或到達原型鏈的末尾。

prototypeObject.getPrototypeOf

對於從 Java 或 C++ 轉過來的開發人員來說 JavaScript 會有點讓人困惑,因為它全部都是動態的,都是運行時,而且不存在類(classes)。所有的都是實例(對象)。即使我們模擬出的 “類(classes)”,也只是一個函數對象。

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

像上面的例子中,如果你執行 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動態變換運行時上下文特性,這種特性主要就體現在apply, call兩個方法的運用上.

區分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>

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

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