【问题标题】:The 'this' keyword returns the window object within an object's prototype in Javascript?'this' 关键字在 Javascript 中返回对象原型中的窗口对象?
【发布时间】:2012-10-24 20:19:30
【问题描述】:

我在一个类中有以下函数:

MyClass.prototype.myFunction = function(item, args) 
{       
    console.log(this);
}

此函数是从我无权更改的外部库调用的。当它被调用时,控制台将“this”记录为窗口对象,而不是实际的实例对象。在搜索 stackoverflow 后,我发现了这句话:

这是根据方法的调用方式设置的,而不是根据方法的编写方式。因此对于 obj.method(),这将在 method() 中设置为 obj。对于 obj.method.call(x),method() 内部的 this 将设置为 x。它由它的调用方式决定。这也意味着如果你将它作为回调传递给例如onclick,这将被设置为全局窗口对象,而不是您所期望的。

我假设这是正在发生的事情,我无法更改它的调用方式。我的问题是,不管它是如何被调用的,是否无论如何都要获取对象的实例?

【问题讨论】:

  • 如果可以的话,使用“new”关键字来实例化类。

标签: javascript prototypejs this prototype function-prototypes


【解决方案1】:

这是与 Javascript 的常见混淆。很容易认为它们的行为类似于其他语言中的扩展方法,但在 Javascript 中,更改 this 的上下文非常容易,以至于它经常是偶然发生的。

所以:

MyClass.prototype.myFunction = function(args) 
{
    // You expect [this] to refer to an instance of MyClass
    this.somePropertyOfMyClass;
};

然后你可以这样调用:

var x = new MyClass();
x.myFunction(args)

然而,在 Javascript 中调用函数的方式可能会改变 this 所指的内容:

var y = somethingElse();
x.myFunction.call(y, args); // now in myFunction [this] refers to y

更多的可能是很多库使用this 上下文进行链接和事件 - 容易犯错误。例如在 jQuery 中:

var $thing = $('.selector');
$thing.click(x.myFunction); // now in myFunction [this] refers to $thing

对于编写 jQuery 的人来说,以这种方式调用 x.myFunction 会破坏它可能并不明显。他们可以通过以下方式解决这个问题(假设他们知道实施):

$thing.click(function() { x.myFunction(); }); 

如果您希望您的 MyClass 能够适应这样的调用,请不要使用 prototype - 而是使用对象的属性:

function MyClass() {
    var self = this;
    // ...
    this.myFunction = function(args) 
    {
        // [self] will always refer to the current instance of MyClass
        self.somePropertyOfMyClass;
    };
}

请注意,更现代的浏览器 Javascript 引擎在优化此类调用方面非常出色,因此我不会将 prototype 用作优化,除非您已经确定需要额外的性能。

【讨论】:

  • 为什么原型应该提供额外的性能。原型在对象的属性之后被调用,并且只有在对象没有这样的属性的情况下才被调用?当您有多个对象时,您可以节省 RAM,但这并不意味着您一定会获得性能。
【解决方案2】:

大概是一个函数引用被传递给某个其他函数来调用,而另一个函数类似于:

function otherFunction(args, fn) {
    ...
    fn();
    ...
}

为确保方法获得所需的this,您可以这样做:

// Create a local variable referencing the `this` you want
var instance = this;

// Pass a function that has a closure to the variable
// and sets the appropriate this in the call
otherFunction(args, function(){myMethod.call(instance)})

现在myMethod 中的this 将是instance 引用的任何内容。请注意,如果在调用 otherFunction 之后和调用方法之前更改 instance 的值,myMethod 将获得该新值。

如果有问题,你也可以处理。

哦,你也可以在构造函数中处理这个问题,方法是为每个实例提供它自己的方法,该方法对该实例有一个闭包:

function MyObj(name) {
  var instance = this;
  instance.name = name;
  instance.getName = function() {
    return instance.name;
  }
}

var anObj = new MyObj('fred');

// Call as a method of anObj
alert(anObj.getName());  // fred 

// Pass method as a reference
var x = anObj.getName;

// Unqualified call
alert(x());  // fred    

【讨论】:

    【解决方案3】:

    规则是:

    从函数调用this时,它指的是全局对象(通常是Window)。
    当从方法调用this 时,它指的是所有者对象(即您正在使用该方法的当前对象)。

    例子:

    function Tryme() {
    
        var that = this
    
        function func2() {
            console.log("'this' from 'func2':", this)
        }
    
        function func3() {
            console.log("'that' from 'func3':", that)
        }
    
        this.method1 = function () {
            console.log("'this' from 'method1':", this)
        }
    
        this.method2 = function () {
            func2()
        }
    
        this.method3 = function () {
            func3()
        }
    }
    
    myinstance = new Tryme()
    
    myinstance.method1() // displays the object 'myinstance'
    myinstance.method2() // displays the object 'Window'
    myinstance.method3() // displays the object 'myinstance'
    

    示例中发生了什么?

    当您调用.method1() 并显示this 时,您当前处于对象myinstance 的方法中。所以this 将引用对象本身(即myinstance)。

    当您调用.method2() 时,此方法将调用对象myinstance 内称为func2() 的本地函数。这个函数func2()是一个函数而不是一个方法,所以this指的是全局对象Window

    当您调用.method3() 时,此方法将调用对象myinstance 内的一个本地函数,称为func3()。这个函数func3()是一个函数而不是一个方法,所以this指的是全局对象Window(如func2())。但是在func3() 中,我们显示的是that 的内容,这是myinstance 对象中的一个局部变量。 that 是一个对象,当this 引用所有者对象(即myinstance)时,该对象已使用this 的值进行初始化。在 JavaScript 中,如果你用object1object2 = object1)的值来初始化object2,那么当你改变一个对象的值时,另一个对象的值也会改变。所以that 将始终引用this 的值,它是myinstance 之一,即使this 的值发生变化。 记住this 是一个关键字,它指的是一个对象,它不是一个变量。

    您的情况如何?

    您从函数中调用了this,因此this 指的是全局对象(Window)。

    @Keith 建议可以做什么,即。创建一个对象,您将在其中创建一个等于您感兴趣的实例的thisself(或that)对象,然后在函数中使用self 对象(这将参考this 您感兴趣的对象)。

    更多信息

    这里:https://www.w3schools.com/js/js_this.asp
    这里:https://crockford.com/javascript/private.html

    【讨论】:

      【解决方案4】:

      一种解决方法是为每个实例创建一个myFunction() 的副本,即在构造函数中创建它而不是在原型上创建它,因为这样您就可以将this 的引用存储为局部变量在构造函数中:

      function MyClass() {
          var self = this;
          this.myFunction = function(item, args) {
              // use self instead of this
              console.log(self);
          };
          // other constructor code here
      }
      

      当然,为每个实例创建一个函数会占用更多内存——这可能是也可能不是问题,具体取决于函数的大小。一种折衷方案可能是在构造函数中为您的函数放置一个包装器,并在原型上定义实际函数:

      function MyClass() {
          var self = this;
          this.myFunction = function(item, args) {
              return self.wrappedMyFunction(item, args);
          };
      
          // your other constructor code here
      }    
      MyClass.prototype.wrappedMyFunction = function(item, args) 
      {       
          console.log(this);
      }
      

      【讨论】:

        猜你喜欢
        • 2012-09-11
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 2016-02-25
        • 1970-01-01
        • 1970-01-01
        • 2014-04-08
        • 1970-01-01
        相关资源
        最近更新 更多