JavaScript 匿名立即自執行函式

admin發表於2019-02-02

匿名自執行函式在當前應用非常廣泛,通過它可以避免很多程式設計中常見問題。

下面將通過程式碼例項對其進行詳細介紹,文字主要涵蓋如下幾個方面內容:

(1).什麼是匿名立即自執行函式。

(2).匿名函式的主要應用方式。

一.匿名立即自執行函式:

匿名立即自執行函式是一種函式應用方式,可以使匿名函式建立之後立即執行。

它並不是ES中定義的一個標準術語,只是對此種應用方式的一種貼切的描述。

建立函式的方式有兩種,一種是函式宣告方式,一種是函式表示式方式。

本文對於函式的建立不做過多介紹,具體參閱JavaScript function 函式一章節。

函式宣告方式建立的函式必定是具名函式,表示式方式建立的函式可以是匿名函式,也可以是具名函式。

程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼
// 具名函式
let funcJ = function f() {}
// 匿名函式
let funcN = function() {}

不要想當然認為funcN是函式的名稱,只是一個變數而已,變數值是一個匿名函式。

既然要執行,自然要呼叫匿名函式,程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
(function(){
  console.log("螞蟻部落");
})()

上面程式碼會立即列印出字串"螞蟻部落",但是上述方式並推薦使用,程式碼修改如下:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
(function(){
  console.log("螞蟻部落");
}())

呼叫匿名函式的小括號應該在小括號之內。

雖然第一種寫法在語法上完全沒有問題,但是第二種寫法看起來更像一個整體。

再額外介紹一個知識點,標準規定,凡是function關鍵字出現在程式碼的行首,那麼程式碼畢竟被解讀為語句。

表示式返回一個值,但是語句並不能,所以如下方式呼叫函式是錯誤的:

[JavaScript] 純文字檢視 複製程式碼
function func(){}()

但是我們可以先轉換為一個表示式,然後再呼叫,程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼
(function func(){})()

將函式放入小括號後,形成一個表示式,表示式能夠返回一個值,也就是函式物件。

二.匿名函式主要應用方式:

(1).避免作用域命名汙染:

函式可以生成一個函式作用域,全域性作用域變數和此函式作用域中的同名變數不會產生汙染。

這個一點非常容易理解,看如下程式碼例項:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
let webName="百度";
(function(){
    let webName="螞蟻部落";
    console.log(webName);
}())
console.log(webName);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201902/02/234117zfsmpd098m64spc7.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

再來看一個常見的應用,比如頁面要引入兩個檔案a.js與b.js,這兩個檔案中,都宣告瞭變數webName。

那麼同時引入的時候,就可能會產生衝突導致問題,比如後面的變數覆蓋前面的,只要將各自檔案的js程式碼放入匿名自執行函式即可解決此問題,程式碼如下:

[JavaScript] 純文字檢視 複製程式碼
// a.js
(function() {
  var webName = "螞蟻部落";
})();
// b.js
(function() {
  var webName = "百度";
})();

(2).提升效能:

這一點可能很多朋友不是太理解,下面進行一下演示。

[JavaScript] 純文字檢視 複製程式碼
(function(){
    // code
}(window))

上述程式碼為匿名函式傳遞引數window,如果匿名函式內有對window物件的引用,在一定程度上可以提升效能。

因為不用越過函式作用域向上級作用域查詢window物件,減少了對作用域的查詢操作。

(3).儲存閉包狀態:

首先看一段程式碼例項,如果不注意可能出現意想不到的問題,尤其會給新手帶來不小的困擾。

[HTML] 純文字檢視 複製程式碼執行程式碼
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
ul li{
  width:300px;
  list-style-type:none;
  font-size:12px;
  line-height:30px;
  height:30px;
  cursor:pointer;
}
ul li span{
  float:right
}
</style>
<script>
window.onload=function(){
  var obox=document.getElementById("box");
  var lis=obox.getElementsByTagName("li");
  var odiv=document.getElementById("show");
  for(var index=0;index<lis.length;index++){
    lis[index].onclick= function(){
      odiv.innerHTML=index;
    } 
  }
}
</script>
</head> 
<body> 
<ul id="box">
  <li>螞蟻部落一</li>
  <li>螞蟻部落二</li>
  <li>螞蟻部落三</li>
  <li>螞蟻部落四</li>
  <li>螞蟻部落五</li>
</ul>
<div id="show"></div>
</body> 
</html>

上述程式碼的初衷是,點選li元素可以將對應元素的索引位置寫入div中。

但是結果卻並非如此,點選任何一個li元素,在div中顯示的數字都是5,好像邏輯上沒有任何問題。

原因是這樣的,當通過for迴圈為li元素註冊事件處理函式,index的值也隨之增加,當for迴圈結束之後,index的值到達5,點選li元素是for迴圈結束之後的事情,所以index值已經變成了5,本質原因是index的作用域是load事件處理函式。下面通過匿名函式修改如下:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
ul li{
  width:300px;
  list-style-type:none;
  font-size:12px;
  line-height:30px;
  height:30px;
  cursor:pointer;
}
ul li span{
  float:right
}
</style>
<script>
window.onload=function(){
  var obox=document.getElementById("box");
  var lis=obox.getElementsByTagName("li");
  var odiv=document.getElementById("show");
  for(var index=0;index<lis.length;index++){
    lis[index].onclick=(function(index){
      return function(){
        odiv.innerHTML=index;
      } 
    })(index)
  }
}
</script>
</head> 
<body> 
<ul id="box">
  <li>螞蟻部落一</li>
  <li>螞蟻部落二</li>
  <li>螞蟻部落三</li>
  <li>螞蟻部落四</li>
  <li>螞蟻部落五</li>
</ul>
<div id="show"></div>
</body> 
</html>

上面程式碼將index作為匿名函式的引數,這樣index的作用域被封閉在獨立的匿名函式中,相互不會影響。ES2015提供了塊級作用域,現在看來上述方式就有點多餘(不考慮瀏覽器相容性問題的話),程式碼例項如下:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
ul li{
  width:300px;
  list-style-type:none;
  font-size:12px;
  line-height:30px;
  height:30px;
  cursor:pointer;
}
ul li span{
  float:right
}
</style>
<script>
window.onload=function(){
  var obox=document.getElementById("box");
  var lis=obox.getElementsByTagName("li");
  var odiv=document.getElementById("show");
  for(let index=0;index<lis.length;index++){
    lis[index].onclick= function(){
      odiv.innerHTML=index;
    } 
  }
}
</script>
</head> 
<body> 
<ul id="box">
  <li>螞蟻部落一</li>
  <li>螞蟻部落二</li>
  <li>螞蟻部落三</li>
  <li>螞蟻部落四</li>
  <li>螞蟻部落五</li>
</ul>
<div id="show"></div>
</body> 
</html>

只要將var修改成let即可,那麼{}就可以形成一個塊級作用域,var宣告變數不具備此功能。

關於let與塊級作用域可以參閱如下兩篇文章:

(1).JavaScript let 命令一章節。

(2).JavaScript 塊級作用域一章節。

相關文章