“this”在 JavaScript 类方法中未定义

问题描述 投票:0回答:9

我是 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。我在这里做错了什么?

javascript class prototype
9个回答
179
投票

我只是想指出,有时会发生此错误,因为函数已作为参数传递给高阶函数,然后

this
的范围丢失了。在这种情况下,我建议将此类函数绑定到
this
。例如

this.myFunction.bind(this)

此外,lambda 函数也可以工作:

(args) => this.myFunction(args)

86
投票

如何调用启动函数?

这应该可行(是关键)

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

43
投票

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

我有一个类,当我在方法引用上运行

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) // <- Add this
  }

  hello (name) {
    return `hello ${name}`
  }

  doGreet (name) {
    return console.log(this.hello(name))
  }
}

18
投票

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


10
投票

使用箭头功能:

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

    }
};

8
投票

在 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


4
投票

这个问题已得到解答,但也许其他人会来这里。

我还遇到了一个问题,即

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


4
投票

如果函数已用作高阶函数(作为参数传递),则

this
的范围会丢失。

要解决此问题,可以将

this
绑定到 @Eliux 描述的函数:

this.myFunction.bind(this);

要像 @DanielTonon 想要的那样自动化此过程,您可以在构造函数中执行此操作:

Object.getOwnPropertyNames(YourClass.prototype).forEach((key) => {
  if (key !== 'constructor') {
    this[key] = this[key].bind(this);
  }
});

0
投票

我在传递一个承诺的捕获处理程序时收到此错误。

class foo {

   catchHandler(error){
     // do something with this
   }
  
   async myFunction(){
       let x = await somePromise.catch(this.catchHandler);
   }
}

我试图将 catchHandler-Function 绑定到

this
,但仍然收到错误。最终为我解决的问题不仅仅是将函数作为参数传递,而是使用箭头函数作为“包装器”:

class foo {

   constructor(){
     this.catchHandler.bind(this); // <--
   }

   catchHandler(error){
     // do something with this
   }
  
   async myFunction(){
      --> let x = await somePromise.catch(e => this.catchHandler(e)); // <--
   }
}

这可能对OP没有帮助,但是当您遇到问题标题中所述的问题时

© www.soinside.com 2019 - 2024. All rights reserved.