技術(shù)頻道導(dǎo)航
HTML/CSS
.NET技術(shù)
IIS技術(shù)
PHP技術(shù)
Js/JQuery
Photoshop
Fireworks
服務(wù)器技術(shù)
操作系統(tǒng)
網(wǎng)站運(yùn)營(yíng)

贊助商

分類目錄

贊助商

最新文章

搜索

從基本術(shù)語(yǔ)開(kāi)始,4步完成對(duì)JavaScript閉包的理解

作者:admin    時(shí)間:2022-6-7 14:36:4    瀏覽:

JavaScript閉包在實(shí)際開(kāi)發(fā)中使用并不多,但它卻是面試官必問(wèn)的問(wèn)題,因此,作為一個(gè)前端開(kāi)發(fā)人員,閉包是躲不開(kāi)的一個(gè)技術(shù)。在本文中,我將從基本術(shù)語(yǔ)開(kāi)始:作用域和詞法作用域,然后,在掌握了基礎(chǔ)知識(shí)之后,最終理解閉包。

在開(kāi)始之前,我建議你不要跳過(guò)范圍和詞法范圍這兩部分,這些概念對(duì)閉包至關(guān)重要,如果你把它們搞好,閉包的概念就變得不言而喻了。

  1. 適用范圍
  2. 范圍嵌套
  3. 詞法范圍
  4. 閉包

一、適用范圍

當(dāng)你定義一個(gè)變量時(shí),你希望它存在于某些邊界內(nèi)。例如,result變量作為內(nèi)部細(xì)節(jié)存在于calculate()函數(shù)中是有意義的。在calculate()之外,該result變量是無(wú)用的。

變量的可訪問(wèn)性由范圍管理,你可以自由訪問(wèn)在其范圍內(nèi)定義的變量。但在該范圍之外,該變量是不可訪問(wèn)的。

在 JavaScript 中,作用域由函數(shù)或代碼塊創(chuàng)建。

讓我們看看范圍如何影響count變量的可用性。此變量屬于由foo()創(chuàng)建的范圍:

function foo() {
  // 函數(shù)范圍
  let count = 0;
  console.log(count); // logs 0
}
foo();
console.log(count); // ReferenceError: count is not defined

demodownload

countfoo()范圍內(nèi)可以自由訪問(wèn)。

但是,超出foo()范圍,count是無(wú)法訪問(wèn)的。如果你嘗試從外部訪問(wèn)count,JavaScript 會(huì)拋出ReferenceError: count is not defined。

如果你在函數(shù)或代碼塊內(nèi)定義了變量,則只能在該函數(shù)或代碼塊內(nèi)使用此變量。上面的示例演示了這種行為。

 

現(xiàn)在,讓我們看一個(gè)通用的公式:

范圍是一種空間策略,用于規(guī)則變量的可訪問(wèn)性。

一個(gè)直接的屬性出現(xiàn)了——作用域隔離了變量。這很好,因?yàn)椴煌淖饔糜蚩梢杂型淖兞俊?/p>

你可以在不同的范圍內(nèi)重用公共變量名稱(count、index、current、value等)而不會(huì)發(fā)生沖突。

foo()bar()函數(shù)范圍有它們自己但同名的變量count: 

function foo() {
  // "foo" 函數(shù)范圍
  let count = 0;
  console.log(count); // logs 0
}
function bar() {
  // "bar" 函數(shù)范圍
  let count = 1;
  console.log(count); // logs 1
}
foo();
bar();

demodownload

來(lái)自foo()bar()函數(shù)范圍的變量count不會(huì)發(fā)生沖突。

2、范圍嵌套

讓我們更多地使用范圍,并將一個(gè)范圍嵌套到另一個(gè)范圍中。例如,函數(shù)innerFunc()嵌套在外部函數(shù)outerFunc()中。

兩個(gè)函數(shù)作用域如何相互交互?我可以從innerFunc()范圍內(nèi)訪問(wèn)outerFunc()范圍的變量outerVar嗎?

讓我們?cè)谑纠袊L試一下:

function outerFunc() {
  // 外部范圍
  let outerVar = 'I am outside!';
  function innerFunc() {
    // 內(nèi)部范圍
    console.log(outerVar); // => logs "I am outside!"
  }
  innerFunc();
}
outerFunc();

demodownload

結(jié)果是,outerVar變量可以在innerFunc()范圍內(nèi)訪問(wèn)。外部范圍的變量可以在內(nèi)部范圍內(nèi)訪問(wèn)。

現(xiàn)在你知道了兩點(diǎn):

  • 范圍可以嵌套
  • 外部范圍的變量可以在內(nèi)部范圍內(nèi)訪問(wèn)

3、詞法范圍

JavaScript 是如何理解innerFunc()內(nèi)部的變量outerVar對(duì)應(yīng)outerFunc()的變量outerVar的?

