javascript閉包的個人理解

Jc Bound發表於2019-04-13

閉包一詞在javascript中非常有名,對於前端來說理解它至關重要,很多高階應用都要依靠閉包實現。掌握了它,對我們的js寫程式碼水平會有很大幫助,因此成為許多公司前端的面試題之一,用來測試應聘者的js水平,可見其重要性,所以作為一個前端,理解閉包是必須的!沒有任何理由說不懂!

理解閉包,首先必須理解變數作用域和作用域鏈。在JavaScript中,JavaScript有兩種作用域:全域性作用域和函式作用域。函式內部可以直接讀取全域性變數。函式子作用域可以訪問父作用域的變數 。

var n = 1;

function f1() {
  console.log(n);
}
f1() // 1
複製程式碼

上面程式碼中,函式f1可以直接訪問全域性變數n, 但是在函式外部無法直接讀取函式內部的變數,

function f1() {
  var n = 1;
}

console.log(n)
//Uncaught ReferenceError: n is not defined  提示n沒有定義
複製程式碼

如果出於種種原因,需要得到函式內的區域性變數。正常情況下,這是辦不到的,只有通過變通方法才能實現。那就是在函式的內部,再定義一個函式。

function f1() {
  var n = 1;
  function f2() {
  console.log(n); // 1
  }
}
複製程式碼

上面程式碼中,函式f2就在函式f1內部,這時f1內部的所有區域性變數,對f2都是可見的。但是反過來就不行,f2內部的區域性變數,對f1就是不可見的。子物件會順著作用域鏈找父物件的變數, 如果想要函式外部訪問函式內部的變數,那麼可以使用return把f2作為返回值,不就可以在發外部訪問到內部的變數了嗎?

function f1() {
  var n = 1;
  function f2() {
  console.log(n); // 1
  }
  return f2
}
var result = f1();
result(); // 1
複製程式碼

上面程式碼中,函式f1的返回值就是函式f2,由於f2可以讀取f1的內部變數,所以就可以在外部獲得f1的內部變數了。 f2就是閉包,。閉包是指有權訪問另一個函式作用域中的變數的函式。在這裡要注意的一點:由於通常閉包都是匿名函式,所以給人造成錯覺,只有匿名函式才能作為閉包,其實,命名、匿名函式都是可以作為閉包函式的,只不過通常閉包都是作為返回值,自身很少被呼叫,所以也就沒了命名的必要,而命名函式基本上都是要呼叫的。

另外看了網上一些文章,是通過作用域的提升來解釋的, f1是一級作用域,f2是二級作用域,f1返回f2後,把f2的作用域提升到一級作用域,就可以在外部被全域性呼叫了,這種說法通俗易懂,很好理解,但是

閉包的優點

1.函式內部的定義的變數可以儲存在記憶體中。一般函式執行後,函式內部的變數就會被銷燬,但是由於閉包的存在,該函式內部的變數就不會被銷燬回收,如上述程式碼中,f1呼叫後,閉包f2會呼叫變數n,使得n始終存在記憶體中。 2.避免全域性變數的汙染,全域性變數是可重用但是汙染全域性,區域性變數不會汙染全域性但是不可重用。而閉包就是二者優點的結合, 3.是封裝物件的私有屬性和私有方法。舉例如下:

function Person(name) {
  var _age;
  function setAge(n) {
    _age = n;
  }
  function getAge() {
    return _age;
  }

  return {
    name: name,
    getAge: getAge,
    setAge: setAge
  };
}

var p1 = Person('張三');
p1.setAge(25);
p1.getAge() // 25
該例子來源與阮一峰的部落格函式閉包內容,
複製程式碼

上面程式碼中,函式Person的內部變數_age,通過閉包getAge和setAge,變成了返回物件p1的私有變數。

閉包的缺點

閉包會保留外層函式的內部變數,所以記憶體消耗很大。因此不能濫用閉包,否則會造成網頁的效能問題。

備註:之前閉包在iE瀏覽器上存在記憶體溢位的問題,不過這是由於ie的垃圾回收機制引起的,目前已經修復這個問題,

相關文章