javascript閉包的我的理解

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

理解閉包,首先必須理解變量做用域和做用域鏈。在JavaScript中,JavaScript有兩種做用域:全局做用域和函數做用域。函數內部能夠直接讀取全局變量。函數子做用域能夠訪問父做用域的變量 。前端

var n = 1;

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

上面代碼中,函數f1能夠直接訪問全局變量n, 可是在函數外部沒法直接讀取函數內部的變量,java

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就是閉包,。閉包是指有權訪問另外一個函數做用域中的變量的函數。在這裏要注意的一點:因爲一般閉包都是匿名函數,因此給人形成錯覺,只有匿名函數才能做爲閉包,其實,命名、匿名函數都是能夠做爲閉包函數的,只不過一般閉包都是做爲返回值,自身不多被調用,因此也就沒了命名的必要,而命名函數基本上都是要調用的。bash

另外看了網上一些文章,是經過做用域的提高來解釋的, 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的垃圾回收機制引發的,目前已經修復這個問題,

相關文章
相關標籤/搜索