JavaScript 初步閉包理解

JavaScript核心-閉包

閉包(Closure)

關於閉包,真的是看了忘忘了看,相信這次應該理解了~

變量的作用域

ES中規定的JavaScript的變量作用域有兩種:全部變量和局部變量(ES中引入塊級作用域)

javascript有兩種特殊的屬性

函數內部可以直接讀取全局變量

var n=999;
function f(){
  alert(n);
}
f(); // 

函數外部不能夠讀取局部變量

function f(){
  var n=999;
}
alert(n); // error

注意 函數內部定義變量使用var,否則你定義的就是一個全局變量

function f(){
  n=999;
}
f();
alert(n); // 

如何從外部讀取局部變量

上邊講到,正常情況下,外部無法讀取局部變量,想要讀取局部變量怎麼辦?
就是在函數內部在定義一個函數

function f(){
  var n=999;
  function f(){
    alert(n); // 
  }
}

在上面的代碼中,函數f就被包括在函數f內部,這時f內部的所有局部變量,對f都是可見的。但是反過來就不行,f內部的局部變量,對f就是不可見的。這就是Javascript語言特有的”鏈式作用域”結構(chain scope),子對象會一級一級地向上尋找所有父對象的變量。所以,父對象的所有變量,對子對象都是可見的,反之則不成立.

f可以讀取f中的變量,將f作爲返回值,那麼f的外部我們就可以讀取內部變量了

function f(){
  var n=999;
  function f(){
    alert(n);
  }
  return f;
}
var result=f();
result(); // 

閉包的概念

上述代碼中f就是閉包,下面看看抽象的閉包~

閉包:閉包是一個代碼塊(在ECMAScript是一個函數)和以靜態方式/詞法方式進行存儲的所有父作用域的一個集合體。所以,通過這些存儲的作用域,函數可以很容易的找到自由變量。

看看容易理解的閉包概念

由於在Javascript語言中,只有函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解成”定義在一個函數內部的函數”。
所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋樑。

閉包的用途

可以讀取函數內部的變量
就是讓這些變量的值始終保持在內存中

function f(){
  var n=999;
  nAdd=function(){n+=}
  function f(){
    alert(n);
  }
  return f;
}
var result=f();
result(); // 
nAdd();#不要懷疑在外部爲什麼還可以調用,nAdd()是掛載在window下的
result(); // 

result其實就是閉包f函數,一共運行兩次,一次二次。這就說明f局部變量一直在內存當中,
並沒有在被調用之後被自動的清楚。

爲什麼會這樣呢?原因就在於f是f的父函數,而f被賦給了一個全局變量,這導致f始終在內存中,而f的存在依賴於f,因此f也始終在內存中,不會在調用結束後,被垃圾回收機制(garbage collection)回收。

注意nAdd的值是一個匿名函數(anonymous function),而這個匿名函數本身也是一個閉包,所以nAdd相當於是一個setter,可以在函數外部對函數內部的局部變量進行操作。

使用閉包的注意點

由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
思考題

題1

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    return function(){
      return this.name;
    };
  }
};
alert(object.getNameFunc()());

題2

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    var that = this;
    return function(){
      return that.name;
    };
  }
};
alert(object.getNameFunc()());

原文地址:
https://yuanyuanshen.github.io/2016/12/08/%E8%BF%99%E6%A0%B7%E8%AE%B2%E9%97%AD%E5%8C%85%EF%BC%8C%E4%BD%A0%E7%BB%88%E7%94%9F%E9%9A%BE%E5%BF%98/

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