20

関数内でそれが であることを知っていますthis

var func = function {
    return this.f === arguments.callee; 
    // => true, if bound to some object
    // => false, if is bound to null, because this.f === undefined
}

var f = func; // not bound to anything;

var obj = {};
obj1.f = func; // bound to obj1 if called as obj1.f(), but not bound if called as func()

var bound = f.bind(obj2) // bound to obj2 if called as obj2.f() or as bound()

編集:

のプロパティにならないため、obj2.f()実際に呼び出すことはできませんfobj2

編集終了。

問題は、この関数の外で、関数がバインドされているオブジェクトを見つける方法です。

私はこれを達成したい:

function g(f) {
  if (typeof(f) !== 'function') throw 'error: f should be function';

  if (f.boundto() === obj)
    // this code will run if g(obj1.f) was called
    doSomething(f);

  // ....

  if (f.boundto() === obj2)
    // this code will run if g(obj2.f) or g(bound) was called
    doSomethingElse(f);
}

関数がバインドされているオブジェクトを変更せずに部分適用します。

function partial(f) {
   return f.bind(f.boundto(), arguments.slice(1));
}

コンセンサス:

あなたはそれをすることはできません。持ち帰り:細心の注意を払って使用bindしてくださいthis:)

4

4 に答える 4

12

部分適用

部分適用を行うことができます:

// This lets us call the slice method as a function
// on an array-like object.
var slice = Function.prototype.call.bind(Array.prototype.slice);

function partial(f/*, ...args */) {

    if (typeof f != 'function')
        throw new TypeError('Function expected');

    var args = slice(arguments, 1);

    return function(/* ...moreArgs */) {
        return f.apply(this, args.concat(slice(arguments)));
    };

}

この関数がバインドされているオブジェクトは?

さらに、質問の最初の部分には非常に簡単な解決策があります。これがオプションかどうかはわかりませんが、JS で簡単にモンキー パッチを適用できます。モンキーパッチbindは完全に可能です。

var _bind = Function.prototype.apply.bind(Function.prototype.bind);
Object.defineProperty(Function.prototype, 'bind', {
    value: function(obj) {
        var boundFunction = _bind(this, arguments);
        boundFunction.boundObject = obj;
        return boundFunction;
    }
});

他のスクリプトが実行される前にそれを実行するだけで、 を使用するスクリプトは、関数にプロパティをbind自動的に追加します。boundObject

function f() { }
var o = { };
var g = f.bind(o);
g.boundObject === o; // true

(注: を使用しているため、上記の ES5 環境にいると想定していますbind。)

于 2013-01-13T23:14:28.507 に答える
6

JavaScript の関数は、技術的には何にもバインドされていません。次のように、オブジェクトのプロパティとして宣言できます。

var obj = {
    fn: function() {}
}
obj.fn();

ただし、関数を独自の変数に単独で取得すると、特定のオブジェクトにバインドされません。

たとえば、これを行った場合:

var obj = {
    fn: function() {}
}
var func = obj.fn;
func();

次に、関数func()を実行するfn()関数を呼び出すと、呼び出されたときにまったく関連付けられませんobj。オブジェクトと関数の関連付けは、関数の呼び出し元によって行われます。関数のプロパティではありません。

を使用するfn.bind(obj)と、 への呼び出しを内部的に実行するだけの新しい関数が作成されobj.fn()ます。JavaScript に新しい機能を魔法のように追加するわけではありません。実際、 MDNでポリフィルが.bind()どのように機能するかを確認できます。


this関数がどのように呼び出されても常に特定のオブジェクトであると期待している場合、それは JavaScript の動作ではありません。関数が実際に呼び出されたときにハードワイヤード オブジェクトとの関連付けを強制するシムでない限り (何をするか.bind())、関数はハードワイヤードの関連付けを持ちません。関連付けは、関数の呼び出し方法に基づいて、呼び出し元によって行われます。これは他のいくつかの言語とは異なります。たとえば、C++ では、呼び出し時に関連付ける適切なオブジェクトがなければ、関数を呼び出すことはできません。言語は単に関数呼び出しを解決せず、コンパイル エラーが発生します。

JavaScript で型に分岐している場合は、言語のオブジェクト指向機能を適切に使用していないか、最大限に活用していない可能性があります。

于 2013-01-13T20:12:34.617 に答える
3

関数をオブジェクトにバインドする代わりに、obj1 と obj2 をプロパティとして保持できるオブジェクトとしてfunc扱ってみませんか?func

例えば:

var func = function {
    this.object; // Could be obj1 or obj2
    return this.f === arguments.callee;
    // => true, if this.object is not null
}

var f = func;

f.object = obj1; // or func.object = obj2;

オブジェクトが obj1 であるか obj2 であるかを処理する関数を作成することもできます。

function g(f) {
  if (typeof(f) !== 'function') throw 'error: f should be function';

  if (f.object === obj)
    // this code will run if g(f) was called
    doSomething(f);
  if (f.object === obj2)
    // this code will run if g(f) or g(bound) was called
    doSomethingElse(f);
}

その理由は、obj1 と obj2 を function のプロパティとして扱いたいからですf。ただし、バインドすると、関数が obj1 または obj2 のプロパティとして追加されます。関数を複数のオブジェクトにバインドすることは可能であるため、関数をバインドした 1 つのオブジェクトを探すのは意味がありません。関数をオブジェクトのサブセットとして追加しているためです。

この場合、オブジェクトを関数のサブセットとして扱いたいので、obj1 または obj2 を保持できるプロパティを関数に追加することが理にかなっています。

于 2013-01-13T20:16:17.447 に答える
2

あなたがバインドを行っている場合は、関数にフィールドを追加して、後でテストするために this を記録できます。

var that = "hello";
var xyz = function () { console.log(this); }.bind(that);
xyz.that = that;

// xyz is callable as in xyz(), plus you can test xyz.that without calling
于 2013-01-13T20:21:59.073 に答える