OnClick Function "this" Возвращает объект Window
Я столкнулся с проблемой царапин в моем приложении JavaScript.
Если я напишу такой элемент:
<li onClick="alert(this.tagName)"></li>
Я получаю "LI".
Однако, если я это сделаю:
<li onClick="foo()"></li>
Где "foo()":
function foo(){ alert(this.tagName); }
Я получаю "undefined."
Я прочь, как "this" должен работать в отношении прикрепленных функций. Но я сбив с толку, потому что "this" не подбирает элемент, но, по-видимому, по умолчанию "окно". Я не могу понять, почему это происходит.
Есть ли у кого есть объяснение?
Ответы
Ответ 1
Это потому, что вы не передаете ссылку на это в вызове функции JavaScript. это в функции JavaScript не относится к тому же объекту, что и в примере onClick. Вместо этого попробуйте:
<li onClick="foo(this)"></li>
function foo(item){ alert(item.tagName); }
Ответ 2
В встроенном прослушивателе:
> <li onClick="alert(this.tagName)"></li>
Значение атрибута onclick эффективно заверяется в функцию и вызывается с установленным в нем элементом, например
function anon() {
/* attribute value */
}
anon.call(element);
Когда вы помещаете функцию в тело, вы получаете:
function anon() {
foo();
}
Здесь this
внутри anon
будет элементом, но поскольку foo
вызывается без установки this
, он будет undefined. В нестрогом режиме this
по умолчанию будет глобальным объектом (window
в браузере). В строгом режиме this
внутри foo
будет undefined.
Одним из решений является передача ссылки на элемент:
<li onclick="foo(this)" ... >
то в функции:
function foo(callingElement) {
...
}
или даже:
<li onclick="foo.call(this)" ... >
function foo() {
var callingElement = this;
}
Ответ 3
Как уже упоминаются другие ответы, значение this
будет зависеть от того, как вызывается функция, содержащая его. Но поскольку ваш пример посвящен обработчикам событий, я хотел бы подчеркнуть, что cjc343 сказал в комментариях:
Вы можете найти более разумным, если удалить обработчики событий inline.
Это довольно просто, на самом деле. Учитывая этот HTML:
<ul id="list">
<li id="item1">item 1</li>
<li id="item2">item 2</li>
<li id="item3">item 3</li>
</ul>
Следующий JavaScript будет учитывать как удаление встроенных обработчиков, так и использование делегирования:
var list = document.getElementById('list');
list.addEventListener('click', function(evt){
console.log("this is the element the event is bound to: " + this.id);
console.log("the event target is the clicked element: " + evt.target.id);
});
http://jsfiddle.net/J3Gje/
Это будет работать на всех браузерах, совместимых с моделью событий W3C, включая IE9. Для более старого IE вы должны использовать attachEvent
вместо addEventListener
и добавлять имена событий в "on"
. Подробнее здесь.
Ответ 4
Другой вариант, поэтому вам не нужно передавать этот как параметр, использовать call или apply. Это встроенный механизм для установки значения этого внутри функции. Хотя я бы отметил, добавление обработчиков событий непосредственно к вашему html немного устарело. Вы можете проверить структуру JS для делегирования событий (jQuery, Prototype, Dojo, YUI и т.д.).
скрипт: http://jsfiddle.net/bboone/Q2CkV/2/
HTML
<div onClick='alert(this.tagName);'>test</div>
<div onClick='foo.call(this);'>test2</div>
JS
function foo(){ alert(this.tagName); }
Ответ 5
Если вы новичок в JavaScript, не используйте ключевое слово this
или new
, потому что либо вы ошибетесь, либо ваш код будет излишне неэффективным и более сложным. То, что вы пытаетесь выполнить, заключается в следующем:
<li onclick="foo(this)">some text</li>
В этом примере событие click этого элемента списка запускает функцию с именем foo. Ключевое слово this
передается как переменная. Ключевое слово this
просто относится к сущности, которая вызвала эту функцию, и если она не может найти этот объект, она будет ссылаться на объект window
браузера. В этом случае объект, который вызвал функцию, является элементом списка node из DOM.
Я по-прежнему предлагаю никогда не использовать ключевое слово this
, чтобы избежать такого путаницы, продвигающегося вперед.
EDIT: Кроме того, не используйте свойство tagName, поскольку оно не является стандартным. Вместо этого используйте свойство nodeName
.