Как JavaScript назначает контекст этому обработчику событий?

после прочтения вопросы #1 , #2 Я до сих пор не нашел ответа на следующий вопрос:

Javascript может устанавливать контекст (т. е. set this) С: bind , call и apply.

но когда я пишу обработчик события:

document.getElementById('myInput').onclick = function ()
                                                   {
                                                      alert(this.value)
                                                   }

Кто/Что на самом деле придает this до ?

П. С. При использовании в jQuery :

  $("#myInput").bind(function (){...})

здесь и внутренняя реализация (bind, call или apply)

так когда я не используя jQuery, кто это делает?

7 ответов


Почему, DOM / JavaScript, конечно, он должен работать таким образом с помощью W3C.

обработчики событий вызываются в контекст определенного объекта (текущей цели события) и предоставляются с самим объектом события.

источник

Как именно это происходит, мы не знаем. Это деталь реализации.

все, что мы знаем, это то, что семантика, определенная W3C, достигается в способ, но какая часть браузера делает это и как, это остается до разработчиков браузера, и они могут реализовать его по своему усмотрению.


чтобы подвести итог всем обсуждениям:

  • в общем-это JavaScript, который связывает this до o внутри вызова функции, когда o.x() называется.
  • однако существуют некоторые альтернативные методы вызова функций (например,f.apply() и f.call()), что изменить это поведение.
  • onclick является частным случаем, и метод, используемый для его вызова, неизвестен и зависит от реализации DOM.

ответы, говорящие, что это DOM, неверны.

Это часть самого JavaScript, как язык. DOM-это только то, что имя указывает на "объектную модель документа", которая представляет HTML для манипулирования с помощью JavaScript. Объекты, связанные с DOM, следуют поведению, указанному стандартами, но это реализуется с помощью JS для него. Это движок JS, который делает это, в связи с тем, какой движок макета используется (Gecko, Trident, WebKit, Presto и др.). Таким образом, если WebKit обнаруживает событие, он передает его движку JS, как указывает спецификация DOM, чтобы он мог манипулировать программистом JS (поэтому вы даже спрашиваете об этом, потому что вы можете работать с ним).

другими словами, если вы пишете что-то на JavaScript, единственным движком, который понимает, как читать и выполнять, является движок JS. Этот движок (v8, SpiderMonkey/Jugger/Trace) будет получать данные от движка макета и использовать его таким образом что вы можете взаимодействовать с ним. Аналогично, с другой стороны, всякий раз, когда вы запускаете код, который влияет на макет, изменения будут обнаружены механизмом макета, и он изменит макет, чтобы пользователь воспринимал изменения: даже если код JS мог инициировать это, это механизм макета, который заботится о макете.

Что такое "это", когда вы назначаете функцию объекту, просто там, где принадлежит функция. Итак, если вы назначаете функцию экземпляру object a, затем указанная функция будет ссылаться на A всякий раз, когда вы используете "это" внутри нее.

Если вы хотите думать об этом в терминах реализации, подумайте об этом таким образом: Всякий раз, когда вы вызываете метод, вы делаете это, сначала сообщая экземпляру, что хотите вызвать метод с N параметрами. Этот экземпляр вызывает метод, но добавляет себя в контекст, как "это".

в Python это делается более явно, делая первый параметр всех методов экземпляра экземпляром себя. Здесь это то же самое, но экземпляр передается неявно, а не явно.

помните, что экземпляр принадлежит метод. Когда вы делаете документ".getElementById ('something')" вызов возвращает объект (который является объектом HTMLElement, который является частью DOM, но это совпадает с тем, как JS взаимодействует с DOM), а затем вы назначаете функцию как свойство click.

затем, всякий раз, когда вы вызываете метод, механизм JavaScript проходит экземпляр по умолчанию, как и другие переменные (например, аргументы также генерируются без каких-либо действий, также выполняемых движком JS, который реализует стандарт ECMAScript).

Я бы рекомендовал проверить страницы 63:

" ключевое слово this вычисляет значение ThisBinding текущего контекста выполнения."

