Подтвердить что ты не робот

Вызов функции в объявлении нотации литерала объекта javascript

Я пытаюсь вызвать функцию внутри литерала объекта, который я создал, используя ключевое слово this. Но появляется сообщение об ошибке: this.doTheMove() не является функцией:

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', Animation.init, false);

}

var Animation = {
  init: function(){

     this.doTheMove(); // I'm calling the function here, but it gives an error.

  },
  doTheMove: function(){

    alert('Animation!');

  }
}

Почему возникает ошибка?

4b9b3361

Ответ 1

Объяснение того, что происходит. Настойный ответ хорош, но я хочу объяснить его более общее. Очень хорошее исследование this можно найти здесь

Обработчик событий - это просто обратный вызов. Вы передаете ему функцию и событие для прослушивания. В целом все, что он будет делать, это вызов этой функции.

Animation.init - это просто получатель этой функции. Подумайте об этом так:

var callback = Animation.init
animBtn.addEventListener('click', callback, false);
...
// internal browser event handler
handler() {
   // internal handler does stuff
   ...
   // Oh click event happened. Let call that callback
   callback();
}

Итак, все, что вы сделали, передано в

var callback = function(){
   this.doTheMove(); // I'm calling the function here, but it gives an error.
}

По умолчанию в javascript this === window. Это будет относиться к глобальному объекту, если он не настроен на что-то. Чистый эффект заключается в том, что вызывается window.doTheMove. И эта функция не существует.

В этом случае, поскольку callback actaully вызывает обработчик события, объект this указывает на объект DOM, который вызвал событие, поэтому ваш вызов node.doTheMove, который все еще не существует.

Что вы хотели сделать, это обернуть его ссылкой на анимацию.

var callback = function() {
    Animation.init();
}

Это выполнение функции и выполняется init на Animation. Когда вы выполняете его на таком объекте, а затем внутренне this === Animation, как и следовало ожидать.

Подводя итог. Проблема здесь в том, что Animation.init - это просто ссылка на функцию. У него нет никакой информации о чем-либо еще, как упоминается Уолли.

Ответ 2

Вы должны изменить способ установки:

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', function() { Animation.init(); }, false);

}

В JavaScript факт, что функция, по-видимому, определяется как часть литерала объекта, на самом деле не означает очень много (если вообще что-то). Ссылка на Animation.init приведет вас к правильной функции, но проблема в том, что когда функция будет вызываться позже (в ответ на фактический "click"), браузер вызывает функцию, но не имеет понятия, что объект "Анимация" msgstr "должно быть ссылкой this. Опять же, тот факт, что функция была объявлена ​​как часть объекта, вообще не имеет значения. Поэтому, если вы хотите, чтобы this был чем-то конкретным по своему усмотрению, вы должны убедиться, что он явно установлен в управляемом вами коде. Вышеупомянутое решение касается простейшего способа сделать это: оно обрабатывает события "click" с анонимной функцией, которая ничего не делает, кроме вызова функции" init" через явную ссылку через "Анимация". Это гарантирует, что this относится к объекту "Анимация", когда выполняется "init".

Другой альтернативой может быть использование функции ".bind()", которую поддерживают некоторые браузеры и фреймворки:

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', Animation.init.bind(Animation); }, false);

}

Сетевой эффект почти то же самое: вызов в .bind() возвращает функцию, вызывающую функцию, на которую он был вызван (являющийся функцией "init" в объекте "Анимация" ), и делает это с его первым аргументом как ссылка this (объект "контекст" ). Это то же самое, что мы получаем из первого примера, или фактически все равно.

Ответ 3

Вот еще один хороший подход, я думаю.

window.onload = function(){

  var animBtn = document.getElementById('startAnim');

  animBtn.addEventListener('click', Animation.init, false);

};

var Animation = {
    init: function(){

        Animation.doTheMove(); // This will work, but your IDE may complain...

    },
    doTheMove: function(){

        alert('Animation!');

    }
};

Ответ 4

Возможно, вы захотите использовать базовый подход к каталогу:

// generate a prototype object which can be instantiated
var Animation = function() { this.doTheMove(); }
Animation.prototype.doTheMove = function() {
    // if the object has only one method, the whole code could be moved to 
    // var Animation = function() {...} above
    alert('Animation!'); 
}

Animation.prototype.otherMethod = function(param1, param2) {
  // ...
}


// run the code onload
window.onload = function(){
  var animBtn = document.getElementById('startAnim');
  animBtn.addEventListener('click', new Animation(), false);
}

Ответ 5

Шесть с половиной лет спустя, но я надеюсь, что мой ответ также может дать некоторое представление о нынешних и будущих разработчиках.

Я склонен кодировать, используя литеральные объекты внутри самостоятельно определенных функций, и исходный вопрос, который вы опубликовали, отлично работает, если добавлена ​​еще одна функция самоисполнения вместе с инструкцией try и catch.

Очень важно отметить, что все это касается области и контекста.

Просьба исправить любые недостатки или предоставить более эффективные рекомендации по использованию этого метода.

(function() {

console.log(this);  // window object

    var animation = {
        init: function() {
            this.doTheMove();
        },
        doTheMove: function() {
            alert("Animation");
            console.log(animation); // animation object
        }
    };

    (function() {
        try {
            console.log("animation.init"); // animation.init function
            animation.init();
        } catch(e) {
            console.log("Error is: " + e);
        }
    })();

})();