小小的芝麻之旅: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]]
爲undefined
app
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.doSomething,Object.getPrototypeOf(a1).doSomething,Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething 等等等, 直到它找到 doSomething 這個屬性或者 Object.getPrototypeOf 返回 null。
若是沒接觸過動態語言,以編譯型語言的思惟方式去理解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>
地獄裏的鐮刀====欣欣