【问题标题】:Accessing object values within anonymous function在匿名函数中访问对象值
【发布时间】:2014-08-24 22:31:18
【问题描述】:

我有一个对象(事物),它跟踪一些值以及一组条件:

var Thing = function(currentValue) {
    this.currentValue = currentValue;
    this.conditions = [];
};

条件可以添加到这个列表中:

Thing.prototype.addCondition = function(condition) {
    this.conditions.push(condition);
}

我希望条件采取某种功能的形式,这样我就可以做到

thing.addCondition(thing.exampleCondition(valueToCheckFor));

这些条件都可以通过

来检查
Thing.prototype.evaluateConditions = function() {
    this.conditions.forEach(function(condition) {
        if (condition()) {
            //Do something
        }
    });
};

目前我有一个这样的条件函数:

Thing.prototype.exampleCondition = function(value) {
    return function() {
        return this.currentValue === value;
    };
};

这显然不起作用 - this.currentValue 在匿名函数中未定义。我的问题是我需要在调用 evaluateConditions() 时根据 currentValue 的值对传递给 exampleCondition 的值进行评估 - 因此我不能这样做

Thing.prototype.exampleCondition = function(value) {
    var c = this.currentValue;
    return function() {
        return c === value;
    };
};

我是一个 javascript 菜鸟,但希望你们聪明的人可以在这里为我指明正确的方向。

【问题讨论】:

    标签: javascript function this anonymous


    【解决方案1】:

    在 javascript 中,每个函数总是根据上下文进行评估,上下文定义了 this 的值。

    函数的上下文可以在调用函数时显式或隐式设置。要隐式设置上下文,您必须调用这样的函数:

    //z will be the context, in other words, inside method: this = z
    a.b.c.d...z.method();
    

    为了显式设置上下文,您可以使用 Function 对象原型中的两个函数:apply and call。这两个与每个浏览器兼容,因此您不会遇到问题。问题是,对于这两个,您每次调用函数时都在设置上下文,因此如果您直接使用它们,它不会帮助您解决问题。

    您必须定义一个函数,该函数每次调用时总是针对相同的上下文进行评估。为此,您可以使用在 Function 对象原型中定义的 bind 函数,问题是它与旧浏览器不兼容,因为它是 ECMA-262 第 5 版的最新添加。不过,解决方案可以将每个条件函数绑定到 addCondition 函数中的对象:

    Thing.prototype.exampleCondition = function(value) {
        return function() {
            return this.currentValue === value;
        };
    };
    
    Thing.prototype.addCondition = function(condition) {
        //The bind function will return a function that will always execute with your object as context
        this.conditions.push(condition.bind(this));
    }
    

    对于浏览器兼容性问题,您可以try this code。将它放在脚本的开头,您可以确定您将拥有适用于每个浏览器的绑定功能。

    另一种可能的解决方案是:

    Thing.prototype.exampleCondition = function(value) {
        var self = this;
        return function() {
            return self.currentValue === value;
        };
    };
    

    问题是,在这种情况下,您没有使用上下文,而是在返回的函数中忽略了它。而不是使用上下文,而是用范围中定义的一些变量替换它。为此,您将强制定义为条件函数的每个函数都执行该小技巧。我认为第一个解决方案更好。

    【讨论】:

    • 关于“…一个上下文,它定义了this对象的值” 一个函数的this被定义only通过调用函数的方式或使用 bindthis 只是execution context 的一个参数。在严格模式下,this 不一定是对象,它可以有任何值(包括 undefined)。
    • 你是对的。我想在我的回答中提出另一点,所以我没有注意那个细节。不过,谢谢,我刚刚编辑了我的答案。
    【解决方案2】:

    问题在于this 在每个函数内部都会发生变化。

    那么,在exampleCondition返回的函数内部,this不会是你的Thing实例,它会是非严格模式下的window和严格模式下的undefined

    因此,你可以这样做

    Thing.prototype.exampleCondition = function(value) {
        var that = this;
        return function() {
            return that.currentValue === value;
        };
    };
    

    或者,如果您愿意,可以使用 ES5 bind

    Thing.prototype.exampleCondition = function(value) {
        return (function() {
            return this.currentValue === value;
        }).bind(this);
    };
    

    【讨论】:

    • 谢谢,这正是我所需要的。
    • forEach 的可选第二个参数是在回调中用作 this 的对象,因此 OP 也可以这样做:this.conditions.forEach(function(condition, this) {...}) so不需要关闭或使用 bind.
    • @RobG 但所需的this 不是forEach 回调之一,而是condition 之一。所以OP需要像this.conditions.forEach(condition=>condition.call(this), this)这样的东西
    • @Oriol——是的,this 对象需要继续传递。
    猜你喜欢
    • 1970-01-01
    • 2017-04-09
    • 2014-11-08
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 2014-04-09
    相关资源
    最近更新 更多