JavaScript函式模式詳解
JavaScript
設計模式的作用是提高程式碼的重用性,可讀性,使程式碼更容易的維護和擴充套件
在javascript
中,函式是一類物件,這表示他可以作為引數傳遞給其他函式;此外,函式還可以提供作用域。
建立函式的語法
命名函式表示式
//命名函式表示式 var add = function add(a,b){ return a+b; }; var foo = function bar() { console.log(foo === bar); }; foo();//true
可見,他們引用的是同一函式,但這隻在函式體內有效。
var foo = function bar() {}; console.log(foo === bar);//ReferenceError: bar is not defined
但是,你不能通過呼叫bar()
來呼叫該函式。
var foo = (function bar() { console.log(foo === bar); })();//false
函式表示式
//又名匿名函式 var add = function(a,b){ return a+b; };
為變數 add
賦的值是函式定義本身。這樣,add
就成了一個函式,可以在任何地方呼叫。
函式的宣告
function foo(){ //code here } //這裡可以不需要分號
在尾隨的分號中,函式表示式應總是使用分號,而函式的宣告中並不需要分號結尾。
宣告式函式與函式表示式的區別在於:在JS
的預編譯期,宣告式函式將會先被提取出來,然後才按順序執行js
程式碼:
console.log(f1);//[Function: f1] console.log(f2);//undefined,Javascript並非完全的按順序解釋執行,而是在解釋之前會對Javascript進行一次“預編譯”,在預編譯的過程中,會把定義式的函式優先執行 function f1(){ console.log("I am f1"); } var f2 = function (){ console.log("I am f2"); };
由於宣告函式都會在全域性作用域構造時候完成,因此宣告函式都是window
物件的屬性,這就說明為什麼我們不管在哪裡宣告函式,宣告函式最終都是屬於window
物件的原因了。
在javascript
語言裡任何匿名函式都是屬於window
物件。在定義匿名函式時候它會返回自己的記憶體地址,如果此時有個變數接收了這個記憶體地址,那麼匿名函式就能在程式裡被使用了,因為匿名函式也是在全域性執行環境構造時候定義和賦值,所以匿名函式的this
指向也是window
物件
var f2 = function (){ console.log("I am f2"); }; console.log(f2());//I am f2 (function(){ console.log(this === window);//true })();
函式宣告與表示式
函式的提升(hoisting)
函式宣告的行為並不等同於命名函式表示式,其區別在於提升(hoisting)行為,看下面例子:
<script type="text/javascript"> //全域性函式 function foo(){alert("global foo!");} function bar(){alert('global bar');} function hoist(){ console.log(typeof foo);//function console.log(typeof bar);//undefined foo();//local foo! bar();//TypeError: 'undefined' is not a function //變數foo以及實現者被提升 function foo(){ alert('local foo!'); } //僅變數bar被提升,函式實現部分 並未被提升 var bar = function(){ alert('local bar!'); }; } hoist(); </script>
對於所有變數,無論在函式體的何處進行宣告,都會在內部被提升到函式頂部。而對於函式通用適用,其原因在於函式只是分配給變數的物件。
提升
,顧名思義,就是把下面的東西提到上面。在JS
中,就是把定義在後面的東西(變數或函式)提升到前面中定義。 從上面的例子可以看出,在函式hoist
內部中的foo
和bar
移動到了頂部,從而覆蓋了全域性foo
和bar
函式。區域性函式bar
和foo
的區別在於,foo
被提升到了頂部且能正常執行,而bar()
的定義並沒有得到提升,僅有它的宣告被提升,所以,當執行bar()
的時候顯示結果為undefined
而不是作為函式來使用。
即時函式模式
函式也是物件,因此它們可以作為返回值。使用自執行函式的好處是直接宣告一個匿名函式,立即使用,省得定義一個用一次就不用的函式,而且免了命名衝突的問題,js
中沒有名稱空間的概念,因此很容易發生函式名字衝突,一旦命名衝突以最後宣告的為準。
模式一:
<script> (function () { var a = 1; return function () { alert(2); }; }()());//彈出2,第一個圓括號自執行,第二個圓括號執行內部匿名函式 </script>
模式二:自執行函式變數的指向
<script type="text/javascript"> var result = (function () { return 2; })();//這裡已執行了函式 alert(result);//result 指向了由自執行函式的返回值2;如果彈出result()會出錯 </script>
模式三:巢狀函式
<script type="text/javascript"> var result = (function () { return function () { return 2; }; })(); alert(result());//alert(result)的時候彈出function(){return 2} </script>
模式四:自執行函式把它的返回值賦給變數
var abc = (function () { var a = 1; return function () { return ++a; } })();//自執行函式把return後面的函式返回給變數 alert(abc());//如果是alert(abc)就會彈出return語句後面的程式碼;如果是abc(),則會執行return後面的函式
模式五:函式內部執行自身,遞迴
// 這是一個自執行的函式,函式內部執行自身,遞迴 function abc() { abc(); }
回撥模式
回撥函式:當你將一個函式write()
作為一個引數傳遞給另一個函式call()
時,那麼在某一時刻call()
可能會執行(或者呼叫)write()
。這種情況下,write()
就叫做回撥函式(callback function)
。
非同步事件監聽器
回撥模式有許多用途,比如,當附加一個事件監聽器到頁面上的一個元素時,實際上是提供了一個回撥函式的指標,該函式將會在事件發生時被呼叫。如:
document.addEventListener("click",console.log,false);
上面程式碼示例展示了文件單擊事件時以冒泡模式傳遞給回撥函式console.log()
的
javascript
特別適用於事件驅動程式設計,因為回撥模式支援程式以非同步方式執行。
超時
使用回撥模式的另一個例子是,當使用瀏覽器的window
物件所提供的超時方法:setTimeout()
和setInterval()
,如:
<script type="text/javascript"> var call = function(){ console.log("100ms will be asked…"); }; setTimeout(call, 100); </script>
庫中的回撥模式
當設計一個js
庫時,回撥函式將派上用場,一個庫的程式碼應儘可能地使用可複用的程式碼,而回撥可以幫助實現這種通用化。當我們設計一個龐大的js
庫時,事實上,使用者並不會需要其中的大部分功能,而我們可以專注於核心功能並提供“掛鉤形式”的回撥函式,這將使我們更容易地構建、擴充套件,以及自定義庫方法
Curry化
Curry化
技術是一種通過把多個引數填充到函式體中,實現將函式轉換為一個新的經過簡化的(使之接受的引數更少)函式的技術。———【精通JavaScript】
簡單來說,Curry化
就是一個轉換過程,即我們執行函式轉換的過程。如下例子:
<script type="text/javascript"> //curry化的add()函式 function add(x,y){ var oldx = x, oldy = y; if(typeof oldy == "undefined"){ return function(newy){ return oldx + newy; }; } //完全應用 return x+y; } //測試 typeof add(5);//輸出"function" add(3)(4);//7 //建立並儲存一個新函式 var add2000 = add(2000); add2000(10);//輸出2010 </script>
當第一次呼叫add()
時,它為返回的內部函式建立了一個閉包。該閉包將原始的x和y值儲存到私有變數oldx和oldy中。
現在,我們將可使用任意函式curry的通用方法,如:
<script type="text/javascript"> //普通函式 function add(x,y){ return x + y; } //將一個函式curry化以獲得一個新的函式 var newadd = test(add,5); newadd(4);//9 //另一種選擇,直接呼叫新函式 test(add,6)(7);//輸出13 </script>
何時使用Curry化
當發現正在呼叫同一個函式時,並且傳遞的引數絕大多數都是相同的,那麼該函式可能是用於Curry化的一個很好的候選引數
相關文章
- 詳解JavaScript函式模式JavaScript函式模式
- JavaScript函式柯里化詳解JavaScript函式
- javascript的replace()函式用法詳解JavaScript函式
- javascript的sort()函式用法詳解JavaScript函式
- JavaScript 節流函式 Throttle 詳解JavaScript函式
- JavaScript陣列操作函式方法詳解JavaScript陣列函式
- 詳解javascript立即執行函式表示式(IIFE)JavaScript函式
- JavaScript中bind、call、apply函式用法詳解JavaScriptAPP函式
- javascript函式全解JavaScript函式
- JavaScript 設計模式系列 – 自定義函式(惰性函式)JavaScript設計模式函式
- JavaScript 設計模式系列 - 自定義函式(惰性函式)JavaScript設計模式函式
- 詳解 JavaScript 建構函式和 "new" 操作符JavaScript函式
- JavaScript進階知識點——函式和物件詳解JavaScript函式物件
- 閉包詳解二:JavaScript中的高階函式JavaScript函式
- 尤拉函式詳解函式
- malloc函式詳解函式
- kill() 函式詳解函式
- ioctl()函式詳解函式
- gluLookAt 函式詳解函式
- fopencookie函式詳解Cookie函式
- Javascript設計模式詳解JavaScript設計模式
- Javascript 嚴格模式詳解JavaScript模式
- 詳解Java函式式介面Java函式
- Socket send函式和recv函式詳解函式
- 建構函式詳解函式
- 函式引數詳解函式
- mysql常用函式詳解MySql函式
- 箭頭函式詳解函式
- fcntl函式用法詳解函式
- eval()函式用法詳解函式
- Oracle 聚合函式詳解Oracle函式
- wait()函式詳解AI函式
- oracle TRANSLATE函式詳解Oracle函式
- select 函式詳解函式
- xslt函式詳解函式
- Oracle 分析函式詳解Oracle函式
- PHP函式處理函式例項詳解PHP函式
- JavaScript系列--JavaScript陣列高階函式reduce()方法詳解及奇淫技巧JavaScript陣列函式