Вызов функции в объявлении литеральной нотации объекта javascript
-
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);
}
})();
})();