2

方法#1

function transform(ar) {
    var alStr = [];
    for(var i=0; i<ar.length; i++) {

        alStr[i] = (function(v) {
            return (function() {
                return v;
            });
        }(ar[i]));
    }

    return alStr;
}

var a = ["a", 24, { foo: "bar" }];
var b = transform(a);
a[1];
b[1]();

方法 2

function transform(ar) {
    var alStr = [];
    for(var a in ar) {
        var O = function() {
            return a;
        }
        alStr.push(O);
    }
    return alStr; 
}

var a = ["a", 24, { foo: "bar" }];
var b = transform(a);
a[1];
b[1]();

上記のメソッドは、配列オブジェクトを、実行時に特定の配列オブジェクトを返す個々の関数に変換するために使用されます。方法 1 が機能し、方法 2 が機能しない理由を知りたい。

4

2 に答える 2

4

方法 2 には 2 つの問題があります。

  1. a配列値 ではなく、キー名 を返していますar[a]return a;つまり、あなたが望むのではなくreturn ar[a];.

  2. この関数は、同じスコープ オブジェクトを参照するため、ループされた最後の値を常に参照します。新しいスコープ オブジェクトを作成するには、クロージャー、withブロック、またはバインドされた関数が必要です。

クロージャー付き:

for(var a in ar) { 
  var O = (function(val) { 
    return function() { 
      return val; 
     }
  })(ar[a]);
  alStr.push(O); 
}

withブロックの場合:

for(var a in ar) { 
  with({val: ar[a]}) {
    alStr.push(function() { 
      return val; 
     });
  }
} 

バインドされた関数を使用:

for(var a in ar) { 
  var O = function(x) { return x; };
  alStr.push(O.bind(null, arr[a]));
} 
于 2012-08-06T01:13:10.543 に答える
3

ピーターオルソンは正しいです。ただし、これを行うためのより現代的な(正しい?)方法は、を使用することfunction.bind(obj, val)です。やや最近導入され、function.bind変数を値で、特定のコンテキストで渡すことができます。詳細はこちらをご覧ください

したがって、次のように書くことができます。

function transform(ar) {
    var alStr = [];
    var O = function(x) { return x }
    for(var a in ar) {
        alStr.push(O.bind(null, ar[a]));
    }
    return alStr; 
}

var a = ["a", 24, 12345];
var b = transform(a);
console.log(a[2]);
b[2]();

これは、クロージャの開始が非常に明確な意味を持つという事実により、より正しいパラダイムです。ただし、bindの使用は、特に関数呼び出し時に(特定のコンテキストまたは特定の規定で)使用される機能的なアプローチになる傾向があります。

withブロックを使用することには、いくつかの欠点もあります(それについてはたくさんの質問があります)。

ボーナスb:配列へのその後の変更も表現したい場合a、このソリューションはその問題を解決します:

function transform(ar) {
    var alStr = [];
    var O = function(x) { return ar[x] }
    for(var a in ar) {
        alStr.push(O.bind(null, a));
    }
    return alStr; 
}

var a = ["a", 24, 12345];
var b = transform(a);
console.log(a[2]);
console.log(b[2]());
console.log("*********");
a[2] = "new value!";
console.log(a[2]);
console.log(b[2]());
于 2012-08-06T01:34:20.833 に答える