我知道函数内部是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()
,因为f
不会成为obj2
的属性
问题是:如何在该函数之外找到函数绑定的对象?
我想实现这个目标:
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
:)
答案 0 :(得分:10)
您可以进行部分申请:
// 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
(注意:由于您使用的是bind
,我假设您处于ES5环境中。)
答案 1 :(得分:4)
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添加任何新功能。实际上,您可以看到.bind()
的填充效果,以了解其工作原理here on MDN。
如果您希望this
始终是一个特定的对象,无论函数如何被调用,这都不是javascript的工作方式。除非函数实际上是一个在调用时强制与硬线对象关联的垫片(.bind()
做什么),否则函数没有硬连线关联。该关联由调用者根据其调用函数的方式完成。这与其他一些语言不同。例如,在C ++中,如果没有在调用时将正确的对象与其关联,则无法调用函数。该语言根本无法解析函数调用,并且您收到编译错误。
如果您正在使用javascript中的类型进行分支,那么您可能没有正确使用该语言的面向对象功能或者最大限度地利用它。
答案 2 :(得分: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的函数中。
答案 3 :(得分:2)
如果你是那个进行绑定的人,你可以在函数中添加一个字段来记录它,以便以后测试。
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