在此示例中,为什么将函数引用推送到数组上不会更改scope
的{s> execution context
this
,而是将函数引用赋给新变量确实更改scope
的 execution context
this
?
(function() {
function Car(year) {
this.year = year;
}
Car.prototype = {
logYear: function() {
console.log(this.year);
}
};
var ford = new Car('Ford', 1999);
ford.logYear();
var cbs = [];
cbs.push(ford.logYear);
for(var x = 0; x < cbs.length; x++) {
cbs[x](); // -> 1999 #1
var callback = cbs[x];
callback(); // -> undefined #2
}
})()
这是因为对数组中函数的引用指向ford
对象上的原始函数,其中this
仍被定义为实例(#1),变量赋值更改{ {1}}指向包裹this
块(#2)?
如果我需要从各种对象中收集这样的一堆方法并在其他地方调用它们,这是一个很好的模式吗?
此引用调用如何与IIFE
?
谢谢!
- 更新
感谢@Satyajeet提供了很好的解释和澄清。
错别字复制错误除了我首先提出这个问题的原因是我怀疑Satyajeet确认了什么,但我正在处理的申请并没有反映出这种行为(或者我认为)。
事实证明,在应用程序中,我正在执行与上面代码类似的过程,我调用console.error.bind(console)
,将不同对象的多个方法添加到数组中。
在应用程序的某个点上,我调用所有这些方法并期望它们的行为方式与在原始文件的 cbs.push(ford.logYear);
execution context
中调用它们的方式相同对象...它们确实如此,因为方法与之交互的值未附加到scope
,它们会在闭包中捕获。
请参阅示例plunker here
- 更新2
修正this
和execution context
的使用对问题/答案的每个部分都是准确的。
答案 0 :(得分:4)
忽略您的深夜复制粘贴错误,并将您的汽车功能重新定义为
function Car(name, year) {
this.name = name;
this.year = year
}
#1
确实更多关于数组的工作方式,而不是上下文和范围(* {{1 }})
您正在调用数组中的函数,因此在javascript中数组中的每个元素都是该数组对象的属性。例如
#2
但是您无法调用var a = [];
a.push('Some value'); // a.0 is a property
,因为在javascript中以数字开头的属性无法使用点表示法引用,并且必须使用括号表示法访问
因此,当您致电a.0
时,它与cbx[0]()
基本相同。
这里有javascript中范围和执行上下文的作用。在javascript中已经有很多关于Scope和Context的好文章和答案。就像this一样,所以我认为不值得在这里解释所有这些。
但是,在执行函数(cbx.0()
依赖于执行上下文而不是范围)之前,基本上没有定义this
。
因此this
将打印#1
因为undefined
等同于cbs[0]()
,而cbs.0()
(执行上下文)设置为数组本身,这是this
。 (你里面只有一个功能)。
您的[function]
也会打印#2
,因为执行上下文是全局(浏览器中的窗口对象)。
回答你的第3个问题是,你需要明确硬绑定执行上下文到你的功能。
undefined
你的第四个问题是我认为ES5的另一个用例 bind 方法,没什么特别的。它通常被使用,因为浏览器实现要求cbs.push(ford.logYear.bind(ford));
的执行上下文(this)必须设置为console.error
。