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()as fdoesn't become a property ofobj2

编辑结束。

问题是:如何在这个函数之外找到函数绑定的对象?

我想实现这一点:

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

共识:

你不能这样做。外卖:使用bindthis非常小心:)

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()which 依次执行该fn()函数时,它被调用时将完全没有关联obj。将对象与函数关联是由函数的调用者完成的。它不是函数的属性。

如果要使用fn.bind(obj),那将创建一个新函数,该函数只是在内部执行对obj.fn(). 它不会神奇地为 javascript 添加任何新功能。事实上,你可以在 MDN 上.bind()看到一个 polyfill来了解它是如何工作的。


如果您希望this无论函数如何调用都始终是一个特定对象,那么这不是 javascript 的工作方式。除非函数实际上是一个 shim,它在被调用时强制与硬线对象关联(做什么.bind()),否则函数没有硬线关联。关联是由调用者根据调用函数的方式完成的。这与其他一些语言不同。例如,在 C++ 中,如果没有正确的对象在调用时与之关联,就无法调用函数。该语言根本无法解析函数调用,并且您会收到编译错误。

如果您在 javascript 中对类型进行分支,那么您可能没有正确使用该语言的面向对象功能或没有充分发挥您的最大优势。

于 2013-01-13T20:12:34.617 回答
3

与其将函数绑定func到对象,不如尝试将func其视为一个对象,它可以将 obj1 和 obj2 作为其属性?

例如:

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 视为函数的属性f。但是,当您绑定时,您会将函数添加为 obj1 或 obj2 的属性。可以将函数绑定到多个对象,因此寻找绑定函数的一个对象是没有意义的;因为您将函数添加为对象的子集。

在这种情况下,由于您希望将对象视为函数的子集,因此将属性添加到可以保存 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 回答