探究JavaScript閉包

什麼是JavaScript閉包?

剛開始知道這個詞,就誤以爲是自動執行的匿名函數塊。
比如說+function(){}();
然而並不是,那麼請看下面的例子:

function init() {
  var name = "initial";
  function displayName() {//displayName() is the inner function, a closure
    alert(name);    
  }
  displayName();    
}
init();

displayname()是閉包嗎?函數內部訪問函數成員局部屬性的方法?

This is an example of lexical scoping: in JavaScript, the scope of a variable is defined by its location within the source code (it is apparent lexically) and nested functions have access to variables declared in their outer scope

這是一個詞法域的例子:Javascript中,變量的作用域由他所在的代碼區域(明顯的詞法上的),和可以訪問外部作用域的嵌套方法組成。

閉包Closure

再看這個例子:

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

What’s different — and interesting — is that the displayName() inner function was returned from the outer function before being executed.
不同並且有趣的地方是:內部方法displayName在函數外面被return出來,還是在執行之前。
那麼可以大膽的說:myFunc就是一個閉包。

A closure is a special kind of object that combines two things: a function, and the environment in which that function was created.
閉包就是一個包含了兩個東西的特殊對象:一個方法和創建這個方法的環境。
再看看一個例子 :

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

顯然add5和add10各自都有各自的環境,所持有的變量是不同的。
看一個閉包引起的錯誤,比較難理解透。

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();

如果有三個輸入框,那麼每個框點擊都會導致#help的內容變成Your age (you must be over 16)。
原因是:賦值給document.getElementById(item.id).onfocus
的function是個閉包函數:,這裏循環創建了三個閉包,但是他們共享了同一個外部作用域,也就是setupHelp,那麼自然循環結束的時候,onfocus 裏面就是指向了數據的最後一個元素。
這些話並不太容易讓人相信。

我debug跟蹤了一下:
循環走完的時候,onfocus function(){}裏面 item 的id已經是’age’,help是
‘Your age (you must be over 16)’

三個input對象都是onfocus綁定了同一個閉包(等同於同一個,環境裏變量和函數行爲都一樣)。

閉包性能

通常一個函數執行完畢之後它內部的局部變量就已經不能再訪問了。
而閉包需要維持他所被創建時的作用域環境,過分使用閉包對速度上的性能和內部的消耗是有影響的。沒必要的時候不要使用閉包。

本文引用自:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章