【问题标题】:Javascript function stored in array vs in a variable存储在数组与变量中的 Javascript 函数
【发布时间】:2016-02-15 05:59:05
【问题描述】:

在此示例中,为什么将函数引用推入数组不会改变 scope execution contextthis 而将函数引用分配给新变量确实会改变 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 的精彩解释和澄清。

除了我最初提出这个问题的原因之外,拼写错误和复制错误是我怀疑 Satyajeet 确认的内容,但我正在处理的应用程序并未反映这种行为(或者我认为如此)。

事实证明,在应用程序中,我正在执行与上面调用cbs.push(ford.logYear); 的代码类似的过程,将来自不同对象的多个方法添加到数组中。

在应用程序中的某个时刻,我调用了所有这些方法,并期望它们的行为方式与在原始对象的 execution context scope 中调用它们时的行为方式相同...确实如此,因为与方法交互的值未附加到 this,它们被捕获在闭包中。

查看示例 plunker here

-- 更新 2

修正了execution contextscope 的用法,以确保问题/答案的每个部分都准确无误。

【问题讨论】:

  • ` cbs[x](); // -> 1999 #1`不会打印任何Ford1999,它正在打印undefined
  • JS 被阻塞作用域。所以this 只会在函数中调用时改变。您的cbs 数组与Car 处于同一范围内
  • 实际上,您的第一个控制台日志来自您执行ford.logYear();,您在所有其他日志消息中都未定义。所以你正在改变this的范围,你只是误解了日志消息
  • @PatrickEvans 啊,谢谢!这就是我迟到编码和复制粘贴所得到的。

标签: javascript function this


【解决方案1】:

忽略您的深夜复制粘贴错误,并将您的 Car 功能重新定义为

function Car(name, year) {
    this.name = name;
    this.year = year
}

#1 实际上更多的是关于 Array 如何工作的问题,而不是关于 contextscope(*#2)

你在数组中调用一个函数,所以在javascript中,数组的每个元素都是该数组对象的一个​​属性。例如

var a = [];
a.push('Some value'); // a.0 is a property 

但你不能调用a.0,因为在javascript中以数字开头的属性不能用点符号引用,必须使用括号符号访问

所以当您调用cbx[0]() 时,它与cbx.0() 基本相同。 这就是 ScopeExecution context 在 javascript 中的作用。已经有很多关于 javascript 中的 Scope 和 Context 的好文章和答案。就像this一样,所以我认为这里不值得解释。

但基本上 this 直到函数执行才被定义(this 取决于 执行上下文 而不是范围)。

所以你的#1 将打印undefined,因为cbs[0]() 等价于cbs.0(),并且this(执行上下文)设置为数组本身,即[function]。 (你里面只有一个函数)。

你的#2 也将打印undefined,因为执行上下文是全局(浏览器中的窗口对象)。 第三个问题的答案是,您需要明确硬绑定执行上下文到您的函数。

cbs.push(ford.logYear.bind(ford));

你的第四个问题是我认为这只是 ES5 bind 方法的另一个用例,没什么特别的。通常使用它是因为浏览器实现要求console.error 的执行上下文(this)必须设置为window.console

【讨论】:

  • 感谢您的澄清。我现在对bind有了更好的理解。事实证明,我在我正在开发的应用程序中使用的模式在传递方法时使用闭包来维护上下文,这就是为什么在我的应用程序的实现中向数组添加方法仍然有效的原因。查看我对我的问题的更新。
  • 哦.. 好像你的 Scope 有问题,我解释了 Context.. :)
  • 我更新了我的问题,以修复我对 execution contextscope 的使用在提及 closuresthis 时保持一致和准确。
猜你喜欢
  • 2010-12-25
  • 2011-07-18
  • 1970-01-01
  • 2014-03-09
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多