Reference to object not same as the object? - javascript

Why this works:
var i = document.createElement("input");
document.body.appendChid(i);
But not this:
var i = document.createElement("input");
var f = document.body.appendChild;
console.log(f === document.body.appendChild); //outputs true
f(i);
And the error details is:
TypeError: 'appendChild' called on an object that does not implement interface Node.

In JavaScript, what looks like a "method" doesn't actually "know" what object it's attached to; essentially, it's just a function which happens to have been saved as a property of some object. The determination of what object this will represent happens when you call it, in most circumstances based on the object to the left of the . in the call.
So your variable f points at the right function, but when it's called, it will see the wrong value of this. Since in this case it expects to be called on a DOM Node (in the working test, document.body), calling it outside of that scope raises the error shown.
Note that the above is all slightly simplified, with just enough detail to explain your example. You can probably find further reading by searching for explanations of this as well as call and apply, which are ways of explicitly setting the this binding of a function call.

Related

Function assignment doesn't work

I'm new to Node.js. I have searched the forum but couldn't find a similar question. Here is the problem I encountered. The following code runs fine.
process.stdout.write("hello world!\n");
but the following code:
var myprint = process.stdout.write;
myprint("hello world");
will generate the following error:
TypeError: Cannot read property 'defaultEncoding' of undefined
Any suggestions? Thank you so much.
Probably, the write() method needs to be called with the correct object reference so the write() method knows what stream it is writing to. There are multiple ways to work around this. Here's one way:
var myprint = process.stdout.write.bind(process.stdout);
myprint("hello world");
See .bind() on MDN for more info.
For future reference, when you do:
var myprint = process.stdout.write;
myprint only contains a reference to the write method and that method is then called with no object reference. That means that the this pointer inside the write() method will not point at the stdout stream like it would when you call it as process.stdout.write(). If a method needs it's instance data (which most methods do), then this creates a problem. You can "bind" the object reference to a new temporary function using .bind() which allows you to assign it to another variable and then use it directly like you were attempting to do.
The write function is trying to access a variable on the this variable, which is not set to process.stdout when you call myprint, unlike when you call process.stdout.write.
Note that
var out = process.stdout;
out.print('wow\n');
will work as expected.

Can you get the property name through which a function was called?

