摘要:依賴于接口的設計模式下面列出的設計模式,尤其依賴接口工廠模式。這些私用的靜態成員可以從構造器內部訪問,這意味著所有私用函數和特權函數都能訪問它們。構造器靜態特權方法封裝之弊私用方法很難進行單元測試。
1.弱類型語言
2.初談閉包在JavaScript中,定義變量時不必聲明其類型。但這并不意味著變量沒有類型。一個變量可以屬于幾種類型之一,這取決于其包含的數據。JavaScript中有三種原始類型:布爾型、數值型和字符串類型(不區分整數和浮點數是JavaScript與大多數其他主流語言的一個不同之處)。此外,還有對象類型和包含可執行代碼的函數類型,前者是一種復合數據類型(數組是一種特殊的對象,它包含著一批值的有序集合)。最后,還有空類型(null)和未定義類型(undefined)這兩種數據類型。原始數據類型按值傳送,而其他數據類型則按引用傳送。
與其他弱類型語言一樣,JavaScript中的變量可以根據所賦的值改變類型。原始類型之間也可以進行類型轉換。toString可以把數值或布爾值轉為字符串。parseFloat和parseInt函數可以把字符串轉變為數值。雙重“非”可以把字符串或數值轉變為布爾值:var bool = !!num;
匿名函數最有趣的用途是用來創建閉包。閉包是一個受到保護的變量空間,由內嵌函數生成。JavaScript具有函數級的作用域。這意味著定義在函數內部的變量在函數外部不能被訪問。JavaScript的作用域又是詞法性質的。這意味著函數運行在定義它的作用域中,而不是在調用它的作用域中。把這兩個因素結合起來,就能通過把變量包裹在匿名函數中而對其加以保護。3.依賴于接口的設計模式
4.用命名規范區別私用成員下面列出的設計模式,尤其依賴接口:
工廠模式。對象工廠所創建的具體對象會因具體情況而異。使用接口可以確保所創建出來的這些對象可以互換使用。也就是說,對象工廠可以保證其生產出來的對象都實現了必需的方法。
組合模式。如果不用接口你就不可能用這個模式。組合模式的中心思想在于可以將對象群體與其組成對象同等對待。這是通過讓它們實現同樣的接口來做到的。如果不進行某種形式的鴨式辨型或類型檢查,組合模式就會失去大部分作用。
裝飾者模式。裝飾者通過透明地為另一對象提供包裝而發揮作用。這是通過實現與另外那個對象完全相同的接口而做到的。對于外界而言,一個裝飾者和它所包裝的對象看不出有什么區別。
命令模式。代碼中所有的命令對象都要實現同一批方法。通過使用接口,你為執行這些命令對象而創建的類可以不必知道這些對象具體是什么,只要知道它們都實現了正確的接口即可。
在一些方法和屬性的名稱前面加下劃線以示其私用性。下劃線的這種用法是一個眾所周知的命名規范,它表明一個屬性(或方法)僅供對象內部使用,直接訪問它或設置它可能會導致意想不到的后果。這有助于防止程序員對它的無意使用,卻不能防止對它的有意使用。后一個目標的實現需要有真正私用性的方法。5.作用域
下面這個示例說明了JavaScript中作用域的特點:
function foo() { var a = 10; function bar() { a *= 2; } bar(); return a; }
在這個示例中,a定義在函數foo中,但函數bar可以訪問它,因為bar也定義在foo中。bar在執行過程中將a設置為a乘以2。當bar在foo中被調用時它能夠訪問a,這可以理解。但是如果bar是在foo外部被調用呢?
function foo() { var a = 10; function bar() { a *= 2; return a; } return bar; } var baz = foo(); console.log(baz());//20 console.log(baz());//40 console.log(baz());//80 var blat = foo(); console.log(blat());//20
在上述代碼中,所返回的對bar函數的引用被賦給變量baz。這個函數現在是在foo外部被調用,但它依然能夠訪問a。這是因為JavaScript的作用域是詞法性的。函數是運行在定義它們的作用域中(本例中是foo內部的作用域),而不是運行在調用它們的作用域中。只要bar被定義在foo中,它就能訪問在foo中定義的所有變量,即使foo的執行已經結束。
這就是閉包的一個例子。在foo返回后,它的作用域被保存下來,但只有它返回的那個函數能夠訪問這個作用域。在前面的示例中,baz和blat各有這個作用域及a的一個副本,而且只有它們自己能對其進行修改。返回一個內嵌函數是創建閉包最常用的手段。
在門戶打開型對象創建模式中,所有方法都創建在原型對象中,因此不管派生多少對象實例,這些方法在內存中只存在一份。而包含特權方法、私用成員的創建模式中,每生成一個新的對象示例都將為每一個私用方法和特權方法生成一個新的副本。這會比其他做法耗費更多內存,所以只宜用在需要真正的私用成員的場合。這種對象創建模式也不利于派生子類,因為所派生出的子類不能訪問超類的任何私用屬性或方法。相比之下,在大多數語言中,子類都能訪問超類的所有私有屬性和方法。故在JavaScript中用閉包實現私用成員導致的派生問題稱為“繼承破壞封裝”。7.靜態方法和屬性
前面所講的作用域和閉包的概念可用于創建靜態成員,包括公用和私用的。大多數方法和屬性所關聯的是類的實例,而靜態成員所關聯的則是類本身。換句話說,靜態成員是在累的層次上操作,而不是在實例的層次上操作。每個靜態成員都只有一份。稍后將會看到,靜態成員是直接通過類對象訪問的。
下面是添加了靜態屬性和方法的Book類:
var Book = (function () { //私有靜態變量 var numOfBooks = 0; //私有靜態方法 function checkIsbn(isbn) { } //返回一個構造器 return function (newIsbn, newTitle, newAuthor) { //私有屬性 var isbn, title, author; //特權方法 this.getIsbn = function () { return isbn; }; this.setIsbn = function (newIsbn) { if (!checkIsbn(newIsbn)) { throw new Error("Book: Invalid ISBN."); } isbn = newIsbn; }; this.getTitle = function () { return title; }; this.setTitle = function (newTitle) { title = newTitle || "No title specified"; }; this.getAuthor = function () { return author; }; this.setAuthor = function (newAuthor) { author = newAuthor || "No author specified"; }; //Constructed code. numOfBooks++; if (numOfBooks > 50) { throw new Error("."); } this.setIsbn(newIsbn); this.setTitle(newTitle); this.setAuthor(newAuthor); } })(); //公共靜態方法 Book.convertToTitleCase = function (inputString) { }; //公共非特權方法 Book.prototype = { display: function () { } };
這里的私用成員和特權成員仍然被聲明在構造器中(分別使用var和this關鍵字)。但哪個構造器卻從原來的普通函數變成了一個內嵌函數,并且被作為包含它的函數的返回值賦給變量Book。這就創建了一個閉包,你可以把靜態的私用成員聲明在里面。位于外層函數聲明之后的一對空括號很重要,其作用是一段代碼載入就立即執行這個函數(而不是在調用Book構造函數時)。這個函數的返回值是另一個函數,它被賦給Book變量,Book因此成了一個構造函數。在實例化Book時,所調用的是這個內層函數。外層那個函數只是用于創建一個可以用來存放靜態私用成員的閉包。
8.私用變量模仿常量在本例中,checkIsbn被設計為靜態方法 ,原因是為Book的每個實例都生成這個方法的一個新副本毫無道理。此外還有一個靜態屬性numOfBooks,其作用在于跟蹤Book構造器的總調用次數。本例利用這個屬性將Book實例的個數限制為不超過50個。
這些私用的靜態成員可以從構造器內部訪問,這意味著所有私用函數和特權函數都能訪問它們。與其他方法相比,它們有一個明顯的優點,那就是內存中只會存放一份。因為其中那些靜態方法被聲明在構造器之外,所以它們不是特權方法,不能訪問任何定義在構造器中的私用屬性。定義在構造器中的私用方法能夠調用那些私用靜態方法,反之則不然。要判斷一個私用方法是否應該被設計為靜態方法,一條經驗法則是看它是否需要訪問任何實例數據。如果它不需要,那么將其設計為靜態方法會更有效率(從內存占用的意義上來講),因為它只會被創建一份。
創建公用的靜態成員則容易得多,只需直接將其作為構造函數這個對象的屬性創建即可,前述代碼中的方法converToTitleCase就是一例。這實際上相當于把構造器作為命名空間來使用。
所有公用靜態方法如果作為獨立的函數來聲明其實也同樣簡單,但最好還是像這樣把相關行為集中在一起。這些方法用于與類這個整體相關的任務,而不是與類的任一特定實例相關的任務。它們并不直接依賴于對象實例中包含的任何數據。
通過創建只有取值器而沒有賦值器的私用變量可以模仿常量。
var Class = (function () { var UPPER_BOUND = 100; //構造器 var ctor = function (constructorArgument) { }; //靜態特權方法 ctor.getUPPER_BOUND = function () { return UPPER_BOUND; }; return ctor; })();9.封裝之弊
10.單體模式私用方法很難進行單元測試。因為它們及其內部變量都是私用的,所以在對象外部無法訪問到它們。這個問題沒有什么很好的應對之策。你要么通過使用公用方法來提供訪問途徑(這樣一來就葬送了使用私有方法所帶來的大多數好處),要么設法在對象內部定義并執行所有單元測試。最好的解決辦法是只對公用方法進行單元測試。這應該能覆蓋到所有私用方法,盡管對它們的測試只是間接的。這種問題不是JavaScript所獨有的,只對公用方法進行單元測試是一種廣為接收的處理方式。
使用封裝意味著不得不與復雜的作用域鏈打交道。
封裝可能會損害類的靈活性,致使其無法被用于某些你未曾想到過的目的。
單體模式是JavaScript中最基本但又最有用的模式之一,它可能比其他任何模式都更常用。這種模式提供了一種將代碼組織為一個邏輯單元的手段,這個邏輯單元中的代碼可以通過單一的變量進行訪問。通過確保單體對象只存在一份實例,你就可以確信自己的所有代碼使用的都是同樣的全局資源。11.單體的基本結構
單體類在JavaScript中有許多用處。它們可以用來劃分命名空間,以減少網頁中全局變量的數目。更重要的是,借助于單體模式,你可以把代碼組織得更為一致,從而使其更容易閱讀和維護。
var Singleton = { attribute1: true, attribute2: 10, method1: function () { }, method2: function (args) { } };
這個單體對象可以被修改。你可以為其添加新成員,這一點與別的對象字面量沒有什么不同。你也可以用delete運算符刪除其現有成員。這實際上違背了面向對象設計的一條原則:類可以被擴展,但不應該被修改。
按傳統的定義,單體是一個只能被實例化一次并且可以通過一個眾所周知的訪問點訪問的類。要是嚴格按照這個定義來說,前面的例子所示的并不是一個單體,因為它不是一個可實例化的類。我們打算把單體模式定義的更廣義一些:單體是一個用來劃分命名空間并將一批相關方法和屬性組織在一起的對象,如果可以被實例化,那么它只能被實例化一次。
12.劃分命名空間為了避免無意中改寫變量,最好的解決辦法之一是用單體對象將代碼組織在命名空間之中。下面是前面的例子用單體模式改良后的結果:
var MyNamespace = { findProduct: function (id) { } };
現在findProduct函數是MyNamespace中的一個方法,它不會被全局命名空間中聲明的任何新變量改寫。要注意,該方法仍然可以從各個地方訪問。不同之處在于現在其調用方式不是findProduct(id),而是MyNamespace.findProduct(id)。還有一個好處就是,這可以讓其他程序員大體知道這個方法的聲明地點及其作用。用命名空間把類似的方法組織到一起,也有助于增強代碼的文檔性。
13.模塊模式有一種單體模式被稱為模塊模式,因為它可以把一批相關方法和屬性組織為模塊并起到劃分命名空間的作用。例如:
MyNamespace.Singleton = (function () { //私有成員 var privateAttribute1 = false; var privateAttribute2 = [1, 2, 3]; function privateMethod1() { } function privateMethod2() { } return { //public members publicAttribute1: true, publicAttribute2: 10, publicMethod1: function () { }, publicMethod2: function (args) { } } })();14.簡單工廠模式
最好用一個例子來說明簡單工廠模式的概念。假設你想開幾個自行車商店,每個店都有幾種型號的自行車出售。這可以用一個類來表示:
/*BicycleShop class.*/ var BicycleShop = function () { }; BicycleShop.prototype = { sellBicycle: function (model) { var bicycle; switch (model) { case "The Speedster": bicycle = new SpeedSter(); break; case "The Lowrider": bicycle = new Lowrider(); break; case "The Comfort Cruiser": default: bicycle = new ComfortCruiser(); } Interface.ensureImplements(bicycle, Bicycle); bicycle.assemble(); bicycle.wash(); return bicycle; } };
sellBicycle方法根據所要求的自行車型號用switch語句創建一個自行車的實例。各種型號的自行車實例可以互換使用,因為它們都實現了Bicycle接口:
/* The Bicycle interface. */ var Bicycle = new Interface("Bicycle", ["assemble", "wash", "ride", "repair"]); /* Speedster class. */ var Speedster = function () { }; Speedster.prototype = { assemble: function () { }, wash: function () { }, ride: function () { }, repair: function () { } };
要出售某種型號的自行車,只要調用sellBicycle方法即可:
var californiaCruisers = new BicycleShop(); var yourNewBike = californiaCruisers.sellBicycle("The Speedster");
在情況發生變化之前,這倒也挺管用。但要是你想在供貨目錄中加入一款新車型又會怎么樣呢?你得為此修改BicycleShop的代碼,哪怕這個類的實際功能實際上并沒有發生改變——依舊是創建一個自行車的新實例,組裝它,清洗它,然后把它交給顧客。更好的解決辦法是把sellBicycle方法中“創建新實例”這部分工作轉交給一個簡單工廠對象:
/* BicycleFactory namespace. */ var BicycleFactory = { createBicycle:function(model){ var bicycle; switch (model) { case "The Speedster": bicycle = new SpeedSter(); break; case "The Lowrider": bicycle = new Lowrider(); break; case "The Comfort Cruiser": default: bicycle = new ComfortCruiser(); } Interface.ensureImplements(bicycle, Bicycle); return bicycle; } };
BicycleFactory是一個單體,用來把createBicycle方法封裝在一個命名空間中。這個方法返回一個實現了Bicycle接口的對象,然后你可以照常對其進行組裝和清洗:
/* BicycleShop class, improved. */ var BicycleShop = function () { }; BicycleShop.prototype = { sellBicycle: function (model) { var bicycle = BicycleFactory.createBicycle(model); bicycle.assemble(); bicycle.wash(); return bicycle; } };
這個BicycleFactory對象可以供各種類用來創建新的自行車實例。有關可供車型的所有信息集中在一個地方管理 ,所以添加更多車型很容易:
/* BicycleFactory namespace,with more models. */ var BicycleFactory = { createBicycle: function (model) { var bicycle; switch (model) { case "The Speedster": bicycle = new SpeedSter(); break; case "The Lowrider": bicycle = new Lowrider(); break; case "The Flatlander": bicycle = new Flatlander(); break; case "The Comfort Cruiser": default: bicycle = new ComfortCruiser(); } Interface.ensureImplements(bicycle, Bicycle); return bicycle; } };15.工廠模式
真正的工廠模式與簡單工廠模式的區別在于,它不是另外使用一個類或對象來創建自行車,而是使用一個子類。按照正式定義,工廠是一個將其成員對象的實例化推遲到子類中進行的類。16.工廠模式的適用場合
17.工廠模式之利動態實現:如果需要創建一些用不同方式實現同一接口的對象,那么可以使用一個工廠方法或簡單工廠對象來簡化選擇實現的過程。
節省設置開銷:如果對象需要進行復雜并且彼此相關的設置,那么使用工廠模式可以減少每種對象所需的代碼量。如果這種設置只需要為特定類型的所有實例執行一次即可,這種作用尤為突出。把這種設置代碼放到類的構造函數中并不是一種高效的做法,這是因為即便設置工作已經完成,每次創建新實例的時候這些代碼還是會執行,而且這樣做會把設置代碼分散到不同的類中。工廠方法非常適合于這種場合。它可以在實例化所有需要的對象之前先一次性地進行設置。無論有多少類會被實例化,這種辦法都可以讓設置代碼集中在一個地方。
用許多小型對象組成一個大對象
18.橋接模式工廠模式的主要好處在于消除對象間的耦合。通過使用工廠方法而不是new關鍵字及具體類,你可以把所有實例化的代碼集中在一個位置。這可以大大簡化更換所用的類或在運行期間動態選擇所用的類的工作。在派生子類時它也提供了更強大的靈活性。
所有這些好處都與面向對象設計的這兩條原則有關:弱化對象間的耦合;防止代碼的重復。在一個方法中進行類的實例化,可以消除重復性的代碼。這是在用一個對接口的調用取代一個具體的實現。這些都有助于創建模塊化的代碼。
橋接模式最常見和實際的應用場合之一就是事件監聽器回調函數。假設有一個名為getBeerById的API函數,它根據一個標識符返回有關某種啤酒的信息。你希望用戶在點擊的時候獲取這種信息。那個被點擊的元素很可能有啤酒的標識符信息,它可能是作為元素自身的ID保存,也可能是作為別的自定義屬性保存。下面是一種做法:
addEvent(element, "click", getBeerById); function getBeerById(e) { var id = this.id; asyncRequest("GET", "beer.uri?id=" + id, function (resp) { console.log(resp.responseText); }); }
這個API只能工作在瀏覽器中,如果要對這個API函數做單元測試,或者在命令行中執行,可能會報錯。一個優良的API設計,不應該把它與任何特定的實現攪在一起。
function getBeerById(id, callback) { asyncRequest("GET", "beer.uri?id=" + id, function (resp) { callback(resp.responseText); }) }
現在我們將針對接口而不是實現進行編程,用橋接模式把抽象隔離開來:
addEvent(element, "click", getBeerByIdBridge); function getBeerBIdBridge(e) { getBeerById(this.id, function (beer) { console.log(beer); }); }
這下getBeerById并沒有和事件對象捆綁在一起了。
19.用橋接模式聯結多個類var Class1 = function (a, b, c) { this.a = a; this.b = b; this.c = c; }; var Class2 = function (d) { this.d = d; }; var BridgeClass = function (a, b, c, d) { this.one = new Class1(a, b, c); this.two = new Class2(d); };20.適配器模式
適配器模式可以用來在現有接口和不兼容的類之間進行適配。使用這種模式的對象又叫包裝器,因為它們是在用一個新的接口包裝另一個對象。
21.適配器的特點適配器可以被添加到現有代碼中以協調兩個不同的接口。如果現有代碼的接口能很好地滿足需要,那就可能沒有必要使用適配器。
從表面上看,適配器模式很像門面模式。它們都要對別的對象進行包裝并改變其呈現的接口。二者的差別在于它們如何改變接口。門面元素展現的是一個簡化的接口,它并不提供額外的選擇,而且有時為了方便完成某些常見任務它還會做出一些假定。而適配器則要把一個接口轉換為另一個接口,它并不會濾除某些能力,也不會簡化接口。如果客戶系統期待的API不可用,那就需要用到適配器。
適配器可被實現為不兼容的方法調用之間的一個代碼薄層。
示例:
假如你有一個對象還有一個以三個字符串為參數的函數:
var clientObject = { string1: "foo", string2: "bar", string3: "baz" }; function interfaceMethod(str1, str2, str3) { }
為了把clientObject作為參數傳遞給interfaceMethod,需要用到適配器。我們可以這樣創建一個:
function clientToInterfaceAdapter(o) { interfaceMethod(o.string1, o.string2, o.string3); } //現在就可以把整個對象傳給這個函數 clientToInterfaceAdapter(clientObject);
clientToInterfaceAdapter函數的作用就在于對interfaceMethod函數進行包裝,并把傳遞給它的參數轉換給后者需要的形式。
22.裝飾者模式裝飾者模式可用來透明地把對象包裝在具有同樣接口的另一對象中。這樣一來,你可以給一個方法添加一些行為,然后將方法調用傳遞給原始對象。相對于創建子類來說,使用裝飾者對象是一種更靈活的選擇。23.享元模式
享元模式最適合于解決因創建大量類似對象而累及的性能問題。這種模式在JavaScript中尤其有用,因為復雜的JavaScript代碼可能很快就會用光瀏覽器的所有可用內存。通過把大量獨立對象轉化為少量共享對象,可以降低運行Web應用程序所需的資源數量。
享元模式用于減少應用程序所需對象的數量。這是通過將對象的內部狀態劃分為內在數據和外在數據兩類而實現的。內在數據是指類的內部方法所需的信息,沒有這種數據的話類不能正常運轉。外在數據則是可以從類身上剝離并存儲在其外部的信息。我們可以將內在狀態相同的所有對象替換為同一個共享對象,這種方法可以把對象數量減少到不同內在狀態的數量。
24.實現享元模式的一般步驟將所有外在數據從目標剝離。具體做法是盡可能多地刪除該類的屬性,所刪除的應該是那種因實例而異的屬性。構造函數的參數也要這樣處理。這些參數應該被添加到該類的各個方法。這些外在數據現在不再保存在類的內部,而是由管理器提供給類的方法。經過這樣的處理后,目標類應該依然具有與之前一樣的功能。唯一的區別在于數據的來源發生了變化。
創建一個用來控制該類的實例化的工廠。這個工廠應該掌握該類所有已創建出來的獨一無二的實例。其具體做法之一是用一個對象字面量來保存每一個這類對象的引用,并以用來生成這些對象的參數的唯一性組合作為它們的索引。這樣一來,每次要求工廠提供一個對象時,它會先檢查那個對象字面量,看看以前是否請求過這個對象。如果是,那么只要返回那個現有對象的引用就行。否則它會創建一個新對象并將其引用保存在那個對象字面量中,然后返回這個對象。另一種做法稱為對象池,這種技術用數組來保存所創建的對象的引用。它適合于注重可用對象的數量而不是那些多帶帶配置的實例的場合。這種技術可用來將所實例化的對象的數目維持在最低值。工廠會處理根據內在數據創建對象的所有事宜。
創建一個用來保存外在數據的管理器。該管理器對象負責控制處理外在數據的種種事宜。在實施優化之前,要是需要一個目標類的實例,你會把所有數據傳給構造函數以創建其新實例。而現在要是需要一個實例,你會調用管理器的某個方法,把所有數據都提供給它。這個方法會分辨內在數據和外在數據。它把內在數據提供給工廠對象以創建一個對象(或者,如果已經存在這樣一個對象的話,則重用該對象)。外在數據則被保存在管理器內的一個數據結構中。管理器隨后會根據需要將這些數據提供給共享對象的方法,其效果就如同該類有許多實例一樣。
25.觀察者模式在事件驅動的環境中,比如瀏覽器這種持續尋求用戶關注的環境中,觀察者模式(又名發布者-訂閱者模式)是一種管理人與其任務之間的關系(確切的說,是對象及其行為和狀態之間的關系)的得力工具。
觀察者模式中存在兩個角色:觀察者和被觀察者。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79986.html
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:請記住,這些書中的一些可能不是最新的,但概念和基礎仍應適用。是最好的老師之一。的秘密由部分組成。在你完成這些書后,查看書籍和最好的本土書籍。 我看過三本,第1本,第二本,第四本。第一本買的的實體書,其他兩本看的是電子書。第一本是大名鼎鼎老道寫的,書很薄,但是非常經典。javascirpt忍者秘籍是jquery的作者寫的,也是非常經典。you dont kown js系列也是非常好。看了...
摘要:是文檔的一種表示結構。這些任務大部分都是基于它。這個實踐的重點是把你在前端練級攻略第部分中學到的一些東西和結合起來。一旦你進入框架部分,你將更好地理解并使用它們。到目前為止,你一直在使用進行操作。它是在前端系統像今天這樣復雜之前編寫的。 本文是 前端練級攻略 第二部分,第一部分請看下面: 前端練級攻略(第一部分) 在第二部分,我們將重點學習 JavaScript 作為一種獨立的語言,如...
摘要:首先,需要來理清一些基礎的計算機編程概念編程哲學與設計模式計算機編程理念源自于對現實抽象的哲學思考,面向對象編程是其一種思維方式,與它并駕齊驅的是另外兩種思路過程式和函數式編程。 JavaScript 中的原型機制一直以來都被眾多開發者(包括本人)低估甚至忽視了,這是因為絕大多數人沒有想要深刻理解這個機制的內涵,以及越來越多的開發者缺乏計算機編程相關的基礎知識。對于這樣的開發者來說 J...
摘要:函數式編程前端掘金引言面向對象編程一直以來都是中的主導范式。函數式編程是一種強調減少對程序外部狀態產生改變的方式。 JavaScript 函數式編程 - 前端 - 掘金引言 面向對象編程一直以來都是JavaScript中的主導范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數式編程越來越多得受到開發者的青睞。函數式編程是一種強調減少對程序外部狀態產生改變的方式。因此,...
摘要:前端入門的門檻相對較低,學習曲線是越來越陡峭,由淺入深,可以分為四個階段。第二階段高級程序設計有的書是用來成為經典的,比如犀牛書還有些書是用來超越經典的,顯然這本書就是。接下來可以看看教程,看看源代碼,嘗試著寫一寫這些效果。 前端入門的門檻相對較低,學習曲線是越來越陡峭,由淺入深,可以分為四個階段。 第一階段:《JavaScript DOM編程藝術》 看這本書之前,請先確認你對J...
閱讀 1583·2021-10-14 09:42
閱讀 3827·2021-09-07 09:59
閱讀 1309·2019-08-30 15:55
閱讀 583·2019-08-30 11:17
閱讀 3349·2019-08-29 16:06
閱讀 512·2019-08-29 14:06
閱讀 3139·2019-08-28 18:14
閱讀 3656·2019-08-26 13:55