萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> javascript框架設計之類工廠

javascript框架設計之類工廠

 這篇文章主要介紹了javascript框架設計之類工廠的相關資料,非常淺顯易懂,有需要的小伙伴可以查看下。

   

類與繼承在javascript的出現,說明javascript已經達到大規模開發的門檻了,在之前是ECMAScript4,就試圖引入類,模塊等東西,但由於過分引入太多的特性,搞得javascript烏煙瘴氣,導致被否決。不過只是把類延時到ES6.到目前為止,javascript還沒有正真意義上的類。不過我們可以模擬類,曾近一段時間,類工廠是框架的標配,本章會介紹各種類實現,方便大家在自己的框架中或選擇時自己喜歡的那一類風格。

1.javascript對類的支持

在其它語言中 ,類的實例都要通過構造函數new出來。作為一個刻意模仿java的語言。javascript存在new操作符,並且所有函數都可以作為構造器。構造函數與普通的方法沒有什麼區別。浏覽器為了構建它繁花似錦的生態圈,比如Node,Element,HTMLElement,HTMLParagraphElement,顯然使用繼承關系方便一些方法或屬性的共享,於是javascript從其它語言借鑒了原型這種機制。Prototype作為一個特殊的對象屬性存在於每一個函數上。當一個函數通過new操作符new出其“孩子”——“實例”,這個名為實例的對象就擁有這個函數的Prototype對象所有的一切成員,從而實現實現所有實例對象都共享一組方法或屬性。而javascript所謂的“類”就是通過修改這個Prototype對象,以區別原生對象及其其它定義的“類”。在浏覽器中,node這個類基於Object修改而來的,而Element則是基於Node,而HTMLElement又基於Element....相對我們的工作業務,我們可以創建自己的類來實現重用與共享。

? 1 2 3 4 5 6 7 8 9 10 11 12 function A(){   } A.prototype = { aa:"aa", method:function(){ } }; var a = new A; var b = new A; console.log(a.aa === b.aa); console.log(a.method === b.method)

一般地,我們把定義在原型上的方法叫原型方法,它為所有的實例所共享,這有好也有不好,為了實現差異化,javascript允許我們直接在構造器內指定其方法,這叫特權方法。如果是屬性,就叫特權屬性。它們每一個實例一個副本,各不影響。因此,我們通常把共享用於操作數據的方法放在原型,把私有的屬性放在特權屬性中。但放於this上,還是讓人任意訪問到,那就放在函數體內的作用域內吧。這時它就成為名副其實的私有屬性。

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function A() { var count = 0; this.aa = "aa"; this.method = function() { return count; } this.obj = {} } A.prototype = { aa:"aa", method:function(){   } }; var a = new A; var b = new A; console.log(a.aa === b.aa);//true 由於aa的值為基本類型,比較值 console.log(a.obj === b.obj) //false 引用類型,每次進入函數體都要重新創建,因此都不一樣。 console.log(a.method === b.method); //false

特權方法或屬性只是只是遮住原型的方法或屬性,因此只要刪掉特權方法,就能方法到同名的原型方法或屬性。

? 1 2 3 4 delete a.method; delete b.method; console.log(a.method === A.prototype.method);//true console.log(a.method === b.method); //true

用java的語言來說,原型方法與特權方法都屬性實例方法,在java中還有一種叫類方法與類屬性的東西。它們用javascript來模擬也非常簡單,直接定義在函數上就行了。

? 1 2 3 A.method2 = function(){} //類方法 var c = new A; console.log(c.method2); //undefined

接下來,我們看下繼承的實現,上面說過,Prototype上有什麼東西,它的實例就有什麼東西,不論這個屬性是後來添加的,還是整個Prototype都置換上去的。如果我們將這個prototype對象置換為另一個類的原型,那麼它就輕而易舉的獲得那個類的所有原型成員。

? 1 2 3 4 5 6 7 8 9 10 function A() {}; A.prototype = { aaa : 1 } function B() {}; B.prototype = A.prototype; var b = new B; console.log(b.aaa); //=> 1; A.prototype.bb = 2; console.log(b.bb) //=> 2;

由於是引用著同一個對象,這意味這,我們修改A類的原型,也等同於修該了B類的原型。因此,我們不能把一個對象賦值給兩個類。這有兩種辦法,

方法1:通過for in 把父類的原型成員逐一賦給子類的原型
方法2是:子類的原型不是直接由父類獲得,先將父類的原型賦值給一個函數,然後將這個函數的實例作為子類的原型。

方法一,我們通常要實現mixin這樣的方法,有的書稱之為拷貝繼承,好處就是簡單直接,壞處就是無法通過instanceof驗證。Prototype.js的extend方法就用來干這事。

? 1 2 3 4 5 function extend (des, source) { //des = destination for (var property in source) des[property] = source[property]; return des; }

方法二,就在原型上動腦筋,因此稱之為原型繼承。下面是個范本

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 function A() {}; A.prototype = { aa:function(){ alert(1) } } function bridge() {   }; bridge.prototype = A.prototype;   function B() {} B.prototype = new bridge();   var a = new A; var b = new B;   console.log(a == b) //false 證明成功分開原型 console.log(A.prototype == B.prototype) //true 子類共享父類的原型方法 console.log(a.aa === b.aa); //為父類動態添加新的方法 A.prototype.bb = function () { alert(2) } //true,繼承父類的方法 B.prototype.cc = function (){ alert(3) } //false 父類未必有子類的new實例 console.log(a.cc === b.cc) //並且它能夠正常通過javascript自帶的驗證機制instanceof console.log(b instanceof A) ;//true console.log(b instanceof B) ; //true
copyright © 萬盛學電腦網 all rights reserved