在覆盖函数中获取正确的此上下文

时间:2016-07-07 12:11:17

标签: javascript angularjs this

我有以下问题:

我正在尝试覆盖一个函数,然后使用angular($scope.$apply())来应用它,但我的this - 上下文似乎不是正确的。

原始函数(在另一个文件中)如下所示:

Anno.prototype.switchTo = function(otherAnno) {
    if (otherAnno != null) {
        this.hideAnno();
        return otherAnno.show();
    } else {
        console.warn("Can't switchTo a null object. Hiding instead.");
        return this.hide();
    }
};

然后在另一个文件中,我“覆盖”它,如下所示:

var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno) {
    switchToFunction(otherAnno);
    $scope.$apply();
};

所以实际上我保存了原始函数,然后重新定义原始函数以调用原始函数,然后应用范围。

现在出现了问题:正如你所看到的,该函数使用了this.hideAnno(),但在我的重新定义的函数中,上下文是另一个,这就是为什么chrome会抛出错误“this.hideAnno()不是一个功能“。但现在我不确定如何才能获得正确的背景。我试图理解this,但我发现JavaScript非常混乱,我真的不明白。

有人可以帮我理解JavaScript混乱吗?

2 个答案:

答案 0 :(得分:1)

当一个函数作为js中的方法被调用时,它内部的this引用该方法所属的对象。

另一方面,当一个函数自己被调用时,它内部的this引用全局对象或严格模式下的undefined

您正在将定义为方法的函数提取(然后调用)到独立函数中,这就是为什么this没有达到预期的效果。

在这种情况下,您需要callapply switchToFunction,将this的值设置为您需要的值。换句话说,您将旧方法的this设置为您创建的新方法的this

var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno, that) {
    switchToFunction.call(this, otherAnno); // sets `this` of the old method to be this of the new method you created
    $scope.$apply();
};

答案 1 :(得分:1)

要理解这个问题,我认为首先我们应该了解this关键字的工作原理以及如何调整它。

  

在JavaScript中,任何函数内的this对象都是对象,在其上调用方法

考虑以下示例,

var obj1 = {
    foo: function() {
        console.log(this);
    }
};

function bar() {
    console.log(this);
}

现在调用方法时,我们得到如下输出

obj1.foo();     // obj1
bar();          // window
  

由于在foo上调用了obj1方法,因此this方法中的foo变为obj1。同样,this方法中的bar将是window对象。

现在,如果我想在函数内部调用bar obj1作为this,该怎么办?为此,JavaScript提供了call, apply and bind方法来动态更改函数的this。让我们看看如何使用call方法实现这一目标。

bar.call(obj1);         // obj1

类似地,

obj1.foo.call(window);          // window

call方法将thisArg对象作为参数,this函数内的bar。如果bar函数还希望参数也可以通过call之后的thisArg方法传递。有关call

的信息,请参阅MDN

所以问题的解决方案将是,

var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno) {
    switchToFunction.call(this, otherAnno);
    $scope.$apply();
};

希望这能让你明白这个问题。