2

Functional JavaScriptを読み始めたところ、すぐに理解できない関数が紹介されました。

function splat(fun) {
  return function(array) {
    return fun.apply(null, array);
  };
}

var addArrayElements = splat(function(x, y) { return x + y });

addArrayElements([1, 2]);
//=> 3

どのように機能しますかsplat(function(x, y) { return x + y })。array[1,2]で呼び出されますが、 への呼び出し内の無名関数はsplat、1 つの配列ではなく 2 つのパラメーターを取るようです。

console.log(fun)このコードの 2 行目に置くと、それfunが anonymous の全体であることがわかりfunction(x, y) { return x + y }ます。console.log(array)afterreturn function(array) {は、配列が であることを示してい[1, 2]ます。じゃあどこarrayから来るの?

どうもありがとう。

4

5 に答える 5

2
addArrayElements = function(array) { fun.apply(null, array); };

しかし

それを含むスコープ (無名関数を作成した関数のスコープ) の変数コンテキストが表示され、アクセス可能な状態を維持するクロージャがあります。splat

JavaScript では、関数は、引数として、またはこの場合のようにクロージャ メカニズムを介して参照および渡すことができるファースト クラスのオブジェクトです。

編集: JavaScript とスコープについて

ほとんどの言語では、変数はデフォルトで、変数が定義されているスコープ (通常は関数のローカル シンボル テーブル) に対してローカルです。対照的に、JavaScript では、変数はvarキーワードを使用して定義されている場合にのみローカルです。それ以外の場合、シンボルは暗黙のルート オブジェクト (Web ブラウザーの場合はwindow. つまり、.

function foo() { someVar = "bar"; }

foo();
alert(someVar); // shows "bar"

ローカル スコープに制限されていないため、シンボルは (意図的かどうかにかかわらず) ルート スコープにリークされています。

それをさらに一歩進める:

function foo() { 
    var baz = function() { 
        someVar = "bar"; 
    };
    baz();
}

foo();
alert(someVar); // shows "bar"

ただし、foo 内で someVar を宣言すると、次のようになります。

function foo() { 
    var someVar;
    var baz = function() { 
        someVar = "bar"; 
    };
    baz();
    alert("someVar in foo=" + someVar); // shows "bar"
}

foo();
alert("someVar in root=" + window.someVar); // shows "undefined"

この最後のバージョンでは、someVar がルート スコープ内の変数としてもルート オブジェクトのプロパティとしても定義されず、エラーが発生したため、someVar だけでなく window.someVar を使用する必要があったことに注意してください。

于 2013-06-30T05:14:18.720 に答える
2
//Every time we call this function, we get another one back
function splat(fun) {
  return function(array) {         // <-- this one will be returned in splat();
    return fun.apply(null, array);
  };
}

//Step one, call splat, pass a function as parameter
var addArrayElements = splat(function(x, y) { return x + y });

/*
  Get back a function that accepts an array, and will execute the function we just passed in on it
*/

// This will call the newly created function, func will be available because it's in a closure
addArrayElements([1, 2]);

最後に、無名関数が 2 つのパラメーターを受け取る場合でも、applyを呼び出してバインドarray[0] ==> xし、array[1] ==> y

于 2013-06-30T05:17:25.560 に答える
2

.applyメソッドを使用せずにこの関数がどのように記述されるかを確認する方が簡単かもしれません。

function splat(fun) {
  return function(array) {
    return fun(array[0], array[1]);
  };
}

まず、関数を渡して splat を呼び出します。

var add = function(x,y){ return x + 1 };
var ff  = splat(add);

この時点で、ff は関数を参照します。これfunction(array)は、引数が 1 つの関数であることを意味します。プライベート変数funadd関数を参照します。

ここで、1 つの引数を渡して ff を呼び出します。

ff([1,2]);

配列内の値を使用して、fun2 つの引数で呼び出します

return fun(array[0], array[1]);

この例と実際の例の唯一の違いは、このapplyメソッドでは、私が行ったように特定の長さ (2) をハードコーディングする代わりに、任意の引数配列の長さを使用できることです。

于 2013-06-30T05:18:28.577 に答える
2

これは高階関数の例です。これは、関数を引数として受け取り、通常の値ではなく関数を返す関数です (ただし、Javascript では関数「単なる通常の値」です)。この場合:

function splat(fun) {

splat引数として関数を取ります...

return function(array) {

...そして、配列を取る新しい関数を返します...

return fun.apply(null, array);

...そして呼び出されるとfun、配列.appliedを引数として最初の関数を呼び出します。

したがってsplat、複数のパラメーターを期待する 1 つの関数を取り、代わりにパラメーターの配列を取る関数でラップします。「splat」という名前は、Ruby などの言語に由来し*ます。関数のパラメーター リスト内の (「splat」または「squashed bug」) は、任意の数の引数を配列に蓄積します。

var addArrayElements = splat(function(x, y) { return x + y });

addArrayElements基本的には次のとおりです。

function (array) {
    // closed over variable:
    // var fun = function(x, y) { return x + y }
    return fun.apply(null, array);
}

これは、新しく返された関数で渡された元のものを閉じて「保存」するクロージャーによって実現されます。funsplat

于 2013-06-30T05:19:51.243 に答える
0

より機能的なアプローチでは、bind() を使用します。これは、もはや splat を実際に必要としないほど短いため、クロージャーを排除することは常に良いことです:

var addArrayElements = Function.apply.bind( function(x, y) { return x + y } , null );

addArrayElements([1, 2]); // === 3
于 2013-06-30T06:18:57.497 に答える