JavaScript 函數模式詳解及樣本_基礎知識

來源:互聯網
上載者:User

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化的一個很好的候選參數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.