函数调用
函数只是对象的一种。
所有Function对象都有调用和Apply方法,这些方法执行被调用的Function对象。
调用这些方法时,这些方法的第一个参数指定对象,该对象将this
在执行Function时由关键字引用-如果它是null
或undefined
全局对象window
,则用于this
。
因此,调用一个函数...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
...带括号-- foo()
等效于foo.call(undefined)
或foo.apply(undefined)
,实际上与foo.call(window)
或相同foo.apply(window)
。
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
将的其他参数call
作为函数调用的参数传递,而的一个附加参数apply
可以将函数调用的参数指定为类似数组的对象。
因此,foo(1, 2, 3)
等于foo.call(null, 1, 2, 3)
或foo.apply(null, [1, 2, 3])
。
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
如果函数是对象的属性...
var obj =
{
whereAmI: "obj",
foo: foo
};
...通过对象访问对该函数的引用并用括号-对其进行调用obj.foo()
等效于foo.call(obj)
或foo.apply(obj)
。
但是,作为对象属性保留的功能未“绑定”到那些对象。在obj
上面的定义中可以看到,由于函数只是对象的一种,因此可以对其进行引用(因此可以通过引用传递给Function调用,也可以通过引用从Function调用返回)。当对函数的引用传递,它通过了关于没有额外的信息从与它进行,这就是为什么会发生以下情况:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
调用我们的Function引用baz
不会提供任何上下文,因此它实际上与相同baz.call(undefined)
,因此this
最终引用window
。如果我们想baz
知道它属于obj
,那么我们需要以某种方式在baz
调用时提供该信息,这是call
or apply
和闭包的第一个参数起作用的地方。
范围链
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
执行Function时,它将创建一个新作用域,并引用任何封闭的作用域。在上述示例中创建匿名函数时,它会引用创建该函数bind
的作用域,即作用域。这称为“关闭”。
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
当您尝试访问变量时,将沿着“作用域链”查找具有给定名称的变量-如果当前作用域不包含该变量,则请查看链中的下一个作用域,依此类推,直到到达全球范围。返回匿名函数并bind
完成执行后,匿名函数仍具有对bind
范围的引用,因此bind
范围不会“消失”。
鉴于以上所有内容,您现在应该能够理解以下示例中的作用域如何工作,以及为什么在调用带有特定值的“预绑定”周围传递函数的技术将起作用this
时,将具有以下作用:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};