I've done a lot of searching and some playing around, and I'm pretty sure the answer to this question is no, but I'm hoping a JavaScript expert might have a trick up his sleeve that can do this.
A JavaScript function can be referenced by multiple properties, even on completely different objects, so there's no such thing as the object or property that holds the function. But any time you actually call a function, you must have done so via a single object (at the very least, the window object for global function calls) and property on that object.
(A function can also be called via a function-local variable, but we can consider the function-local variable to be a property of the activation object of the scope, so that case is not an exception to this rule.)
My question is, is there a way to get that property name that was used to call the function, from inside the function body? I don't want to pass in the property name as an argument, or closure around a variable in an enclosing scope, or store the name as a separate property on the object that holds the function reference and have the function access that name property on the this object.
Here's an example of what I want to do:
var callName1 = function() { var callName = /* some magic */; alert(callName); };
var obj1 = {'callName2':callName1, 'callName3':callName1 };
var obj2 = {'callName4':callName1, 'callName5':callName1 };
callName1(); // should alert 'callName1'
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'
From my searching, it looks like the closest you can get to the above is arguments.callee.name, but that won't work, because that only returns the name that was fixed to the function object when it was defined, and only if it was defined as a named function (which the function in my example is not).
I also considered that maybe you could iterate over all properties of the this object and test for equality with arguments.callee to find the property whose value is a reference to the function itself, but that won't work either (in the general case), because there could be multiple references to the function in the object's own (or inherited) property set, as in my example. (Also, that seems like it would be kind of an inefficient solution.)
Can this be done?
Short answer:
No, you cannot get "the property name" used to call your function.
There may be no name at all, or multiple names across different scopes, so "the property name" is pretty ill defined.
arguments.callee is deprecated and should not be used.
There exists no solution that does not use arguments or closure.
Long answer:
As thefourtheye commented, you should rethink what you are trying to do and ask that instead in a new question. But there are some common misconceptions, so I will try to explain why you cannot get the "simple property name".
The reason is because it is not simple.
Before we go ahead, let us clarify something. Activation Objects are not objects at all.
The ECMAScript 5.1 specification calls them Environment Records (10.2.1), but a more common term is Scope chain.
In a browser the global scope is (often) the window object, but all other scopes are not objects.
There may be an object that you use to call a function, and when you call a function you must be in some scope.
With few exceptions, scopes are not objects, and objects are not scopes.
Then, there are many names.
When you call a function, you need to reference it, such as through an object property. This reference may have a name.
Scope chain has declarations, which always have a name.
A Function (the real function, not reference) may also have a function name - your arguments.callee.name - which is fixed at declaration.
Not only are they different names, they are not (always) the "the property name" you are seeking.
var obj = { prop : function f(){} }, func = obj.prop;
// "obj" and "func" are declarations.
// Function name is "f" - use this name instead of arguments.callee
// Property name is "prop"
func(); // Reference name is "func"
obj.prop(); // Reference names are "obj" and "prop"
// But they are the same function!
// P.S. "this" in f is undefined (strict mode) or window (non-strict)
So, a function reference may comes from a binding (e.g. function declaration), an Object (arguments.callee), or a variable.
They are all References (8.7). And reference does have a name (so to speak).
The catch is, a function reference does not always come from an object or the scope chain, and its name is not always defined.
For example a common closure technique:
(function(i){ /* what is my name? */ })(i)
Even if the reference does have a name, a function call (11.2.3) does not pass the reference or its name to the function in any way.
Which keeps the JavaScript engine sane. Consider this example:
eval("(new Function('return function a(){}'))()")() // Calls function 'a'.
The final function call refers the eval function, which refers the result of a new global scope (in strict mode, anyway), which refers a function call statement, which refers a group, which refers an anonymous Function object, and which contains code that expresses and returns a function called 'a'.
If you want to get the "property name" from within a, which one should it get? "eval"? "Function"? "anonymous"? "a"? All of them?
Before you answer, consider complications such as function access across iframes, which has different globals as well as cross origin restriction, or interaction with native functions (Function.prototype.bind for example), and you will see how it quickly becomes hell.
This is also why arguments.caller, __caller__, and other similar techniques are now all deprecated.
The "property name" of a function is even more ill defined than the caller, almost unrealistic.
At least caller is always an execution context (not necessary a function).
So, not knowing what your real problem is, the best bet of getting the "property name" is using closure.
there is no reflection, but you can use function behavior to make adding your own fairly painless, and without resorting to try/catch, arguments.callee, Function.caller, or other strongly frowned-upon behavior, just wasteful looping:
// returning a function from inside a function always creates a new, unique function we can self-identify later:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//the one ugly about this is the extra "()" at the end:
var obj1 = {'callName2':callName(), 'callName3':callName() };
var obj2 = {'callName4':callName(), 'callName5':callName() };
//test out the tattle-tale function:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
if you REALLY want to make it look like an assignment and avoid the execution parens each time in the object literal, you can do this hacky routine to create an invoking alias:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//make an alias to execute a function each time it's used :
Object.defineProperty(window, 'callNamer', {get: function(){ return callName() }});
//use the alias to assign a tattle-tale function (look ma, no parens!):
var obj1 = {'callName2': callNamer, 'callName3': callNamer };
var obj2 = {'callName4': callNamer, 'callName5': callNamer };
//try it out:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
all that aside, you can probably accomplish what you need to do without all the looping required by this approach.
Advantages:
works on globals or object properties
requires no repetitive key/name passing
uses no proprietary or deprecated features
does not use arguments or closure
surrounding code executes faster (optimized) than
a try/catch version
is not confused by repeated uses
can handle new and deleted (renamed) properties
Caveats:
doesn't work on private vars, which have no property name
partially loops owner object each access
slower computation than a memorized property or code-time repetition
won't survive call/bind/apply
wont survive a setTimeout without bind() or a wrapper function
cannot easily be cloned
honestly, i think all the ways of accomplishing this task are "less than ideal", to be polite, and i would recommend you just bite the coding bullet and pass extra key names, or automate that by using a method to add properties to a blank object instead of coding it all in an object literal.
Yes.
Sort Of.
It depends on the browser. (Chrome=OK, Firefox=Nope)
You can use a factory to create the function, and a call stack parsing hack that will probably get me arrested.
This solution works in my version of Chrome on Windows 7, but the approach could be adapted to other browsers (if they support stack and show the property name in the call stack like Chrome does). I would not recommend doing this in production code as it is a pretty brittle hack; instead improve the architecture of your program so that you do not need to rely on knowing the name of the calling property. You didn't post details about your problem domain so this is just a fun little thought experiment; to wit:
JSFiddle demo: http://jsfiddle.net/tv9m36fr/
Runnable snippet: (scroll down and click Run code snippet)
function getCallerName(ex) {
// parse the call stack to find name of caller; assumes called from object property
// todo: replace with regex (left as exercise for the reader)
// this works in chrome on win7. other browsers may format differently(?) but not tested.
// easy enough to extend this concept to be browser-specific if rules are known.
// this is only for educational purposes; I would not do this in production code.
var stack = ex.stack.toString();
var idx = stack.indexOf('\n');
var lines = ex.stack.substring(idx + 1);
var objectSentinel = 'Object.';
idx = lines.indexOf(objectSentinel);
var line = lines.substring(idx + objectSentinel.length);
idx = line.indexOf(' ');
var callerName = line.substring(0, idx);
return callerName;
}
var Factory = {
getFunction: function () {
return function () {
var callName = "";
try {
throw up; // you don't *have* to throw to get stack trace, but it's more fun!
} catch (ex) {
callName = getCallerName(ex);
}
alert(callName);
};
}
}
var obj1 = {
'callName2': Factory.getFunction(),
'callName3': Factory.getFunction()
};
var obj2 = {
'callName4': Factory.getFunction(),
'callName5': Factory.getFunction()
};
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'

