我正在尝试创建一个示例,说明为什么习惯用语var that = this
是必要的(例如,如here所述)。
因此,我开始使用错误代码的示例,该代码无法正确绑定this
。但是,我写的代码给了我一些意想不到的结果(在另一个方向):
message = "message in global scope";
// the below erroneous code aims to demonstrate why we need
// the "var that = this" idiom to capture the "this" lexical scope
var createLoggingFunctionWrongWay = function () {
return function () {
console.log(this.message);
};
};
// the below *does* print "message in global scope"
// i.e. fails in the way I expected
createLoggingFunctionWrongWay.call({message:"message"})();
// I was expecting the below to also print "message in global scope" as
// well, yet it prints "undefined"
setTimeout(createLoggingFunctionWrongWay.call({
message: "message"
}), 1000);
在nodejs
下运行时,我得到:
$ nodejs foo.js
message in global scope
undefined
我的问题是为什么第二次调用(使用setTimeout
)也不会以同样的方式失败,并将this
解释为指向global
中的Node.js
对象}(message
变量所在的位置)?
更新
当我在匿名函数中插入console.log(this)
时,在第一次调用时,我得到全局上下文对象(message
所在的位置),而在第二次调用时(通过setTimeout
)我得到以下对象:
{ _idleTimeout: 1000,
_idlePrev: null,
_idleNext: null,
_idleStart: 1446483586705,
_onTimeout: [Function],
_repeat: false
}
答案 0 :(得分:5)
在Node.js中,调用setTimeout
的回调,并将Timeout
对象绑定为上下文(this
)对象,但他们没有其中定义的message
。这就是第二种方法打印undefined
的原因。您可以看到相应的代码段here。
var timer = new Timeout(after);
var length = arguments.length;
var ontimeout = callback;
switch (length) {
// fast cases
case 0:
case 1:
case 2:
break;
case 3:
ontimeout = callback.bind(timer, arguments[2]);
break;
case 4:
ontimeout = callback.bind(timer, arguments[2], arguments[3]);
break;
case 5:
ontimeout =
callback.bind(timer, arguments[2], arguments[3], arguments[4]);
break;
// slow case
default:
var args = new Array(length - 2);
for (var i = 2; i < length; i++)
args[i - 2] = arguments[i];
ontimeout = callback.apply.bind(callback, timer, args);
答案 1 :(得分:0)
您可以通过bind
方法将范围传播到返回的函数:
message = "message in global scope";
var createLoggingFunctionWrongWay = function () {
return (function () {
console.log(this.message);
}).bind(this);
};
setTimeout(createLoggingFunctionWrongWay.call({ message: "message" }), 1000);
否则它在其范围内起作用,实际上是通过忽略注入最外层函数的那个来导致全局的。
一个简单的函数调用,没有注入范围(也就是说,你既没有使用call
,也没有使用apply
或bind
等),它具有全局上下文作为其默认一个。这主要是因为函数调用必须具有上下文,但在这种情况下,没有特定的上下文与该函数相关联,因此它默认为全局函数。
请注意,我们所说的功能不是原型的一部分。