но самое главное, страница 68 " вызовы функций"

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf


в вашем примере, о onclick обработчик это совершенно прямо вперед: элемент DOM is объект, вы определяете onclick свойства функция. Эта функция эффективно становится методом этого DOMElement / object.
когда этот объект нажат, функция вызывается как метод этого элемента, поэтому это указывает на его владелец элемент.

проще говоря, контекст, в котором выполняется функция, совпадает с контекст, в котором был создан is (опять же: в вашем примере как метод элемента DOM), если только ссылка на функцию объект присваивается другому объекту, или когда функция объект вызывается в другом контексте, используя call или apply & co.
конечно, есть немного больше, чем это: как я намекнул выше, функции сами по себе являются объектами и, как говорят, являются свободно в сочетании с их "владелец". Что ж, на самом деле у них нет владельца как такового, каждый раз, когда вызывается функция, определяется ее контекст:

var foo = someObject.someFunction;//reference to method
someObject.someFunction();//this === someObject, context is the object preceding the function
foo();//implies [window].foo(); ==> this is window, except for strict mode

как отметил @wroniasty, Мой разговор о собственности может быть немного запутанной. Дело в том, что функции-это объекты, они ничем не принадлежат. Когда объекту присваивается метод, весь этот объект действительно принадлежит - это ссылка на объект функции. Когда эта функция вызывается через эту ссылку,this будет указывать на объект, которому принадлежала вызывающая ссылка.
когда мы применяем это к вашему elem.onclick = function(){} мы видим только элемент принадлежит ссылка на выражение функции, объявленное в некоторой области (global, namespace-object, не имеет значения). Когда событие click сработало, это ссылка будет использоваться для вызова обработчика, таким образом, присваивая ссылку на элемент this. Чтобы уточнить:

document.getElementById('foo').onclick = (function()
{//This function returns the actual handler
    var that = this;//closure var
    console.log(this);//logs window object
    //defined in global context
    return function(e)//actual handler
    {
        console.log(this === that);//false
        console.log(this);//elem
        console.log(that);//window
    };
})();//IIFE

чтобы обработчик был объявлен в глобальном контексте, и обработчик может получить доступ к контексту, который он был объявлен в using that благодаря замыканий (но это другая история). Дело в том, что событие ссылается на обработчик, используя onclick свойство элемента foo. Это свойство является ссылкой на объект function, поэтому объект function устанавливает свой контекст для любого объекта, сделавшего вызов.

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


http://dmitrysoshnikov.com/ecmascript/chapter-3-this/#this-value-in-the-function-code

в основном, это делается внутренними JavaScript.

контекст-это объект, вызывающий функцию, например

elem.onclick();  // elem === this

однако:

func = elem.onclick;
func() // global === this

это действительно не имеет ничего общего с DOM, как уже упоминалось, но как JavaScript предназначен для работы при вызове функции внутри объекта.

возьмите это в качестве примера:

var myObject = {
    id: 1,
    onclick: null
}

myObject.onclick = function() {
    console.log(this.id);
}

вызов myObject.onclick() будет log 1 в консоли, что означает myObject - это его контекст.

С onclick также является свойством объекта,this будет родительским объектом, в вашем случае HTMLElement.


для иллюстрации, хотя реализации могут отличаться, подумайте о следующей функции

 function f() { alert(this.name); } 

as

function f(this) { alert(this.name); } 

представьте себе,этой в качестве секретного параметра, который можно переопределить с помощью bind, apply и call, но который обычно устанавливается в вызывающий объект браузером.

пример

var a = {},
    b = {};

a.name = "John";
b.name = "Tom";

// "this" param added secretly
function printName( ) { 
    console.log( this.name ) 
};

a.printName = printName     
b.printName = printName;

при вызове функции printName браузер устанавливает, что "секрет" этой параметр для вызова функция. В приведенном ниже примере это b, и поэтому" Tom " печатается на консоли.

printName( ); // global context assumed so this === window
b.printName( ); // this === b and outputs "Tom"
printName.call( a ); //this === a and outputs "John"

дополнительная информация здесь.