I'm playing around with scopes in JavaScript and I was curious about something I ran across when calling a function from an array. In the below example I work with three different scopes. One bound to an Object called foobar, one bound to window and then a third one which actually refers to the function itself. I'm just curious why the function is scoped to itself and not to the global window object. Is it because Array access is a function call itself so the stored function is in a local scope?
var foobar = {
doWork: function() {
console.log('doing some work...');
console.log(this);
}
}
foobar.doWork(); // `this` will refer to foobar
var doWorkClone = foobar.doWork;
doWorkClone(); // `this` will refer to window
var workClones = [];
workClones.push(foobar.doWork);
workClones[0](); // `this` will refer to the doWork function itself
They behave the same way. In a.b(), the function a.b is called with this set to a.
foobar.doWork(); // function is `foobar.doWork`, `this` is `foobar`
workClones[0](); // function is `workClones[0]`, `this` is `workClones`
This is because the . and [] notation are functionally the same thing. It does not matter which one you use, nor does it matter whether you're dealing with an array or not.
to understand this, litteraly, it might be helpfull to see how the js works under the hood.
when you write f(args), js will execute f.call(this, args). Hence this always refers to where you call the function from.
In your case:
foobar.doWork() --> foobar
doWorkClone() --> window or wrapping expression
workClones[0]() --> "0" is in workClones, so workClones
Related
All the articles and books I read say that it doesn't matter where I define my function, it's where I invoke the function that decides which object 'this' is bound to. But with this example, I don't understand why 'this' is bound to global object.
function foo(){
console.log(this);
}
var obj = {
myMethod: function() {
foo();
}
};
obj.myMethod();
As I understand, 'obj' object is the one that invokes the function so 'this' should be bound to 'obj', but the result is window object. Can anyone please explain this for me?
this is a strange beast in JavaScript, so you'd do well to read the overview on MDN.
But in summary, it doesn't matter where the function was originally defined, but what does matter is the location from which it's being executed...
If the function is defined globally and you invoke it using myFunction(x), then it's executing in the global scope, and this will refer to the global object (as you have discovered in your foo() function where this is the Window object)
If a function is contained in an object's property then this will refer to the object that contains the property. (Object properties which contain functions are called "methods")
For example...
myFunction = function() { console.log(this); }
myObject = {
myMethod: myFunction
}
myFunction(x) // `this` == the global window object.
myObject.myMethod(x) // `this` == `myObject`
NOTE 1. You can also invoke functions using 'call', 'apply', and 'bind'
which enable you to specify what this should refer to inside the function when it runs. (Read about them in detail on the link I provided.)
NOTE 2. The ES6 "arrow function" syntax ((x)=>{ ... }) is an exception, as this will always be the same value as this would be wherever the arrow function itself was defined.
When foo() is created it is created with a closure . When it is invoked it still remembers its scope through this closure with which it was created and at that time, this was bound to global object.
You're calling foo from within myMethod, so it isn't obj directly calling foo. To have this point to obj you should assign foo directly to myMethod.
e.g.
function foo() {
console.log(this);
}
var obj = {
myMethod: foo
};
obj.myMethod();
I have noticed something while playing around which has sparked a quick question.
When code is executed in the global/window context, any function declarations get added as methods to the window object.
But when I am in the context of another object, writing a function declaration does not add the method to my objects methods.
function functionInGlobalCtx() { // This will be added as a function to the window object
// code...
}
var myObject = {};
myObject.myObjectFunction = function () {
var $this = this; // The context here is the 'myObject' object
function functionHopefullyInMyObjectCtx() {
// code...
}
}
myObject.myObjectFunction();
Why does the function declaration exist as part of the window object but not the one for the object?
Is this simply 'how JavaScript works' (special rules apply to the global context?) or am I missing something?
Thanks.
Its actually understandable. Function is object. Myobject and myobjectfunction are two different objects. So are 'this' and function itself.
In your example, you define the hopefullyfunction in myobjfunction, not in myobject.
All functions declared globally will be attached to the global window object. That's how JavaScript works.
JavaScript only has function scope. So any function declared inside another function is private to the outer function.
The function functionHopefullyInMyObjectCtx can not be accessed from outside yet.
myObject.myObjectFunction = function () {
var $this = this;
function functionHopefullyInMyObjectCtx() {
// code...
}
}
Declaring a function inside a function does not attach it to the this automatically. However the function remains private and is only accessible within the scope it was declared in.
If you wanted to access the functionHopefullyInMyObjectCtx function from myObject.myObjectFunction then here is a way:
var myObject = {};
myObject.myObjectFunction = function () {
return {
functionHopefullyInMyObjectCtx: function() {
console.log('I got called');
}
}
}
obj = myObject.myObjectFunction();
//obj now has ref to the inner function
obj.functionHopefullyInMyObjectCtx();
I got called
Here is a good read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
I believe I have found the answer I was looking for.
Why are variables automatically assigned to the global/window object?
Because the JavaScript engine keeps a 'global environment record' of the items declared within the global scope (just like all scopes have an environment record holding all declaration information), but the difference between the global environment record and normal scope environment records is that the engine makes this record accessible within code (not just for engine internal use), through the window object!
If I am wrong or it's not quite right, please go ahead and correct me.
Thank you for your help.
https://es5.github.io/x10.html#x10.2.3
Difference between variable declaration syntaxes in Javascript (including global variables)?
I am trying to sharpen my JavaScript skills and I am aware that there are four basic ways to invoke a function - which alter the way this is defined. The two I am interested in are the basic two:
Invocation as a function
Invocation as a method
Which is fine. The first, this will refer to the window object:
function doSomething() {
console.log(this);
}
doSomething(); // window is logged
And the second this will refer to the object it is being executed from within:
var t = {
doSomething: function () {
console.log(this);
}
};
t.doSomething(); // t is logged
Which is all fine. However, is it correct to say, that in these two invoking methods, this is always going to return the object the method is contained within (if that makes sense)?
In the first example, doSomething() is, in reality, defined within the window object - so is a property of the window object, even if we do not define it (or reference it).
Therefore, can it not be said that, in reality, invocation as a function is invocation as a method? Or not?
Imagine defining your function, not in the scope of the global object like you did, but in the scope of another function:
function outer() {
var inner = function(){console.log(this)};
inner();
};
outer();
What do you think the this will be bound to ? What will be printed ?
You might believe it will be the outer function object but its turns out that it will always be the global object.
It is just as if you had written:
function outer() {
var inner = function(){console.log(this)};
inner.call(window);
};
outer();
This is a quite hazardous and far from intuitive JS "feature".
So, to get back to your first example, what you are doing is basically this:
doSomething = function () {
console.log(this);
}
doSomething().call(window);
And, like Yoshi pointed out, if you were using the ES5's strict mode, you would end up doing something like that instead, which is, in my opinion, far less dangerous:
doSomething().call(undefined);
It also gives you a strong hint about the fact that you should never use this in a function ;)
From Javascript-Garden:
Foo.method = function() {
function test() {
//this is set to the global object
}
test();
}
In order to gain access to Foo from within test, it is necessary to create a local variable inside of method that refers to Foo:
Foo.method = function() {
var that = this;
function test(){
//Use that instead of this here
}
test();
}
Could anyone explain this? As far as I understood, this refers to the global object if it's called in the global scope. But here it's called inside of a function, which is inside a method (first example). Why exactly does it refer to the global object, while the second example doesn't?
As far as I understood, this refers to the global object if it's called in the global scope.
No. this will refer to the default object if the function is called without explicit context. The scope is irrelevant. (In strict mode it will refer to undefined instead).
Why exactly does it refer to the global object
We can't tell what it refers to. The value of this is determined by how the function is called, not how it is defined.
Now you have updated the example, we can see that it is called without context, so this (in the inner function) will be the default object, which in a web browser is window (it would be undefined in strict mode).
while the second example doesn't?
In the second example, the inner function doesn't use this (which will have the same value as the previous example).
The second example uses that instead. that is defined in the scope of the outer function and is set to whatever the value of this is when that function is called.
Assuming that function is called as Foo.method() then (outer) this (and hence that) will be Foo because that is the context on which method was called.
this in a function isn't set when you define the function. It's only dynamically defined to the receiver of the function call.
If you call foo.test(), this in test will be foo.
But if you do
var f = foo.test;
f();
then this in f (which is foo.test) will be the external object (window if you're executing it at the root level).
It would be the same with
foo.test.call(window);
The second example uses a closure to place the outer functions variables on the scope chain of the inner function.
Foo.method = function() {
var that = this;
function test(){
//This function has access to the outer variables scope chain.
}
}
I've been reading through quite a few articles on the 'this' keyword when using JavaScript objects and I'm still somewhat confused. I'm quite happy writing object orientated Javascript and I get around the 'this' issue by referring the full object path but I don't like the fact I still find 'this' confusing.
I found a good answer here which helped me but I'm still not 100% sure. So, onto the example. The following script is linked from test.html with <script src="js/test.js"></script>
if (!nick) {
var nick = {};
}
nick.name= function(){
var helloA = 'Hello A';
console.log('1.',this, this.helloA);
var init = function(){
var helloB = 'Hello B';
console.log('2.',this, this.helloB);
}
return {
init: init
}
}();
nick.name.init();
What kind of expected to see was
1. Object {} nick.name, 'Hello A'
2. Object {} init, 'Hello B'
But what I get is this?
1. Window test.html, undefined
2. Object {} init, undefined
I think I understand some of what's happening there but I would mind if someone out there explains it to me.
Also, I'm not entirely sure why the first 'console.log' is being called at all? If I remove the call to the init function //nick.name.init() firebug still outputs 1. Window test.html, undefined. Why is that? Why does nick.name() get called by the window object when the html page loads?
Many thanks
Also, I'm not entirely sure why the first 'console.log' is being called at all?
nick.name = function(){
// ...
}();
Here you define a function, call it immediately (hence ()) and assign its return value ({init: init}) to nick.name
So the execution is:
Create a variable called nick if there isn't one with a non-falsey value already
Create an anonymous function that…
Creates a variable called helloA in its own scope
Outputs data using console.log containing "1" (as is), this (the window because the function is executing in the global context instead of as a method), and this.helloA (window.helloA, which doesn't exist.
Defines a function called init
Returns an object which gets assigned to nick.name
Then you call nick.name.init() which executes the init function in the context of name.
This defines helloB
Then it console.logs with "2" (as is), this (name), and this.helloB (nick.name.helloB - which doesn't exist)
So the first output you get is from console.log('1.',this, this.helloA);
I think your main problem is that you are confusing this.foo (properties on the object on which a method is being called) with variable scope (variables available to a function)
It's much simpler if you think about this as a function, not as a variable. Essentially, this is a function which returns current "execution context", that is, the object the current function was "applied" to. For example, consider the following
function t() { console.log(this)}
this will return very different results depending upon how you call it
t() // print window
bar = { func: t }
bar.func() // print bar
foo = { x: 123 }
t.apply(foo) // print foo
this is defined on a per-function basis when the function call is made. When you call a function as o.f(), this will be o within the function, and when you call it as f(), this will be the global object (for browsers, this is the window).
You wrote nick.name = function(){...}(); and the right-hand part is of the form f(), hence the Window.
var foo = bar; defines a local variable. It may not be accessed as this.foo (well, except when you're at global scope, but that's silly). To define a member, you usually write this.foo = bar; instead.
This is what your code does:
It creates an object and assigns to the variable nick.
It creates an anonymous function.
It calls the function (in the window scope).
It assigns the return value (an object containing the init property) to the name property of the object.
It gets the value from the init property, which is a method delegate, and calls the method.
The anonymous function does this:
It declares a local variable named helloA and assigns a string to it. (Creating a local variable doesn't add it as a property to the current object.)
It logs this (window) and the helloA property (which doesn't exist).
It creates an anonymous function and assignes to the local variable init.
It creates an object with the property init and the value from the local variable init.
The anonymous function assigned to the init property does this:
It declares a local variable named helloB and assigns a string to it. (Creating a local variable doesn't add it as a property to the current object.)
It logs this (the object from the name property, not the nick variable), and the helloB property (which doesn't exist).