confusion about the 'this' keyword in Javascript

I can claim that 'this' keyword is the most confusing part of Javascript for those who comes from languages like C#.
I have read a lot about this on the internet and on StackOverflow too. like here and here.
I know that 'this' keyword will be bound to the context. and in constructor function it will be bound to the object being created, and when there is no immediate context it will bound to global object (i.e window)
I know all that , however confusion is still not fully cleared; So the best way to understand is by testing codes.
So I decided to write small code and I was surprised by how much convoluted the this keyword.
here is the code i tested:
function sayHi(name){
var tt = name;
return {
ss: tt,
work: function(anotherName){
alert ("hiiiii " + anotherName);
}
};
}
//this method invocation has no effect at all right now
sayHi("John");
var hi2 = new sayHi("wallace");
hi2.work("May");
alert(hi2.ss);
as expected the alert window will show (Hiiiiii May ) then ( wallace). Notice now that the line sayHi("John"); has no effect at all.
and Now the confusion will start when I change one thing ONLY (change var tt => this.tt):
function sayHi(name){
//this is the ONLY change I did.
this.tt = name;
return {
ss: tt,
work: function(anotherName){
alert ("hiiiii " + anotherName);
}
};
}
// Now this line invocation will be problematic
sayHi("John");
var hi2 = new sayHi("wallace");
hi2.work("May");
alert(hi2.ss);
the result surprised me when the alert mthod gave ( Hiiiiiii May ) and then (John) not (wallace);
so I had the idea to comment the line sayHi("John"); but that resulted in the whole code being no-functional and not working.
the demo is here
I know this might be newbee question. But it is really confusing here and I did try to read many articles and SO questions but i m missing this point.
Why does the line sayHi("John"); setting the hi2.ss to John?? and why does it break the code when we delete it ; although we invoke the sayHi method by using the new keyword afterward ??
Because you assign the parameter "name" to a property of the object referenced by this (which in this case will be window), your subsequent reference to "tt" in that object literal will be to the "tt" property of the global object, since that's the next enclosing scope.
Your first call to "sayHi" is made without the new operator, so in that call this will refer to the global object (window). The first line in the second version
this.tt = name;
therefore will set window.tt to "John".
The next call is made with the new operator. Because of that, this in the function refers to the newly-instantiated object. The line
this.tt = name;
will therefore really have no net effect on anything, because the function returns a different object in all cases. The last line of your test:
alert(hi2.ss);
says "John" because that's what's in window.tt. Why does that matter? Because "sayHi" returns an object with a property ("ss") set from the value of the symbol "tt". The only "tt" in scope will be window.tt, which was set back in the first call to the function.
When you first invoke sayHi("John");, this will point to the global object window. That means this.tt = name actually creates a global tt variable.
Then when you invoke new sayHi("wallace");, this correctly points to a new instance of sayHi, but you are returning another object instead of letting new naturally return the instance.
If you carefully look at your object literal, you define ss like ss: tt,. Since you aren't using this.tt and there is no tt symbol found in the constructor's scope, the value will then be resolved as a global variable (which was previously set to John).
When invoking a constructor function, if no return statement exists in the function then this is implicitly returned otherwise the return value is returned and this is simply ignored.
In your second example you are saving the name argument as this.tt but returning a different object. That's why things aren't working. Basically use this or return a custom object, but don't do both.

