最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - How does JavaScript assign context to this of event handlers? - Stack Overflow

programmeradmin0浏览0评论

After reading related questions #1 , #2 I still haven't found an answer to the following question:

Javascript can set context (i.e. set this) with: bind , call and apply.

But when I'm write an event handler:

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

Who/What actually attaches this to the object itself ?

P.S. When using jQuery's :

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

there is an internal implementation of (bind, call or apply)

So when I am not using jQuery, who is doing it?

After reading related questions #1 , #2 I still haven't found an answer to the following question:

Javascript can set context (i.e. set this) with: bind , call and apply.

But when I'm write an event handler:

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

Who/What actually attaches this to the object itself ?

P.S. When using jQuery's :

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

there is an internal implementation of (bind, call or apply)

So when I am not using jQuery, who is doing it?

Share Improve this question edited May 23, 2017 at 12:12 CommunityBot 11 silver badge asked Oct 4, 2012 at 7:58 Royi NamirRoyi Namir 149k144 gold badges491 silver badges829 bronze badges 5
  • 2 The DOM implementation is responsible for that IMO – wroniasty Commented Oct 4, 2012 at 8:02
  • 1 w3.org/TR/DOM-Level-3-Events/#event-type-click – wroniasty Commented Oct 4, 2012 at 8:04
  • @wroniasty can you reference me where is says there something about context&this ? in the table the context talks about the properties inside... – Royi Namir Commented Oct 4, 2012 at 8:07
  • @wroniasty, you took my words right out of my mouth, this is basically yet another "by definition" answer – Alexander Commented Oct 4, 2012 at 8:07
  • Your #1 and #2 both link to the same question. – Barmar Commented Oct 4, 2012 at 8:17
Add a comment  | 

7 Answers 7

Reset to default 9

Why, the DOM/JavaScript of course, it's supposed to work that way by W3C.

Event handlers are invoked in the context of a particular object (the current event target) and are provided with the event object itself.

Source

How exactly that happens, we don't know. It's an implementation detail.

All we know is, that the semantics as defined by the W3C are achieved in some way, but which part of the browser does that and and how, that is left up to the browser developers, and they can implement it as they see fit.

To sum up all the discussions:

  • In general it is JavaScript that binds this to o inside a function call, when o.x() is called.
  • However, there are some alternative methods of calling functions (like f.apply() and f.call()) that change this behaviour.
  • onclick is a special case, and the method used to invoke it is unknown and depends on the DOM implementation.

The answers saying it is the DOM are wrong.

This is part of JavaScript itself, as a language. The DOM is ONLY what the name indicates "Document Object Model", which is just how HTML is represented for manipulation by using JavaScript. Objects related to the DOM follow the behavior specified by the standards, but this is implemented by using JS for it. It is the JS engine what does this, in communication with whatever layout engine is being used (Gecko, Trident, WebKit, Presto, etc.). So, if WebKit detects an event, it passes it to the JS engine as the DOM specification indicates so that it can manipulated by the JS programmer (which is why you're even asking about this, because you can work with it).

In other words, if you're writing something in JavaScript, the only engine that understands how to read and execute that is the JS engine. This engine (v8, SpiderMonkey/Jugger/Trace) will receive data from the layout engine and use it so that you can interact with it. Similarly, on the other hand, whenever you run code that affects the layout, the changes will be detected by the layout engine and it will change the layout so that the user perceives the changes: even if the JS code might have initiated this, it is the layout engine that takes care of the layout.

What "this" is when you assign a function to an object, is simply wherever the function belongs to. So, if you assign a function to instance of object a, then said function will refer to a whenever you use "this" inside of it.

If you wanted to think of it in implementation terms, think of it this way: Whenever you are calling a method, you do so by first telling an instance that you want to call a method with N parameters. This instance calls the method but adds itself into the context, as "this".

In Python this is done more explicitly by making the first parameter of all instance methods the instance itself. Here it is the same, but the instance is passed implicitly instead of explicitly.

Remember, the instance owns the method. When you do "document.getElementById('something')" the call returns an object (which happens to be an HTMLElement object that is part of the DOM, but that's coincidental to how JS interacts with the DOM), and then you are assigning the function as the property click.

Then, whenever you call the method, the JavaScript engine passes the instance by default, just like it passes other variables (like arguments is also generated without you doing anything, also done by the JS engine which implements the ECMAScript standard).

I would recommend checking pages 63:

"The this keyword evaluates to the value of the ThisBinding of the current execution context."

but most importantly, page 68 "Function calls"

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

In your example, of an onclick handler it's perfectly straight forward: a DOM element is an object, you're defining the onclick property to be a function. That function effectively becomes a method of that DOMElement/object.
When that object is clicked, the function is called as a method of that element, so this points to its owner, the element.

Put simply, the context in which the function executes is the same as the context in which is was created (again: in your example as a method of a DOM Element), unless a reference to a function object is assigned to another object, or when that function object is invoked in another context using call or apply & co.
There's a little more to it than this, of course: as I hinted at above, functions are objects themselves and are said to be loosely coupled to their "owner". Well, actually they don't have an owner as such, each time a function is called, its context is determined:

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

As @wroniasty pointed out, my talking about ownership might be slightly confusing. The thing is, functions are objects, they're not owned by anything. When an object is assigned a method, all that object really owns is a reference to a given function object. When that function is called via that reference, this will point to the object that owned the calling reference.
When we apply that to your elem.onclick = function(){}, we see the element only owns a reference to a function expression that was declared in some scope (global, namespace-object, doesn't matter). When the click event fired, that reference will be used to call the handler, thus assigning a reference to the element to this. To clarify:

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

So the handler was declared in the global context, and the handler can access its the context it was declared in using that, thanks to closures (but that's another story). The point is, the event references the handler using the onclick property of the element foo. That property is a reference to a function object, so the function object sets its context to whatever object made the call.

I do hope this clears up any confusion I caused with regard to ownership of functions, and perhaps how context in JS is determined.

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

Basically, it's done by JavaScript internals.

The context is the object calling the function, e.g.

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

However:

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

This really has nothing to do with the DOM as has been mentioned, but how JavaScript is designed to work when you call a function within an object.

Take this as an example:

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

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

Calling myObject.onclick() will log 1 to the console, which means myObject is its context.

Since onclick is also a property of an object, this will be the parent object, in your case an HTMLElement.

For illustration purposes, although implementations may differ, think of the following function

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

as

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

Imagine this as a secret parameter that you can override with bind, apply and call but that normally gets set to the calling object by the browser.

Example

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;

When calling the printName function the browser sets that "secret" this parameter to the calling function. In the example below this is b and so "Tom" is printed to the console.

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

Further info here.

发布评论

评论列表(0)

  1. 暂无评论