簡體   English   中英

JavaScript示例問題:詞法范圍/閉包 - Eloquent Javascript

[英]JavaScript example question: lexical scoping/closure - Eloquent Javascript

所以我是編程的新手,我正在嘗試用Eloquent Javascript這本書來學習JS。

到目前為止一直很好,直到我用以下代碼到達一個例子

function makeAddFunction(amount) {
  function add(number) {
    return number + amount;
  }
  return add;
}

var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));

注意:show就像alert,只顯示教程集成的JS控制台屏幕上的變量。

作者說這是一個展示詞匯范圍如何允許合成函數的例子。 這里的章節

我不明白的是addTwoaddFive (可能是變量)如何將參數發送到函數makeAddFunctionadd ,更具體地說,函數add如何知道變量發送的參數是參數number

謝謝你的幫助!

在javascript中,函數是第一類對象,也就是說,它可以傳遞,賦值給變量等。變量addTwo和addFive包含函數。 這些函數由“factory”函數makeAddFunction生成。

addTwo和addFive包含的函數包含它們創建時存在的范圍。 也就是說,例如,當創建addTwo時,參數“amount”為2.所以addTwo實質上是以下函數:

function addTwo(number) {
   return number + 2;
}

當有人調用addTwo()時,它不會將任何內容傳遞給makeAddFunction。 MakeAddFunction已經運行並完成。 但是,makeAddFunction(其中“amount”等於2)中創建的作用域在addTwo函數中存在。

addTwoaddFive是變量 - 但它們是函數變量。 看看typeof(addTwo) - 它是一個函數。 這就像你這樣做:

var addTwo = function(x) { return x + 2; };

它與此相同:

function addTwo(x) { return x + 2; }

(編輯:正如Šime所指出的那樣,它們並不完全相同。請看這里解釋兩者之間的區別。)

一旦你理解了這個例子,希望這個例子有意義。 你甚至可以做這樣奇怪的事情,聲明一個匿名函數並立即調用它:

var seven = function(x) { return x + 2; }(5);

從字面上看,在物理機器代碼級別,完全相同: 這相當於與此問題相關的所有目的:

function addTwo(x) { return x + 2; }
var seven = addTwo(5);

編輯:

或許對此不那么令人困惑的“前傳”如下:

function makeTheAddTwoFunction()
{
    return function(x) { return x + 2; }
}

var addTwo = makeTheAddTwoFunction();

這很愚蠢,但用於說明函數的功能。 當然,這種函數通常會接受參數,這樣它每次都可以創建不同的函數,但是你去了。

我認為理解這個例子的關鍵是理解函數可以返回其他函數(就像任何其他變量一樣)。 記錄該代碼將有助於理解該概念。

/** 
 * Creates an adder function
 * @param {number} amount Amount to add
 * @return {function}  Method that adds 'amount' to its argument. 
 * See the documentation of add for its signature
 */
function makeAddFunction(amount) {      
  /**
   * Everytime makeAddFunction is called, a new instance of add  is created
   * (and returned) that holds on to its copy of 'amount' (through the closure)
   * @param {number} number value to add to 'amount'
   * @return {number} 'amount' + 'number'
   */
  return function add(number) {
    return number + amount;
  };
}

// addTwo now is a reference to a function that when called
// adds 2 to whatever is passed in
var addTwo = makeAddFunction(2);
// addFive Adds 5 to its argument
var addFive = makeAddFunction(5);
// addTwo(1) = 3, addFive(1) = 6, therefore, output is 9
show(addTwo(1) + addFive(1));

Re:我不明白的是addTwo和addFive是多少,它們應該是函數makeAddFunction?

addTwo和addFive是變量。 但它們的值不是簡單的標量(數字,字符串等)。 相反,他們的價值觀是功能。 由於它們的值是函數,因此可以調用這些函數。 例如, addTwo(1)

Re:更具體地說,函數add如何知道變量發送的參數是參數號?

函數add調用它的第一個參數號。 所以稍后,當您通過變量(例如addOne)調用函數時,addOne的第一個參數將變為number。

ps如果你在想自己,“自我,這非常棘手!” 那么你是對的 - 這就是這個例子的全部目的,展示一些棘手的東西。 你經常使用這種技術的頻率可能從不到每一次都有所不同。

想到這樣一段代碼的最好方法是在你的腦海里替換價值觀和插圖

// when this one is invoked
var addTwo = makeAddFunction(2);

// makeAddFunction
// becomes something like
function makeAddFunction(2) {
  function add(number) {
    return number + 2;
  }
  // return a function, that adds
  // 2 to every number it gets
  return add;
}

// therefore this function call
// will add 2 to 1 and return 3
addTwo(1);

與往常一樣,這里是關於JavaScript閉包Jibbring筆記 它討論了范圍,執行上下文,變量/屬性解析等...

雖然JavaScript閉包是詞法,但執行上下文 (可能包含屬性)受到約束(比如Python或Ruby),而不僅僅是“自由變量”(就像C#或Scala一樣)。 這就是為什么只能在新的函數范圍中引入變量的原因。 (現代Mozilla實現介紹let )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM