'this' - undefined в методах класса 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 omitted
Проблема в Request.prototype.start
, this
равна undefined, и поэтому оператор if вычисляет false. Что я здесь делаю неправильно?
Ответы
Ответ 1
Как вы вызываете функцию запуска?
Это должно работать ( новый - это ключ)
var o = new Request(destination, stay_open);
o.start();
Если вы вызываете его как Request.prototype.start()
, this
будет ссылаться на глобальный контекст (window
в браузерах).
Кроме того, если this
- undefined, это приводит к ошибке. Значение if не оценивается как false.
Обновить: this
объект не задан на основе объявления, а вызовом. Это означает, что если вы присваиваете свойство функции переменной типа x = o.start
и вызываете x()
, this
внутри начала больше не ссылается на o
. Это происходит, когда вы делаете setTimeout
. Чтобы заставить его работать, сделайте следующее:
var o = new Request(...);
setTimeout(function() { o.start(); }, 1000);
Ответ 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 a.k.a 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
.