15

私はプログラミングが初めてで、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 コンソールの画面に変数を表示するだけです。

著者は、これはレキシカルスコープが関数の統合を可能にする方法を示す例であると言います。 ここの章

私が理解していないaddTwoのはaddFive、変数であると思われる and が関数makeAddFunctionandにパラメーターを送信する方法、より具体的には、変数が送信しているパラメーターが parameter であることをadd関数がどのように認識するかです。addnumber

助けてくれてありがとう!

4

6 に答える 6

9

JavaScript では、関数は第一級のオブジェクトです。つまり、関数を渡したり、変数に割り当てたりすることができます。変数 addTwo と addFive には関数が含まれています。これらの関数は、「ファクトリー」関数 makeAddFunction によって生成されます。

addTwo および addFive に含まれる関数には、作成時に存在していたスコープが含まれています。つまり、たとえば addTwo が作成されたとき、パラメータ「amount」は 2 でした。つまり、addTwo は本質的に次の関数です。

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

誰かが addTwo() を呼び出しても、makeAddFunction には何も返されません。MakeAddFunction は既に実行され、終了しています。ただし、makeAddFunction 内で作成されたスコープ ("amount" が 2 に等しい) は、addTwo 関数内に残ります。

于 2010-11-07T01:12:16.103 に答える
8

addTwoaddFiveは変数ですが、関数変数です。見てくださいtypeof(addTwo)- それは関数です。あなたがこれをした場合のようです:

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

これと同じです:

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

(編集: Šime が指摘したように、それらはまったく同じではありません。2 つの違いの説明については、こちらを参照してください。)

それを理解すれば、この例はうまくいけば意味をなすでしょう。匿名関数を宣言してすぐに呼び出す、このような奇妙なこともできます。

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();

これはばかげていますが、関数を作成する関数を説明するのに役立ちます。もちろん、そのような関数は通常、毎回異なる関数を作成できるように引数を受け入れますが、そこまでです。

于 2010-11-07T01:09:09.757 に答える
6

その例を理解するための鍵は、関数が他の関数を返すことができることを理解することだと思います (他の変数と同じように)。そのコードを文書化することは、その概念を理解するのに大いに役立ちます。

/** 
 * 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));
于 2010-11-07T02:36:48.347 に答える
3

Re: 私が理解できないのは、おそらく変数である addTwo と addFive が関数 makeAddFunction にパラメーターを送信する方法です。

addTwo と addFive は変数です。しかし、それらの値は単純なスカラー (数値、文字列など) ではありません。むしろ、それらの値は関数です。それらの値は関数であるため、それらの関数を呼び出すことは問題ありません。例えば、addTwo(1)

Re: より具体的には、関数 add は、変数が送信しているパラメーターがパラメーター番号であることをどのように認識しますか?

関数 add は、その最初のパラメーター番号を呼び出しています。そのため、後で addOne などの変数を介して関数を呼び出すと、addOne に指定された最初のパラメーターが数値になります。

ps 「自分自身、これはかなりトリッキーだ!」と考えている場合は、その通りです。それが、この例の全体的な目的であり、何かトリッキーなことを示すことです。この手法を使用する頻度は、まったく使用しない場合と、時々使用する場合があります。

于 2010-11-07T01:12:28.260 に答える
0

このようなコードを考える最良の方法は、値を置き換えて頭の中で介入することです。

// 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);
于 2010-11-07T09:24:48.967 に答える
0

いつものように、JavaScriptクロージャに関するジブリングノートは次のとおりです。スコープ、実行コンテキスト、変数/プロパティの解決などについて説明します。

JavaScriptクロージャは字句ですが、実行コンテキスト(プロパティを含む場合があります)はバインドされ(PythonまたはRubyを考えてください)、「自由変数」(C#またはScalaの場合のように)だけではありません。これが、新しい変数を新しい関数スコープにのみ導入できる理由です。(最新のMozilla実装ではlet)が導入されています。

于 2010-11-07T09:29:25.543 に答える