Я новичок в 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
не определено и , таким образом, если Равняется заявление к ложным. Что я здесь делаю не так?
javascript
class
prototype
Карсон Майерс
источник
источник
start
вprototype
?Request.prototype
настроено?this
в JavaScript нет постоянной ссылки на «владельца» вызываемой прототипной функции, как это было бы в большинстве объектно-ориентированных языков, таких как Java.new Object()
. Все, что вы добавляете к нему, автоматически становится свойствами объектов, созданных с помощьюnew Request()
.Request.prototype
- это то место, откудаRequest
наследуются экземпляры . В данном случае это, вероятно,Function
илиObject
.Ответы:
Как вы вызываете функцию запуска?
Это должно работать ( новое - это ключ)
var o = new Request(destination, stay_open); o.start();
Если вы прямо назовете его like
Request.prototype.start()
,this
будет ссылаться на глобальный контекст (window
в браузерах).Кроме того, если
this
не определено, это приведет к ошибке. Выражение if не возвращает false.Обновление :
this
объект устанавливается не на основе объявления, а путем вызова . Это означает, что если вы присваиваете свойство функции переменной, такой какx = o.start
и callx()
,this
внутри start больше не ссылается наo
. Вот что происходит, когда вы это делаетеsetTimeout
. Чтобы заставить его работать, сделайте следующее:var o = new Request(...); setTimeout(function() { o.start(); }, 1000);
источник
var listen = new Request(destination, stay_open); setTimeout(listen.start, 500);
o.start.bind(o)
. Почему неx = o.start; x()
работает?.bind()
возвращает новую функцию, не работающую на месте. Так что тебе придется делатьx = o.start.bind(o); x()
илиo.start = o.start.bind(o); x=o.start; x()
Я просто хотел указать, что иногда эта ошибка возникает из-за того, что функция использовалась как функция высокого порядка (передана в качестве аргумента), а затем область видимости
this
терялась. В таких случаях я бы рекомендовал передать такую функцию привязанной кthis
. Напримерthis.myFunction.bind(this);
источник
this
теряется размах ?ООП в JavaScript немного напуган (или сильно), и к нему нужно привыкнуть. Первое, что вам нужно иметь в виду, это то, что классов нет, и мышление в терминах классов может сбить вас с толку. А чтобы использовать метод, прикрепленный к конструктору (эквивалент определения класса в 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
создается экземпляр Конструктора (в противном случае он указывает на глобальный объект в браузере)источник
В 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
.источник
render
вызывается, а не один раз при создании экземпляра класса. Кроме того, большая часть вашего примера не имеет отношения к вопросу.handleChange()
На этот вопрос был дан ответ, но, возможно, сюда придет кто-то другой.
У меня также была проблема с
this
undefined, когда я глупо пытался деструктурировать методы класса при его инициализации: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 { } };
источник