Why does setting a variable (outside of the object scope) equal to an object method return an undefined result?

The code below was copied and pasted from the MDN page on OOP with JavaScript. I have researched general questions on OOP with JavaScript. However, I'm a beginner and have the following questions about this code snippet:
What is the purpose of the line Person.prototype.gender = '';? If I take it out and run the code, I get the same results.
Why exactly does calling genderTeller() cause an 'undefined' alert? The MDN explanation seems a bit thin from a beginner's perspective. Is this a scope issue?
function Person(gender) {
this.gender = gender;
}
Person.prototype.gender = '';
Person.prototype.sayGender = function () {
alert(this.gender);
};
var person1 = new Person('Male');
var genderTeller = person1.sayGender;
person1.sayGender(); // alerts 'Male'
genderTeller(); // alerts undefined
alert(genderTeller === person1.sayGender); // alerts true
alert(genderTeller === Person.prototype.sayGender); // alerts true
What is the purpose of the line Person.prototype.gender = '';? If I take it out and run the code, I get the same results.
This seems to establish a default value for the gender property. With it, the property is still set even when an instance is created without calling the constructor:
var person2 = Object.create(Person.prototype);
console.log(person2.gender); // ""
Which could be useful when creating a child type:
function Employee() {}
Employee.prototype = Object.create(Person.prototype);
console.log(new Employee().gender); // ""
Why exactly does calling genderTeller() cause an 'undefined' alert?
MDN's document on this should explain it further, especially the section on "Function context." But, the value of this is determined when a function is called rather than by when or where it's defined.
By assigning person1.sayGender to genderTeller, it's being disassociated from person1. So, it's no longer a "method" of a particular object.
Instead, it's called as a regular function with the value of this being defaulted to the global object, which is window in browsers.
window.gender = 'n/a';
var genderTeller = person1.sayGender;
genderTeller(); // logs: 'n/a'
For question 1, the line
Person.prototype.gender = '';
gives the gender property a default value so that even if it is not assigned some other value when a new Person object is created, then it has a default value that is not undefined. There is a difference between '' and undefined that is important sometimes and not important other times, but there is a difference.
For question 2, when you do this:
var person1 = new Person('Male');
var genderTeller = person1.sayGender;
genderTeller(); // alerts undefined
Your variable genderTeller contains a function pointer and only a function pointer. It has NO association with your person1 object. When you call it as just a function, the this pointer inside the function will be set to either the global object (window in a browser) or undefined (if running in strict mode) and thus because this is not a Person object, this.gender will not contain an appropriate value and will likely be undefined.
There is a very important lesson in this error. In javascript, the this pointer is set according to how a method is called. When you call genderTeller(), you're just calling a function and thus there is no association whatsoever with any particular Person object. The this pointer will NOT point to a Person object and thus any references to this.xxx that assume it's a Person object will not work.
When you call person1.sayGender(), this is a very different way of calling the same function. Because you're calling it via an object reference, javascript will set the this pointer to the person1 object and it will work.
The difference between these two scenarios is subtle, but very important in javascript so I'll try to explain a bit more.
After you create your person1 object, it's an object that contains a property called sayGender. That property contains a value that points to the function for the sayGender operation. sayGender is just a function that's contained in a property (technically in the prototype chain on the person1 object, but you can just think of it as a property on that object.
When you do this:
var genderTeller = person1.sayGender;
You're creating a new variable called genderTeller that now ALSO holds a pointer to that same function. But, just like when it's in the sayGender property, it is just a function. It has no innate binding to any object. It only gets a binding to an object if you call it via an object reference (or if you use .call() or .apply() to force an object reference but that's beyond what you're doing here). When you just call
genderTeller()
you are just calling a function and it will have no object reference associated with it and thus this will not point to a Person object when the function runs.
As I mentioned above, it is possible to force an object reference. For example, you could do all of these:
var genderTeller = person1.sayGender;
genderTeller.call(person1);
// .apply() only differs from .call() in how
// arguments are passed to the function
// since you have no arguments to sayGender() it looks the same as .call()
var genderTeller = person1.sayGender;
genderTeller.apply(person1);
var genderTeller = person1.sayGender.bind(person1);
genderTeller();
And, it would again work because you were forcing an association with the person1 object when the function is called.
See MDN's reference for .call() and .apply() and .bind() if you want more info on this, but you should generally not need to use those just to call methods on an object because just calling it with the form obj.method() creates the object association and causes the this pointer to be set appropriately for you.
I looked over the article and was struck by how confusing this would indeed be to somebody not already intimately familiar with javascript.
Regarding #1, I believe this is a hint to the JIT compiler that "gender" is a string. Javascript JIT compilers like it when object properties stay the same type (in this case, String). It's silly that the article does not describe this, or that this line is there at all. Maybe it's there to demonstrate that you can override prototype properties in a "new Person" instance
Regarding #2, when you call object.method() in automatically calls method where the stack fills in "object" as "this". but if you do something like var detachedmethod = curobject.method and then call detachedmethod(), it does not call with "this" bound as curobject (instead, in the method body, this === undefined. Or maybe "window" I'm not sure :-))
All in all, it's a bunch of nitpicking, and not very important for day to day javascript usage, and can be picked up as you go along.
Here is the correct answer.
1) The prototype definition is not for a default value for Person. In fact, if you create another new Person with no gender, you will see it remains undefined.
var person2 = new Person();
person2.sayGender; // alerts undefined
The point here is to show that the constructor definition overrides a prototype definition.
2) Calling genderTeller() causes undefined because genderTeller is a global function which happens to have same function definition that it copied from person1.sayGender method. genderTeller is same as window.genderTeller.
Therefore when you execute genderTeller(), 'this' = window. Since window does not have a 'gender' property, you get an undefined. You can see it by this code
genderTeller(); // returns undefined
gender = 'hi there';
genderTeller(); // returns 'hi there'
Hope that helps. Here is a Plunker. http://plnkr.co/edit/wwc2vYIvH9QdFYStesVW

How does JavaScript assign context to this of event handlers?

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?
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.

Categories

Resources