I know about function scope, self-executing functions, hoisting and other cool words, but I am totally of-base with the following.
var o = {
a : 1,
f : (function(){
console.log(this.a);
})()
};
Why is this gives me undefined? Function is self-executed right when the object is initialized, therefore I expect it to already assign a to 1. But it is not doing this.
The function is not called in the scope of your newly created object, but in the global scope. There, a (or window.a) is indeed undefined. The braces themselves do not create a new block. Only when you call a method later, this is bound to o as you assume. Compare it with this:
var o = {
a : 1,
f : function(){
console.log(this.a);
}
};
o.f(); // console prints 1
Because you're not calling it via o, its this is not o.
Additionally you never assing the function to anything either - f is set to be the return value (undefined).
Related
function F () {
var color = "red";
this.fun = function f () {
console.log(color);
};
};
var i = new F();
i.fun();
I'm a bit confused to what new F() / new F is.
Here's what I know about the new keyword:
i) It creates {} either in constructor function or somehow related to constructor function.
ii) this in constructor function references this empty object and
iii) makes constructor function return this object unless you specify constructor function to return something else instead. So my first thought is that in the code above, new F() returns { fun: [Function: f] }.
When you console.log(new F()); what comes is slightly different:
F { fun: [Function: f] }
It look like an object, however this behaviour makes it apparent it's more complicated:
i.fun() returns "red". A method of this object is able to access
variables inside the constructor function that made it. If it were
purely a basic object it wouldn't be able to do that.
Right now, my only idea is that new F() is an object that is able to see the scope of the constructor function that made it.
Disclaimer: I am aware of what closures are and I know how function f could see color in F. I thought what was going on was a copy of function f was being added as a value in a brand new object which is assigned to i. Therefore, how does function f, in this brand new object, see the color variable in a completely separate function, F?
For example:
function F (v) {
var v = v;
var color = "red";
this.fun = function f () {
console.log(color);
};
};
var i = {fun: function f() {console.log(color)}};
i.fun() //returns 'color' is not defined.
There's another step when new F() is used:
iv) It sets the prototype of the object to an object like {contructor: F}.
This is why the object is logged as F { fun: [Function f] } instead of just {fun: [Function f] }. Objects with a prototype other than the standard Object prototype are shown with the name of the constructor function as a prefix.
As far as access to the variable color is concerned, it's no different from any other nested function, is a closure that captures variables from the containing environment. It's no different from writing an ordinary function like this:
function F() {
var color = 'red';
let fun = function f() {
console.log(color);
};
return {
fun: fun
}
}
let i = F()
i.fun()
Using new has no effect on the way variables are captured in a closure.
When you assign this.fun = function f ... it just stores the closure in the fun property. JavaScript never makes copies of objects, functions, etc. unless you do so explicitly -- assignments always assign references to the object.
You can even copy the closure to another object, it will still retain its access to the original environment. Since the function doesn't refererence this, it doesn't care how it's called.
var foo = {};
foo.fun2 = i.fun;
foo.fun2() // will log "red"
When you call new F() the following steps are performed (from MDN):
Creates a blank, plain JavaScript object;
Links (sets the constructor of) this object to another object;
Passes the newly created object from Step 1 as the this context;
Returns this if the function doesn't return an object.
So when executing the code var i = new F(); you have the following steps:
Create a new object. {} The prototype of this new object is set to F.prototype.
Set the constructor of this object to the function F. This changes the display to F {}
Bind the function F to the object and execute F. That means this within the body of F() refers to the object F {} we are carrying from Step 2.
The new keyword causes the expression to return that object if the return type of F() is undefined (which it is, as there's no value returned).
During step 3, F is executed, with this as an empty object F {}.
The first line var color = "red"; is executed. It defines and assigns a variable, nothing special.
The second line is executed. this.fun = function f() { ... }; The function must be evaluated first before the assignment.
During the evaluation of the function, a closure is created around all variables in scope. A specific reference to this instance's declaration of the variable color is captured in scope. The function f, even when referenced outside of F, carries this closure with it. Anywhere it is executed, it carries the same closure which was captured during evaluation of this line. This closure has the variable color, so no matter where it's passed around and executed, it still knows what the variable color is. This is how closures work.
Hopefully that last paragraph clears up why this works the way it does for you.
To specifically address your last example:
var i = {fun: function f() {console.log(color)}};
The function f() in this context was not evaluated with color in its scope. The closure captured during the evaluation of this line of code does not include color, because color is a local variable only defined in the scope of a current execution of the function F().
Javascript has constructor functions, you can do:
class F {
constructor() { this.color = "red"; }
fun() {
console.log(this.color);
}
};
Then you have to call that with new F();
When not calling a constructor specifically you can call any function with new, which has the effect of making the this function inside the function apply to the function itself. You can call it with apply and set this to whatever you want.
For that reason a common convention in JS was to name functions that expected to be called with new with CapitalCase, and those that didn't with camelCase. So you could just call fooBar() however you wanted, but would expect bugs if you had new FooBar() without the new.
Therefore, how does function f, in this brand new object, see the color variable in a completely separate function, F?
It doesn't, f is inside F and sees the var color declared across that scope. Functions inherit the scope of anything they're declared inside. f can see the rest of F, but F can't see the closure inside f.
You are able to access color (value: red) beacuse of closure as you mentioned.
Since color variable was available at the time of function f / fun declaration. It saves it value as a closure variable.
If you want separate copies of color variable as well. Define it on this like following:
function F (color) {
this.color = color;
this.fun = function f () {
console.log(this.color);
};
};
var i1 = new F("green");
var i2 = new F("red");
i1.fun(); // green
i2.fun(); // red
In your second code snippet you are getting color as undefined because there is no color variable declared in same scope as function f (inside i object) or globally.
Hello I am a javascript beginner and I read about how to interpret the this keyword but in this example I am still confused:
<script>
function example(param) {
this.a = param;
var b = true;
this.getB = function() {
return b;
}
this.setB = function(x) {
b = x;
}
}
document.write(window.a); //prints "undefined" (line A)
document.write(window.b); //prints "undefined" (line B)
document.write(window.getB(); //generates an error "undefined is not a function (Line C)"
For Line A, I guess the explanation is that this refers to the object that owns the function example, in this case, the window object. Therefore you can reference window.a, but it is not defined so it prints undefined
I cannot understand Line B. Isn't var b restricting b to a local scope? Which should mean that you can only reference b within the function? I was expecting Line B to generate an error, not printing undefined.
I have totally no clue about Line C, why does it generate an error, and what does this mean in this case?
Many thanks!
The this variable depends on how the function is being used.
If you instantiate the function (treat it like a class) then this will refer to the instance of the class:
new example("foo").getB(); // `this` is an instance of example
If you call it with Function.prototype.call then this will refer to whatever object you passed to the call method:
example.call(anotherObject, "foo"); // `this` refers to anotherObject
If you just execute it directly then this may refer to the window or whatever other surrounding scope.
example("foo"); // `this` likely refers to the window object
You can also use Function.prototype.bind to wrap your function in a specific scope to help clear things up:
var wrappedExample = example.bind(aSpecificObject);
wrappedExample(); // Doesn't matter how it's called, `this` will refer to aSpecificObject
Of course you may want to consider your target browsers before using bind (or use a polyfill).
First - you never call the example() function. So nothing it does has any effect.
Second - you have a syntax error on the last line, you are missing a ).
If you were to fix those issues, the results would be different:
function example(param) {
this.a = param;
var b = true;
this.getB = function() {
return b;
}
this.setB = function(x) {
b = x;
}
}
example("data");
document.write(window.a); //prints "undefined" (line A)
document.write(window.b); //prints "undefined" (line B)
document.write(window.getB()); //generates an error "undefined is not a function (Line C)"
For Line A, I guess the explanation is that "this" refers to the object that owns the function "example", in this case, the window object. Therefore you can reference window.a, but it is not defined so it prints "undefined"
It wasn't defined because you weren't calling the function. If you were to call it, then it is defined as the value of param.
I cannot understand Line B. Isn't "var b" restricting b to a local scope? Which should mean that you can only reference b within the function? I was expecting Line B to generate an error, not printing "undefined".
The locally scoped variable b is distinct from the b property of the object that is stored in this.
Accessing an undefined property of an object doesn't throw an error in JavaScript, it gives you undefined.
If you were to access an undeclared variable, then you would have a Reference Error.
I have totally no clue about Line C, why does it generate an error, and what does "this" mean in this case?
As with the other examples, you don't use this for lines A, B or C. You use window. this is only used inside the function.
You were getting an error because you never ran the function, so window.getB was never set. Calling the undefined value as a function throws an error.
If you fix the problem, as described above, you get the value of the local b variable.
If you are using this within a function, it will refer to the global window object.
function whatsThis(){
console.log(this);
}
whatsThis(); //displays the window object
If the function exists within an object created by a constructor function, however, this will refer to the parent object
var WhatsThis = function(){
this.showThis = function(){
console.log(this);
};
};
var obj = new WhatsThis();
obj.showThis(); //displays the instance of WhatsThis
Likewise with object literals, this refers to the containing object.
As we know , setTimeout is not working correctly with this becuase it runs in a global scope ( and this will be window)
But I've made a simple test :
Just wrap it with function :
var o={}
o.a=1;
o.m=function (){alert(this.a);}
setTimeout(
function (){
o.m() ;
}
,100);
And it does alert 1.
Am I missing something here ? why none of the answer suggests this solution ? does it behave different ?
p.s. : for those who intereseted here is a demo where it fails :
var o={}
o.a=1;
o.m=function (){alert(this.a);}
setTimeout( o.m ,100); //undefined
The proper way to do this is to bind() the scope of the anonymous function.
var o = {};
o.a = 1;
setTimeout(function (){
alert(this.a);
}.bind(o), 1000);
While your answer produces the same results, it's not accessing the scope of o from within the anonymous function. It's merely calling a function of the global object o.
Your reference to this.a is from within the scope of o.
You're missing closures. Your callback function will have access to o, even if it's not been declared globally, as long as the callback was defined in a scope that did have access to o.
JS can't GC o, because the callback function still references it, hence your snippet works
Example:
(function()
{
var scope = {};//an empty object
setTimeout(function()
{
console.log(scope);
console.log(typeof scope);
},1000);
}());
console.log(scope);
Here, you'll see undefined being logged, and (about) a second later, you'll see {} followed by object appear.
Whereas:
var foo = {bar: 'foobar',
callback: function()
{
console.log(this);
}
};
setTimeout(foo.callback, 1000);
console.log(foo.callback());
Will first log the object, referenced by foo, but then a second later, the same function object will log the global object because (as you say correctly), the function reference is invoked in the global context. The only way to avoid this is to use bind, or create another closure (but that would take us too far ATM).
I have gone into more detail on JS's ad-hoc context binding and reference resolving here, here, here, here and so on, and so forth
"this" is defined differently in different scopes, whereas you only defined "o" globally.
Consider the following code:
function A() {}
A.prototype.go = function() {
console.log(this); //A { go=function()}
var f = function() {
console.log(this); //Window
};
f();
}
var a = new A();
a.go();
Why does 'this' inside function 'f' refers to the global scope? Why it is not the scope of function 'A' ?
JavaScript has a different concept of what the special name this refers to
than most other programming languages do. There are exactly five different
ways in which the value of this can be bound in the language.
The Global Scope
this;
When using this in global scope, it will simply refer to the global object.
Calling a Function
foo();
Here, this will again refer to the global object.
ES5 Note: In strict mode, the global case no longer exists.
this will instead have the value of undefined in that case.
Calling a Method
test.foo();
In this example, this will refer to test.
Calling a Constructor
new foo();
A function call that is preceded by the new keyword acts as
a constructor. Inside the function, this will refer
to a newly created Object.
Explicit Setting of this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
When using the call or apply methods of Function.prototype, the value of
this inside the called function gets explicitly set to the first argument
of the corresponding function call.
As a result, in the above example the method case does not apply, and this
inside of foo will be set to bar.
Note: this cannot be used to refer to the object inside of an Object
literal. So var obj = {me: this} will not result in me referring to
obj, since this only gets bound by one of the five listed cases.
Common Pitfalls
While most of these cases make sense, the first one is to be considered another
mis-design of the language because it never has any practical use.
Foo.method = function() {
function test() {
// this is set to the global object
}
test();
}
A common misconception is that this inside of test refers to Foo; while in
fact, it does not.
In order to gain access to Foo from within test, it is necessary to create a
local variable inside of method which refers to Foo.
Foo.method = function() {
var that = this;
function test() {
// Use that instead of this here
}
test();
}
that is just a normal variable name, but it is commonly used for the reference to an
outer this. In combination with closures, it can also
be used to pass this values around.
Assigning Methods
Another thing that does not work in JavaScript is function aliasing, which is
assigning a method to a variable.
var test = someObject.methodTest;
test();
Due to the first case, test now acts like a plain function call; therefore,
this inside it will no longer refer to someObject.
While the late binding of this might seem like a bad idea at first, in
fact, it is what makes prototypal inheritance work.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
When method gets called on a instance of Bar, this will now refer to that
very instance.
Disclaimer: Shamelessy stolen from my own resources at http://bonsaiden.github.com/JavaScript-Garden/#function.this
The reason why is you are invoking f as a function and not a method. When invoked as a function this is set to window during the execution of the target
// Method invocation. Invoking a member (go) of an object (a). Hence
// inside "go" this === a
a.go();
// Function invocation. Invoking a function directly and not as a member
// of an object. Hence inside "f" this === window
f();
// Function invocation.
var example = a.go;
example();
The scope of all functions is window.
To circumvent that, you can do this:
function A() {}
A.prototype.go = function() {
var self = this;
console.log(self); //A { go=function()}
var f = function() {
console.log(self); //A { go=function()}
};
f();
}
Because function f() is not called without any object reference. Try,
f.apply(this);
What type of function is the following and which is their best use?
var f = function (){
var a = 0;
return {
f1 : function(){
},
f2 : function(param){
}
};
}();
I tried to convert it to:
var f = {
a : 0,
f1: function (){
},
f2: function (param){
}
}
But seems does not works the same way.
It's just a plain old function that is invoked immediately, and returns an object which is then referenced by f.
The functions referenced by object returned retain their ability to reference the a variable.
No code outside that immediately invoked function can reference a so it enjoys some protection since you control exactly what happens to a via the functions you exported.
This pattern is sometimes called a module pattern.
Regarding your updated question, it doesn't work the same because a is now a publicly available property of the object.
For the functions to reference it, they'll either do:
f.a;
or if the function will be called from the f object, they can do:
this.a;
Like this:
var f = {
a : 0,
f1: function (){
alert( this.a );
},
f2: function (param){
this.a = param;
}
}
f.f2( 123 );
f.f1(); // alerts 123
But the key thing is that a is publicly available. Any code that has access to f can access f.a and therefore make changes to it without using your f1 and f2 functions.
That's the beauty of the first code. You get to control exactly what happens to a.
Basically that creates a "class" - JS doesn't have classes so a class is basically a function such as your function f.
The interesting thing about the code you posted is that it creates a private variable a and two public functions f1 and f2. They are public because the constructor - the outer function - returns them.
This is a common pattern for organising and encapsulating JS code.
You can read more about it here
It's a simple function to create and return an object. It's immediately executed, and its result is saved to your variable f
It first declares a local (or private) variable a, visible only withing the scope of the function. Then it constructs an object which has members f1 and f2, both of which are functions. Since this return object is declared within the same scope that a is declared, both f1 and f2 will have access to a.
Your conversion simply creates a single object. Where before you had a function that would create endless objects, you now have a single object, and no more. I'm not sure exactly why it doesn't work, but one major difference is that a is now visible to the world, where before it was private to the return object.