JavaScript 實(shí)現(xiàn)了一種名為詞法作用域(或靜態(tài)作用域)的作用域機(jī)制。詞法作用域意味著變量的可訪問(wèn)性由變量在嵌套作用域內(nèi)的位置決定。

更簡(jiǎn)單,詞法作用域意味著在內(nèi)部作用域內(nèi)可以訪問(wèn)外部作用域的變量。

它被稱為詞法(或靜態(tài)),因?yàn)橐妫ㄔ谠~法分析時(shí))僅通過(guò)查看 JavaScript 源代碼而不執(zhí)行它來(lái)確定范圍的嵌套。

詞法作用域的思想是:

詞法范圍由靜態(tài)確定的外部范圍組成。

例如:

const myGlobal = 0;
function func() {
  const myVar = 1;
  console.log(myGlobal); // logs "0"
  function innerOfFunc() {
    const myInnerVar = 2;
    console.log(myVar, myGlobal); // logs "1 0"
    function innerOfInnerOfFunc() {
      console.log(myInnerVar, myVar, myGlobal); // logs "2 1 0"
    }
    innerOfInnerOfFunc();
  }
  innerOfFunc();
}
func();

demodownload

innerOfInnerOfFunc()的詞法范圍由innerOfFunc()、func()和全局范圍(最外層范圍)組成的。在innerOfInnerOfFunc()里面,你可以訪問(wèn)詞法范圍變量myInnerVarmyVar 和 myGlobal。

innerOfFunc()的詞法范圍由func()和全局范圍組成。你可以在innerOfFunc()里訪問(wèn)詞法范圍變量myVarmyGlobal

最后,func()的詞法作用域僅由全局作用域組成。你可以在func()里訪問(wèn)詞法范圍變量myGlobal。

4、閉包

通過(guò)前面的介紹,我們知道了詞法范圍允許靜態(tài)訪問(wèn)外部范圍的變量。距離閉包僅一步之遙!

讓我們?cè)倏匆幌?code>outerFunc()和innerFunc()例子:

function outerFunc() {
  let outerVar = 'I am outside!';
  function innerFunc() {
    console.log(outerVar); // => logs "I am outside!"
  }
  innerFunc();
}
outerFunc();

demodownload

innerFunc()作用域內(nèi),從詞法作用域訪問(wèn)outerVar變量,這個(gè)我們已經(jīng)知道了。

請(qǐng)注意,innerFunc()調(diào)用發(fā)生在其詞法范圍(outerFunc()的范圍)內(nèi)。

讓我們做一個(gè)改變:innerFunc()在其詞法范圍之外被調(diào)用:在一個(gè)函數(shù)exec()中。innerFunc()還能訪問(wèn)outerVar嗎?

讓我們對(duì)代碼片段進(jìn)行調(diào)整:

function outerFunc() {
  let outerVar = 'I am outside!';
  function innerFunc() {
    console.log(outerVar); // => logs "I am outside!"
  }
  return innerFunc;
}
function exec() {
  const myInnerFunc = outerFunc();
  myInnerFunc();
}
exec();

demodownload

現(xiàn)在innerFunc()在其詞法范圍之外執(zhí)行,但在exec()函數(shù)范圍內(nèi)。重要的是:

innerFunc()仍然可以從其詞法范圍里訪問(wèn)outerVar,甚至在其詞法范圍之外執(zhí)行。

換句話說(shuō),innerFunc() 從它的詞法范圍中關(guān)閉了(也就是捕獲、記?。?code>outerVar變量。

換句話說(shuō),innerFunc()是一個(gè)閉包,因?yàn)樗鼜钠湓~法范圍內(nèi)關(guān)閉了outerVar變量。 

 

現(xiàn)在,你應(yīng)該了解什么是閉包了:

閉包是一個(gè)訪問(wèn)其詞法范圍的函數(shù),甚至在其詞法范圍之外執(zhí)行。

更簡(jiǎn)單地說(shuō),閉包是一個(gè)函數(shù),它從定義它的地方記住變量,而不管它后來(lái)在哪里執(zhí)行。 

識(shí)別閉包的經(jīng)驗(yàn)法則:如果在函數(shù)內(nèi)部看到一個(gè)外來(lái)變量(未在該函數(shù)內(nèi)部定義),則該函數(shù)很可能是一個(gè)閉包,因?yàn)樵撏鈦?lái)變量已被捕獲。

在前面的代碼片段中,outerVarinnerFunc()閉包內(nèi)的一個(gè)外來(lái)變量,它從outerFunc()的作用域捕獲。

總結(jié)

本文通過(guò)4個(gè)方面,從基本術(shù)語(yǔ)開(kāi)始,由淺入深逐步介紹了什么是閉包。通過(guò)本文的學(xué)習(xí),你應(yīng)該知道了閉包的基本概念和其固有特點(diǎn)。

相關(guān)文章

標(biāo)簽: 閉包  
x
  • 站長(zhǎng)推薦
/* 左側(cè)顯示文章內(nèi)容目錄 */