【问题标题】:'this' is undefined in JavaScript class methods'this' 在 JavaScript 类方法中未定义
【发布时间】:2011-04-30 00:49:12
【问题描述】:

我是 JavaScript 新手。就我所做的一切而言,新功能是对现有代码进行了调整并编写了少量 jQuery。

现在我正在尝试编写一个带有属性和方法的“类”,但我遇到了方法问题。我的代码:

function Request(destination, stay_open) {
    this.state = "ready";
    this.xhr = null;
    this.destination = destination;
    this.stay_open = stay_open;

    this.open = function(data) {
        this.xhr = $.ajax({
            url: destination,
            success: this.handle_response,
            error: this.handle_failure,
            timeout: 100000000,
            data: data,
            dataType: 'json',
        });
    };

    /* snip... */

}

Request.prototype.start = function() {
    if( this.stay_open == true ) {
        this.open({msg: 'listen'});
    } else {

    }
};
//all console.log's omitted

问题是,在Request.prototype.start 中,this 未定义,因此 if 语句的计算结果为 false。我在这里做错了什么?

【问题讨论】:

  • 您在prototype 中有start 有什么原因吗?
  • Request.prototype 设置为什么?
  • 我在这里有一个类似的问题:stackoverflow.com/questions/3198264/… 其中有很多有用的链接。关键在于 JavaScript 中的this不是对被调用原型函数的“所有者”的常量引用,就像在大多数 OO 语言(如 Java)中一样。
  • @Matt:Request 是一个构造函数。 Request.prototype 默认为new Object()。您添加到其中的任何内容都会自动成为使用 new Request() 创建的对象的属性。
  • 我的意思是,这个问题比这个问题晚了 3 年提出的

标签: javascript class prototype


【解决方案1】:

你是如何调用启动函数的?

这应该有效(是关键)

var o = new Request(destination, stay_open);
o.start();

如果你像Request.prototype.start()这样直接调用它,this将引用全局上下文(浏览器中的window)。

此外,如果 this 未定义,则会导致错误。 if 表达式的计算结果不为 false。

更新this 对象不是基于声明设置的,而是通过调用。这意味着如果将函数属性分配给x = o.start 之类的变量并调用x(),则start 内部的this 不再引用o。这就是您执行setTimeout 时发生的情况。要使其正常工作,请改为执行以下操作:

 var o = new Request(...);
 setTimeout(function() { o.start(); }, 1000);

【讨论】:

  • 我正在使用 setTimeout:var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);
  • 这救了我的命,因为我试图理解为什么我传递给表达的函数'basicAuth 不能使用相同的输出。
  • 或者o.start.bind(o)。为什么x = o.start; x() 不起作用?
  • .bind() 返回一个新函数,而不是就地工作。所以你必须做x = o.start.bind(o); x()o.start = o.start.bind(o); x=o.start; x()
【解决方案2】:

JavaScript 的 OOP 有点古怪(或很多),需要一些时间来适应。您需要记住的第一件事是没有类,从类的角度思考可能会让您大吃一惊。为了使用附加到构造函数的方法(类定义的 JavaScript 等价物),您需要实例化您的对象。例如:

Ninja = function (name) {
    this.name = name;
};
aNinja = new Ninja('foxy');
aNinja.name; //-> 'foxy'

enemyNinja = new Ninja('boggis');
enemyNinja.name; //=> 'boggis'

请注意Ninja 实例具有相同的属性,但aNinja 无法访问enemyNinja 的属性。 (这部分应该非常简单/直接)当您开始向prototype 添加内容时,情况会有所不同:

Ninja.prototype.jump = function () {
   return this.name + ' jumped!';
};
Ninja.prototype.jump(); //-> Error.
aNinja.jump(); //-> 'foxy jumped!'
enemyNinja.jump(); //-> 'boggis jumped!'

直接调用这个会抛出一个错误,因为this只在构造器被实例化时指向正确的对象(你的“类”)(否则它指向全局对象,浏览器中的window

【讨论】:

    【解决方案3】:

    在 ES2015 又名 ES6 中,classfunctions 的语法糖。

    如果您想强制为this 设置上下文,您可以使用bind() 方法。正如@chetan 指出的那样,在调用时您也可以设置上下文!检查以下示例:

    class Form extends React.Component {
    constructor() {
        super();
      }
      handleChange(e) {
        switch (e.target.id) {
          case 'owner':
            this.setState({owner: e.target.value});
            break;
          default:
        }
      }
      render() {
        return (
          <form onSubmit={this.handleNewCodeBlock}>
            <p>Owner:</p> <input onChange={this.handleChange.bind(this)} />
          </form>
        );
      }
    }
    

    这里我们将handleChange() 中的上下文强制为Form

    【讨论】:

    • 您应该在构造函数中将函数绑定到 this 。否则,每次调用 render 时都会绑定它,而不是在实例化类时绑定一次。此外,您的大部分示例都与问题无关。
    • 或者在定义handleChange()时使用箭头语法
    【解决方案4】:

    我只是想指出,有时会发生此错误,因为函数已被用作高阶函数(作为参数传递),然后this 的范围丢失了。在这种情况下,我建议将此类函数绑定到this。例如

    this.myFunction.bind(this);
    

    【讨论】:

    • 很好的解释!!这正是我想要的。
    • 不知道你刚刚救了我多少头痛
    • 为什么this的范围会丢失?
    • 谢谢。这是正确答案!为什么不被接受?
    • 或者你可以使用箭头函数,那么你就不必调用绑定了。
    【解决方案5】:

    这个问题已经回答了,但也许其他人会来这里。

    当我在初始化类时愚蠢地试图解构类的方法时,我还遇到了 this 未定义的问题:

    import MyClass from "./myClass"
    
    // 'this' is not defined here:
    const { aMethod } = new MyClass()
    aMethod() // error: 'this' is not defined
    
    // So instead, init as you would normally:
    const myClass = new MyClass()
    myClass.aMethod() // OK
    
    

    【讨论】:

      【解决方案6】:

      使用箭头功能:

      Request.prototype.start = () => {
          if( this.stay_open == true ) {
              this.open({msg: 'listen'});
          } else {
      
          }
      };
      

      【讨论】:

        【解决方案7】:

        之前的答案都没有为我提供完整的解决方案,所以在这里发布我的。

        我有一个类,当我在方法引用上运行 forEach 时返回错误。

        例如

        class Foo {
          hello (name) {
            return `hello ${name}`
          }
        
          doGreet (name) {
            return console.log(this.hello(name)) // <- 'this' is undefined
          }
        }
        
        // print some names...
        const foo = new Foo();
        (['nick', 'john']).forEach(foo.doGreet)
        
        // TypeError: Cannot read property 'hello' of undefined
        //     at doGreet (/.../test.js:7:17)
        

        解决方案是在构造函数中绑定方法的this 的上下文。即

        class Foo {
          constructor () {
            this.doGreet = this.doGreet.bind(this)
          }
        
          // ... yada yada ...
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-06-03
          • 1970-01-01
          • 1970-01-01
          • 2020-05-26
          • 1970-01-01
          • 2017-08-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多