Javascript 函数存储在数组 vs 变量中
Javascript function stored in array vs in a variable
在此示例中,为什么将函数引用推入数组不会更改 scope
execution context
of this
而分配函数对新变量的引用确实改变了 scope
execution context
of 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)并且变量赋值发生变化this
指向包装 IIFE
块 (#2)?
如果我需要从各种对象中收集一堆这样的方法并在其他地方调用它们,这是一个很好的模式吗?
此引用调用与 console.error.bind(console)
等示例有何关联?
谢谢!
--更新
感谢 的精彩解释和澄清。
抛开拼写错误和复制错误,我首先问这个问题的原因是我怀疑 Satyajeet 确认了什么,但我正在处理的应用程序并没有反映这种行为(或者我认为如此)。
事实证明,在应用程序中,我正在执行与上述代码类似的过程,我调用 cbs.push(ford.logYear);
,将来自不同对象的多个方法添加到一个数组中。
我在应用程序中调用了所有这些方法,并希望它们的行为方式与在 execution context
scope
原始对象...他们这样做,因为方法交互的值没有附加到 this
,它们被捕获在闭包中。
查看示例 plunker here
--更新2
修复了 execution context
和 scope
的用法,使 question/answer 的每个部分都准确无误。
忽略你深夜复制粘贴的错误,重新定义你的 Car 函数为
function Car(name, year) {
this.name = name;
this.year = year
}
#1
实际上更多的是关于 Array 如何工作的问题,而不是关于 context 和 范围(*#2
)
您在数组内部调用函数,因此 在 javascript 中,数组的每个元素都是该数组对象 属性 的一个 。例如
var a = [];
a.push('Some value'); // a.0 is a property
但您不能调用 a.0
因为在 javascript 中以数字开头的属性不能用点表示法引用,必须使用括号表示法访问
所以当您调用 cbx[0]()
时,它与 cbx.0()
基本相同。
Scope和Execution context在javascript中的作用来了。 javascript 中已经有很多关于范围和上下文的好文章和答案。就像this,所以我认为不值得在这里解释所有这些。
但基本上 this
直到函数执行才定义(this
取决于 执行上下文 而不是范围)。
所以你的#1
会打印undefined
因为cbs[0]()
等同于cbs.0()
,而this
(执行上下文)设置为Array本身,即 [function]
。 (你里面只有一个函数)。
你的 #2
也将打印 undefined
因为执行上下文是 global(window object in case of browser)。
你的第三个问题的答案是,你需要显式硬绑定你的函数的执行上下文。
cbs.push(ford.logYear.bind(ford));
你的第 4 个问题是我认为只是 ES5 的 bind 方法的另一个用例,没什么特别的。通常使用它是因为浏览器实现要求 console.error
的执行上下文 (this) 必须设置为 window.console
.
在此示例中,为什么将函数引用推入数组不会更改 scope
execution context
of this
而分配函数对新变量的引用确实改变了 scope
execution context
of 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)并且变量赋值发生变化this
指向包装 IIFE
块 (#2)?
如果我需要从各种对象中收集一堆这样的方法并在其他地方调用它们,这是一个很好的模式吗?
此引用调用与 console.error.bind(console)
等示例有何关联?
谢谢!
--更新
感谢
抛开拼写错误和复制错误,我首先问这个问题的原因是我怀疑 Satyajeet 确认了什么,但我正在处理的应用程序并没有反映这种行为(或者我认为如此)。
事实证明,在应用程序中,我正在执行与上述代码类似的过程,我调用 cbs.push(ford.logYear);
,将来自不同对象的多个方法添加到一个数组中。
我在应用程序中调用了所有这些方法,并希望它们的行为方式与在 execution context
scope
原始对象...他们这样做,因为方法交互的值没有附加到 this
,它们被捕获在闭包中。
查看示例 plunker here
--更新2
修复了 execution context
和 scope
的用法,使 question/answer 的每个部分都准确无误。
忽略你深夜复制粘贴的错误,重新定义你的 Car 函数为
function Car(name, year) {
this.name = name;
this.year = year
}
#1
实际上更多的是关于 Array 如何工作的问题,而不是关于 context 和 范围(*#2
)
您在数组内部调用函数,因此 在 javascript 中,数组的每个元素都是该数组对象 属性 的一个 。例如
var a = [];
a.push('Some value'); // a.0 is a property
但您不能调用 a.0
因为在 javascript 中以数字开头的属性不能用点表示法引用,必须使用括号表示法访问
所以当您调用 cbx[0]()
时,它与 cbx.0()
基本相同。
Scope和Execution context在javascript中的作用来了。 javascript 中已经有很多关于范围和上下文的好文章和答案。就像this,所以我认为不值得在这里解释所有这些。
但基本上 this
直到函数执行才定义(this
取决于 执行上下文 而不是范围)。
所以你的#1
会打印undefined
因为cbs[0]()
等同于cbs.0()
,而this
(执行上下文)设置为Array本身,即 [function]
。 (你里面只有一个函数)。
你的 #2
也将打印 undefined
因为执行上下文是 global(window object in case of browser)。
你的第三个问题的答案是,你需要显式硬绑定你的函数的执行上下文。
cbs.push(ford.logYear.bind(ford));
你的第 4 个问题是我认为只是 ES5 的 bind 方法的另一个用例,没什么特别的。通常使用它是因为浏览器实现要求 console.error
的执行上下文 (this) 必须设置为 window.console
.