16

我在一个类中有以下功能:

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

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

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

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

4

4 回答 4

8

这是与 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

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

$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;
    };
}

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

于 2015-07-28T17:40:30.890 回答
4

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

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)})

现在将是任何this参考。请注意,如果您在调用之后和调用方法之前更改 的值,将获得该新值。myMethodinstanceinstanceotherFunctionmyMethod

如果这是一个问题,您也可以处理它。

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

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    
于 2012-11-05T01:09:57.883 回答
4

规则是:

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,它是对象内的局部变量myinstancethat是一个对象,该对象已使用thiswhen的值进行了初始化,该值this引用了所有者对象(即。myinstance)。在 JavaScript 中,如果你用( )object2的值进行初始化,那么当你改变一个对象的值时,另一个对象的值也会改变。所以总是指的是哪个值object1object2 = object1thatthismyinstance,即使值发生this变化。请记住this是一个关键字,它指的是一个对象,它不是一个变量。

你的情况发生了什么?

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

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

更多信息

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

于 2019-06-13T17:55:51.923 回答
1

一种解决方法是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-11-05T01:23:24.863 回答