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

StackOverflow https://stackoverflow.com/questions/4820163

  •  26-10-2019
  •  | 
  •  

Вопрос

Я пытаюсь вызвать функцию внутри созданного мной литерала объекта, используя метод 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!');

  }
}

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

Это было полезно?

Решение

Объяснение того, что происходит. Ответ Поинти хорош, но я хочу объяснить это более общим. Очень хорошее исследование на 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's 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 Активно называется обработчиком событий this объект точек в объекте DOM, который вызвал событие, поэтому ваше призвание node.doTheMove который до сих пор не существует.

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

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

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

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

Другие советы

Вам нужно изменить способ настройки:

window.onload = function(){

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

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

}

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

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

window.onload = function(){

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

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

}

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

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

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

    }
};

Вы можете использовать базовый подход портотипа:

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

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

Я склонен писать код с использованием литеральных объектов внутри самоопределяемых функций, и исходный опубликованный вопрос работает нормально, если вместе с оператором 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);
        }
    })();

})();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top