JavaScript类方法中未定义“ this”


83

我是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.startthis是不确定的,因此,如果语句评估为假。我在这里做错了什么?


有你有充分的理由startprototype
xj9

什么是Request.prototype设置?
马特·鲍尔

我在这里有一个类似的问题:stackoverflow.com/questions/3198264/…,其中有一堆有用的链接。问题的关键在于this,JavaScript不是对原型函数的“所有者”的不变引用,就像在大多数OO语言(如Java)中那样。
马克·布林格

1
@Matt:请求是构造函数。Request.prototype默认为new Object()。您添加到其中的所有内容都会自动成为使用创建的对象的属性new Request()
Chetan S

@Matt BallRequest.prototypeRequest继承实例的地方。在这种情况下,可能是FunctionObject
xj9

Answers:


67

您如何调用启动函数?

这应该工作(是关键)

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

如果直接将其命名为Request.prototype.start()this则会引用全局上下文(window在浏览器中)。

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

更新this对象不是基于声明设置的,而是通过调用设置的。这意味着,如果您将function属性分配给诸如x = o.startand的变量x(),则thisstart不再引用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()
theonlygusti

35

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

this.myFunction.bind(this);

3
很好的解释 !!那正是我想要的。
vandersondf

1
没有告诉您您为我省了多少头痛
Native Coder

为什么this迷路的范围?
theonlygusti

17

JavaScript的OOP有点时髦(或很多),并且需要一些习惯。您需要记住的第一件事是没有班级,关于班级的思考会绊倒您。为了使用附加到构造函数的方法(JavaScript等效于Class定义),您需要实例化对象。例如:

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在浏览器中指向全局对象)


6

在ES2015中又名ES6,class是的语法糖functions

如果要强制设置上下文,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


6
您应该在构造函数中将此函数绑定到此函数。否则,您将在每次render调用该类时都绑定它,而不是在实例化该类时绑定一次。同样,您的大多数示例与该问题并非真正相关。
erich2k8 '18

或在定义handleChange()
Nitin

0

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

我还有一个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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.