在 Javascript 中,为什么“this”运算符不一致?

IT技术 javascript
2021-01-19 22:49:25

在 JavaScript 中,“this”运算符在不同场景下可以指代不同的事物。

通常在 JavaScript“对象”中的方法中,它指的是当前对象。

但是当用作回调时,它变成了对调用对象的引用。

我发现这会导致代码出现问题,因为如果您将 JavaScript“对象”中的方法用作回调函数,您将无法判断“this”是指当前“对象”还是“this”指的是调用对象。

有人可以澄清有关如何解决此问题的用法和最佳实践吗?

   function TestObject() {
            TestObject.prototype.firstMethod = function(){
                      this.callback();
                      YAHOO.util.Connect.asyncRequest(method, uri, callBack);

            }

            TestObject.prototype.callBack = function(o){
              // do something with "this"
              //when method is called directly, "this" resolves to the current object
              //when invoked by the asyncRequest callback, "this" is not the current object
              //what design patterns can make this consistent?
              this.secondMethod();
            }
            TestObject.prototype.secondMethod = function() {
             alert('test');
            }
        }
6个回答

在我喋喋不休地谈论这个变量的神奇之前,关于最佳实践的快速建议如果您想要 Javascript 中的面向对象编程 (OOP) 来密切反映更传统/经典的继承模式,请选择一个框架,了解其怪癖,不要试图变得聪明。如果您想变得更聪明,请将 javascript 作为一种函数式语言来学习,并避免考虑类之类的事情。

这提出了关于 Javascript 需要牢记的最重要的事情之一,并在没有意义时对自己重复一遍。Javascript 没有类。如果某样东西看起来像一个类,那是一个聪明的把戏。Javascript 有对象(不需要嘲讽的引号)和函数(这不是 100% 准确,函数只是对象,但有时将它们视为独立的事物会有所帮助)

这个变量被附连到功能。每当您调用一个函数时,它都会被赋予一个特定的值,具体取决于您调用该函数的方式。这通常称为调用模式。

在javascript中有四种调用函数的方法。您可以将函数作为方法函数构造函数apply调用

作为一种方法

方法是附加到对象的函数

var foo = {};
foo.someMethod = function(){
    alert(this);
}

当作为方法调用时,this将绑定到函数/方法所属的对象。在这个例子中,这将绑定到 foo。

作为函数

如果您有一个独立的函数,则this变量将绑定到“全局”对象,几乎总是浏览器上下文中窗口对象。

 var foo = function(){
    alert(this);
 }
 foo();

这可能是你绊倒的原因,但不要难过。许多人认为这是一个糟糕的设计决定。由于回调是作为函数而不是方法调用的,这就是为什么您会看到似乎不一致的行为。

许多人通过做类似的事情来解决这个问题,嗯,这个

var foo = {};
foo.someMethod = function (){
    var that=this;
    function bar(){
        alert(that);
    }
}

你定义一个变量指向这个闭包(一个它自己的主题)一直that存在,所以如果你把 bar 作为回调调用,它仍然有一个引用。

作为构造函数

您还可以调用函数作为构造函数。根据您使用的命名约定 ( TestObject),这也可能是您正在做的事情,也是您绊倒的原因

您可以使用new关键字将函数作为构造函数调用

function Foo(){
    this.confusing = 'hell yeah';
}
var myObject = new Foo();

当作为一个构造函数调用时,一个新的对象将被创建,并且将被绑定到该对象。同样,如果您有内部函数并且它们被用作回调,您将作为函数调用它们,并且this将绑定到全局对象。使用那个var that = this;技巧/模式。

有些人认为,constructor/new 关键字是扔给 Java/传统 OOP 程序员的一种方法,用于创建类似于类的东西。

使用应用方法。

最后,每个函数都有一个名为apply. Apply 可以让您确定this的值,还可以让您传入参数数组。这是一个无用的例子。

function foo(a,b){
    alert(a);
    alert(b);
    alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
可能值得补充:还有 call 方法,它的功能类似于 apply,只是参数不作为数组传递。
2021-03-17 22:49:25
@Alan,很好的答案,但也值得一提bind
2021-04-05 22:49:25

在 JavaScript 中,this总是指调用正在执行的函数的对象。因此,如果该函数被用作事件处理程序,this则将引用触发事件的节点。但是,如果您有一个对象并在其上调用一个函数,例如:

myObject.myFunction();

然后this里面myFunction会提到myObject是否有意义?

为了解决这个问题,你需要使用闭包。您可以按如下方式更改代码:

function TestObject() {
    TestObject.prototype.firstMethod = function(){
        this.callback();
        YAHOO.util.Connect.asyncRequest(method, uri, callBack);
    }            

    var that = this;
    TestObject.prototype.callBack = function(o){
        that.secondMethod();
    }

    TestObject.prototype.secondMethod = function() {
         alert('test');
    }
}
链接到一个关于 javascript 中闭包的非常好的演示:tinyurl.com/5mrpjv
2021-03-12 22:49:25
函数原型不应该放在构造函数之外吗?或替换TestObject.prototypethat.
2021-03-21 22:49:25
请记住,“在 JavaScript 中,“this”始终指的是调用正在执行的函数的对象”这句话在技术上是不正确的。这可以有四种不同的上下文,具体取决于函数的调用方式。
2021-03-22 22:49:25

this对应于函数调用的上下文。对于不是作为对象的一部分(无.运算符)调用的函数,这是全局上下文(window在网页中)。对于称为对象方法(通过 . 运算符)的函数,它是对象。

但是,您可以随心所欲地制作它。所有函数都有 .call() 和 .apply() 方法,可用于通过自定义上下文调用它们。因此,如果我像这样设置一个对象智利:

var Chile = { name: 'booga', stuff: function() { console.log(this.name); } };

...并调用Chile.stuff(),它会产生明显的结果:

booga

但如果我愿意,我可以接受并真正解决它

Chile.stuff.apply({ name: 'supercalifragilistic' });

这个其实挺有用的。。。

如果您使用的是 javascript 框架,则可能有一种方便的方法来处理这个问题。例如,在 Prototype 中,您可以调用一个方法并将其作用域到特定的“this”对象:

var myObject = new TestObject();
myObject.firstMethod.bind(myObject);

注意:bind() 返回一个函数,因此您也可以使用它来预定义类中的回调:

callBack.bind(this);

http://www.prototypejs.org/api/function/bind

我相信这可能是由于 [closures]( http://en.wikipedia.org/wiki/Closure_(computer_science)在 Javascript 中的工作原理。

我刚刚开始自己​​处理闭包。阅读链接的维基百科文章。

这是另一篇提供更多信息文章

有哪位大神能证实一下吗?