“ this”在 JavaScript 类方法中没有定义

我刚接触 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。我做错了什么?

150930 次浏览

如何调用 start 函数?

这应该可以(新的是关键)

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

If you directly call it like Request.prototype.start(), this will refer to the global context (window in browsers).

此外,如果 this未定义,则会导致错误。

Update: this object is not set based on declaration, but by 祈祷. What it means is that if you assign the function property to a variable like x = o.start and call x(), this inside start no longer refers to o. This is what happens when you do setTimeout. To make it work, do this instead:

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

JavaScript's OOP is a little funky (or a lot) and it takes some getting used to. This first thing you need to keep in mind is that 没有课程 and thinking in terms of classes can trip you up. And in order to use a method attached to a Constructor (the JavaScript equivalent of a Class definition) you need to instantiate your object. For example:

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只在构造函数被实例化时指向正确的对象(你的“ Class”)(否则它会指向浏览器中的全局对象 window)

在 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的作用域丢失了。在这种情况下,我建议将这样的函数绑定到 this。例如。

this.myFunction.bind(this);

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

我还遇到过 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


使用箭头功能:

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


}
};

以前的答案对我来说都没有完整的解决方案,所以把我的贴在这里。

我有一个类,当我在方法引用上运行 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))
}
}

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

const module = {
x: 42,
getX: function() {
return this.x;
}
};


const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined


const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42

如果一个函数被用作高阶函数(作为参数传递) ,那么 this的作用域就会丢失。

为了解决这个问题,我们可以像@Eliux 描述的那样将 this绑定到函数上:

this.myFunction.bind(this);

要像@DanielTonon 希望的那样自动化这个过程,可以在构造函数中完成:

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