'this'在JavaScript类方法中未定义

Car*_*ers 65 javascript prototype class

我是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
Run Code Online (Sandbox Code Playgroud)

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

Eli*_*iuX 71

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

this.myFunction.bind(this);
Run Code Online (Sandbox Code Playgroud)

  • 为什么 `this` 的范围会丢失? (6认同)
  • 好问题!我希望这有帮助:https://eliux.github.io/javascript/common-errors/why-this-gets-undefined-inside-methods-in-javascript/ (5认同)
  • 不知道你刚刚让我多少头痛 (4认同)
  • 很好的解释 !!这正是我所寻找的。 (3认同)
  • 谢谢。这才是正确答案!为什么这不被接受? (2认同)

Che*_*try 56

你是如何调用启动功能的?

这应该工作(新的是关键)

var o = new Request(destination, stay_open);
o.start();
Run Code Online (Sandbox Code Playgroud)

如果直接调用它Request.prototype.start(),this将引用全局上下文(window在浏览器中).

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

更新:this对象不是基于声明设置的,而是通过调用设置的.这意味着如果你将函数属性分配给变量like x = o.start和call x(),那么thisstart in不再引用o.这就是你做的事情setTimeout.要使其工作,请改为:

 var o = new Request(...);
 setTimeout(function() { o.start(); }, 1000);
Run Code Online (Sandbox Code Playgroud)


xj9*_*xj9 15

JavaScript的OOP有点时髦(或很多),需要一些时间来习惯.你需要记住的第一件事是没有课程,而且课程方面的思考可能会让你失望.并且为了使用附加到构造函数的方法(类似于类定义的JavaScript),您需要实例化对象.例如:

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

enemyNinja = new Ninja('boggis');
enemyNinja.name; //=> 'boggis'
Run Code Online (Sandbox Code Playgroud)

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

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

直接调用此方法将引发错误,因为this在实例化构造函数时仅指向正确的对象(您的"类")(否则它指向全局对象,window在浏览器中)


Kas*_*sra 10

使用箭头函数:

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

    }
};
Run Code Online (Sandbox Code Playgroud)


Nic*_*aly 8

以前的答案都没有为我提供完整的解决方案,因此请在此处发布我的答案。

我有一个类,当我运行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)
Run Code Online (Sandbox Code Playgroud)

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

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

  // ... yada yada ...
}
Run Code Online (Sandbox Code Playgroud)


Nit*_*tin 6

在 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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们强制内部的上下文handleChange()Form

  • 您应该在构造函数中将函数绑定到 this。否则,每次调用 `render` 时都会绑定它,而不是在实例化类时调用一次。此外,您的大部分示例与该问题并不真正相关。 (7认同)