//1st question
var x = 4,
obj = {
x: 3,
bar: function() {
var x = 2;
setTimeout(function() {
var x = 1;
alert(this.x);
}, 1000);
}
};
obj.bar();
//2nd question
function foo(a) {
arguments[0] = 2;
alert(a);
}
foo(1);
1.why it returns 4 instead of 1? i thought this.x refer to 1, but it seems wrong....i just dont understand why it returns 4
2.why it return alert 2 instead of 1, i thought i pass a to function a, and as far as i know, i pass 1 to function foo, and 1 should be alerted because of a(which is 1 when i pass)....i just don't understand why it alert 2
The runtime (in non-strict mode) invokes the setTimeout() callback with this bound to window (the global context), so this.x refers to the outer x.
The arguments object serves as a way to alias the formal parameters of a function. Setting the value of arguments[0] also sets the value of the first declared parameter to the function.
1. why it returns 4 instead of 1?
Notice the first initialization: var x = 4, which in non-strict mode attaches a property x to global object: window.x = 4.
setTimeout(function() {
var x = 1;
alert(this.x);
}, 1000);
setTimout() callback has this context as the global object. And actually calling alert(this.x) -> alert(window.x) -> alert(4).
2.why it return alert 2 instead of 1
arguments object represents the list of function arguments. When modifying it, you actually modify the arguments values: arguments[0] = 2 modifies first argument a = 2.
Related
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 3 years ago.
Initial question
The below code should return 1,3 since x: 1 is just present above return statement - however, it's returning 3,1. Why is this? Will it be same result when we use let and/or const.
It would be great if you guys explain, so that I can improve my fundamentals. Below is my code:
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
console.log("this--->", this);
return this.x;
}
}
}
var go = foo.baz.bar;
alert(go());
alert(foo.baz.bar());
Update 1:
In the first case bar is considered as a closure which has access to the variables outside and prints 3:
bar: function() {
console.log("this--->", this);
return this.x;
}
The 'this' keyword will mean two different objects for the two function calls. You may see it by adding 'console.log(this);' before the return statement. Try using an arrow function instead!
When you assign foo.baz.bar to a var go, after the assignment go just holds a reference to the inner function. If it is then called from the outer scope then x = 3. In effect, the this within a function depends on the scope that the function is called from.
In the second case, when you call bar(), it is in the scope of the object it's called from within (i.e. foo.baz ), so this time the this within function bar() refers to baz, giving and so x = 1.
More on scope and this in javascript here
Here you can read up on Function.prototype.bind. This method should be able to help you out with your issue.
Check the code example below:
var x = 3;
const foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
//You're assigning a function definition to a variable, but this will not maintain scope:
const fn = foo.baz.bar;
//When called like this, bar() can be thought of as a method of foo.baz
console.log(foo.baz.bar()); //so we expect x = 1;
//You must properly bind your function reference to the desired "this" object:
const globalBound = fn; //which would be equivalent of: fn.bind(this);
const fooBound = fn.bind(foo);
const bazBound = fn.bind(foo.baz);
console.log(globalBound()); //x = 3
console.log(fooBound()); //x = 2
console.log(bazBound()); //x = 1
x = 'Now globalBound() will return a string';
foo.x = 'and so will fooBound(), but bazBound() will remain unchanged';
console.log(globalBound());
console.log(fooBound());
console.log(bazBound());
I encourage you to change var x = 3 to let x = 3 and check out your result.
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 5 years ago.
This is an interview question! And I can't know the reason of it!
function fun(val) {
this.x = val;
return this;
}
var x = fun(1);
var y = fun(2);
console.log(x.x); //I can't understand this result.
console.log(y.x);
Well, I think that happens because "This" in the fun function refers to Window object not a local thing inside the function. so therefore you first call it by fun(1) and make the window.x = 1, and then call it by fun(2) and it becomes window.x = 2 .. then you console log it when both x and y are a reference to window ... and therefore both will have the same final value.
When you call a function the "normal" way, the this object points to the global object (window):
function testFunction () {
return this;
}
console.log(window === testFunction());
This means that what your function returns is the global object, and both variables x and y are references to the global object. Before it returns, it assigns a property x to the global object.
In the first function call, it assigns 1 to the property x of the global object. In the second function call, it assigns 2 to the same property. This is why you get 2 two times.
If you want this to refer to another object than the global one, you have to use call:
function testFunction (value) {
this.x = value;
return this;
}
var firstObject = {};
var secondObject = {};
var x = testFunction.call(firstObject, 1);
var y = testFunction.call(secondObject, 2);
console.log(x.x);
console.log(y.x);
console.log(x === firstObject);
console.log(y === secondObject);
console.log(window === testFunction());
This seems strange to me. I have
var j = "x";
var k = "y";
function fun1 ( a, b) {
var j = a;
var k = b;
console.log("this.j is:", this.j);
console.log("this.k is:", this.k);
this.j = a;
this.k = b;
return this.j + this.k;
};
console.log("j is ", j);
console.log("k is ", k);
console.log("fun1(3,4) is ", fun1(3,4));
console.log("j is ", j);
console.log("k is ", k);
console.log("fun1(2,7) is ", fun1(2,7));
console.log("j is ", j);
console.log("k is ", k);
When I run this in Node.js, I get:
j is x
k is y
this.j is: undefined
this.k is: undefined
fun1(3,4) is 7
j is x
k is y
this.j is: 3
this.k is: 4
fun1(2,7) is 9
j is x
k is y
Why aren't j and k being set to arguments a and b in the function when they are declared? It just doesn't seem right that I have to do BOTH var j = a; AND this.j = a; !! What am I doing wrong?
In node, the output properly shows that the j and k variables in global are not being clobbered by the local variables j and k in fun1. When I run this in Chrome or Firefox, the global variables DO GET clobbered. In other words I get
j is x
k is y
this.j is: undefined
this.k is: undefined
fun1(3,4) is 7
j is 3
k is 4
this.j is: 3
this.k is: 4
fun1(2,7) is 9
j is 2
k is 7
Why isn't the local scope protecting the global var?
Thanks for any hints.
I recommend you to go read that! :) That explain precisely how to use this and what is the this!
Read here! Mozilla Developper Network
Here is the article if the link is dead. (Sorry, the formating is not perfect and the text is very long.)
Summary
A function's this keyword behaves a little differently in JavaScript
compared to other languages. It also has some differences between
strict mode and non-strict mode.
In most cases, the value of this is determined by how a function is
called. It can't be set by assignment during execution, and it may be
different each time the function is called. ES5 introduced the bind
method to set the value of a function's this regardless of how it's
called.
Syntax this Global context In the global execution context (outside of
any function), this refers to the global object, whether in strict
mode or not.
console.log(this.document === document); // true
// In web browsers, the window object is also the global object:
console.log(this === window); // true
this.a = 37; console.log(window.a); // 37 Function context Inside a
function, the value of this depends on how the function is called.
Simple call
function f1(){ return this; }
f1() === window; // global object In this case, the value of this is
not set by the call. Since the code is not in strict mode, the value
of this must always be an object so it defaults to the global object.
function f2(){ "use strict"; // see strict mode return this; }
f2() === undefined;
In strict mode, the value of this remains at
whatever it's set to when entering the execution context. If it's not
defined, it remains undefined. It can also be set to any value, such
as null or 42 or "I am not this".
Note: In the second example, this should be undefined, because f2 was
called without providing any base (e.g. window.f2()). This feature
wasn't implemented in some browsers when they first started to support
strict mode. As a result, they incorrectly returned the window object.
As an object method
When a function is called as a method of an object, its this is set to
the object the method is called on.
In the following example, when o.f() is invoked, inside the function
this is bound to the o object.
var o = { prop: 37, f: function() {
return this.prop; } };
console.log(o.f()); // logs 37 Note that this behavior is not at all
affected by how or where the function was defined. In the previous
example, we defined the function inline as the f member during the
definition of o. However, we could have just as easily defined the
function first and later attached it to o.f. Doing so results in the
same behavior:
var o = {prop: 37};
function independent() { return this.prop; }
o.f = independent;
console.log(o.f()); // logs 37 This demonstrates that it matters only
that the function was invoked from the f member of o.
Similarly, the this binding is only affected by the most immediate
member reference. In the following example, when we invoke the
function, we call it as a method g of the object o.b. This time during
execution, this inside the function will refer to o.b. The fact that
the object is itself a member of o has no consequence; the most
immediate reference is all that matters.
o.b = {g: independent, prop: 42}; console.log(o.b.g()); // logs 42
this on the object's prototype chain
The same notion holds true for methods defined somewhere on the
object's prototype chain. If the method is on an object's prototype
chain, this refers to the object the method was called on, as if the
method was on the object.
var o = {f:function(){ return this.a + this.b; }}; var p =
Object.create(o); p.a = 1; p.b = 4;
console.log(p.f()); // 5 In this example, the object assigned to the
variable p doesn't have its own f property, it inherits it from its
prototype. But it doesn't matter that the lookup for f eventually
finds a member with that name on o; the lookup began as a reference to
p.f, so this inside the function takes the value of the object
referred to as p. That is, since f is called as a method of p, its
this refers to p. This is an interesting feature of JavaScript's
prototype inheritance.
this with a getter or setter
Again, the same notion holds true when a function is invoked from a
getter or a setter. A function used as getter or setter has its this
bound to the object from which the property is being set or gotten.
function modulus(){ return Math.sqrt(this.re * this.re + this.im *
this.im); }
var o = { re: 1, im: -1, get phase(){
return Math.atan2(this.im, this.re); } };
Object.defineProperty(o, 'modulus', {
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142 As a constructor
When a function is used as a constructor (with the new keyword), its
this is bound to new object being constructed.
Note: while the default for a constructor is to return the object
referenced by this, it can instead return some other object (if the
return value isn't an object, then the this object is returned).
/* * Constructors work like this: * * function MyConstructor(){ *
// Actual function body code goes here. * // Create properties on
|this| as * // desired by assigning to them. E.g., * this.fum =
"nom"; * // et cetera... * * // If the function has a return
statement that * // returns an object, that object will be the *
// result of the |new| expression. Otherwise, * // the result of
the expression is the object * // currently bound to |this| * //
(i.e., the common case most usually seen). * } */
function C(){ this.a = 37; }
var o = new C(); console.log(o.a); // logs 37
function C2(){ this.a = 37; return {a:38}; }
o = new C2(); console.log(o.a); // logs 38 In the last example (C2),
because an object was returned during construction, the new object
that this was bound to simply gets discarded. (This essentially makes
the statement "this.a = 37;" dead code. It's not exactly dead, because
it gets executed, but it can be eliminated with no outside effects.)
call and apply
Where a function uses the this keyword in its body, its value can be
bound to a particular object in the call using the call or apply
methods that all functions inherit from Function.prototype.
function add(c, d){ return this.a + this.b + c + d; }
var o = {a:1, b:3};
// The first parameter is the object to use as // 'this', subsequent
parameters are passed as // arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// The first parameter is the object to use as // 'this', the second
is an array whose // members are used as the arguments in the function
call add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 Note that with
call and apply, if the value passed as this is not an object, an
attempt will be made to convert it to an object using the internal
ToObject operation. So if the value passed is a primitive like 7 or
'foo', it will be converted to an Object using the related
constructor, so the primitive number 7 is converted to an object as if
by new Number(7) and the string 'foo' to an object as if by new
String('foo'), e.g.
function bar() { console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number] The bind method
ECMAScript 5 introduced Function.prototype.bind. Calling
f.bind(someObject) creates a new function with the same body and scope
as f, but where this occurs in the original function, in the new
function it is permanently bound to the first argument of bind,
regardless of how the function is being used.
function f(){ return this.a; }
var g = f.bind({a:"azerty"}); console.log(g()); // azerty
var o = {a:37, f:f, g:g}; console.log(o.f(), o.g()); // 37, azerty As
a DOM event handler
When a function is used as an event handler, its this is set to the
element the event fired from (some browsers do not follow this
convention for listeners added dynamically with methods other than
addEventListener).
// When called as a listener, turns the related element blue function
bluify(e){ // Always true console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target); this.style.backgroundColor =
'#A5D9F3'; }
// Get a list of every element in the document var elements =
document.getElementsByTagName('*');
// Add bluify as a click listener so when the // element is clicked
on, it turns blue for(var i=0 ; i
elements[i].addEventListener('click', bluify, false); } In an in–line
event handler
When code is called from an in–line handler, its this is set to the
DOM element on which the listener is placed:
Show this
The above alert shows button. Note however that only the
outer code has its this set this way:
Show inner
this In this case, the inner function's this isn't set so it
returns the global/window object (i.e. the default object in
non–strict mode where this isn't set by the call).
I just started reading Functional JavaScript and immediately was introduced to a function that I don't understand:
function splat(fun) {
return function(array) {
return fun.apply(null, array);
};
}
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements([1, 2]);
//=> 3
How does splat(function(x, y) { return x + y }) work. It's called with the array [1,2], but it seems like the anonymous function inside the call to splat takes two parameters, not one array.
Putting console.log(fun) on line 2 of this code shows that fun is the entirety of the anonymous function(x, y) { return x + y }. console.log(array) after return function(array) { shows that array is [1, 2]. Where does array come from then?
Thanks much.
It might be simpler to see how this function would have been written without using the .apply method:
function splat(fun) {
return function(array) {
return fun(array[0], array[1]);
};
}
First you call splat, passing it a function:
var add = function(x,y){ return x + 1 };
var ff = splat(add);
At this point, ff refers to the function(array) function, meaning its an one-argument function. The private variable fun refers to the add function.
Now, you call ff passing its one argument
ff([1,2]);
and it uses the values in the array to call fun with two arguments
return fun(array[0], array[1]);
The only difference between this and the real example is that the apply method lets you work with any argument array length instead of hardcoding a specific length (2) like I did.
//Every time we call this function, we get another one back
function splat(fun) {
return function(array) { // <-- this one will be returned in splat();
return fun.apply(null, array);
};
}
//Step one, call splat, pass a function as parameter
var addArrayElements = splat(function(x, y) { return x + y });
/*
Get back a function that accepts an array, and will execute the function we just passed in on it
*/
// This will call the newly created function, func will be available because it's in a closure
addArrayElements([1, 2]);
The last thing is that, even if the anonymous function takes two parameters, we call apply on it so it will bind array[0] ==> x and array[1] ==> y
This is an example of a higher order function. That's a function that takes functions as arguments and returns functions instead of just regular values (though functions are "just regular values" in Javascript). In this case:
function splat(fun) {
splat takes a function as its argument...
return function(array) {
...and returns a new function which takes an array...
return fun.apply(null, array);
...and when called calls the first fun function with the array .applied as its arguments.
So splat takes one function which expects several parameters and wraps it in a function which takes an array of parameters instead. The name "splat" comes from languages like Ruby, where a * (a "splat" or "squashed bug") in the parameter list of a function accumulates an arbitrary number of arguments into an array.
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements is now basically:
function (array) {
// closed over variable:
// var fun = function(x, y) { return x + y }
return fun.apply(null, array);
}
Here this is realized by a closure, which closes over and "preserves" the original fun passed to splat in the new returned function.
addArrayElements = function(array) { fun.apply(null, array); };
BUT
it has a closure whereby the variable context of its containing scope (that of the splat function that created the anonymous function) remains visible and accessible.
In JavaScript, functions are first-class objects that can be referenced and passed as arguments or, as in this case, through the closure mechanism.
Edit: about JavaScript and scope
In most languages, variables are, by default, local to the scope they're defined in (which usually is a function's local symbol table). By contrast, in JavaScript a variable is local only if it is defined using the var keyword; otherwise, the symbol will be looked back in the chain of the containing scopes, up to the implicit root object (which in the case of web browsers is window. I.e.,
function foo() { someVar = "bar"; }
foo();
alert(someVar); // shows "bar"
Not being restricted to the local scope, the symbol has been (purposely or not) leaked to the root scope.
Taking it one step further:
function foo() {
var baz = function() {
someVar = "bar";
};
baz();
}
foo();
alert(someVar); // shows "bar"
However, if you declare someVar within foo:
function foo() {
var someVar;
var baz = function() {
someVar = "bar";
};
baz();
alert("someVar in foo=" + someVar); // shows "bar"
}
foo();
alert("someVar in root=" + window.someVar); // shows "undefined"
Note that in this last version I needed to use window.someVar instead of just someVar because someVar never got defined as a variable in the root scope nor as a property of the root object, which caused an error.
a more functional approach uses bind(), which is short enough you don't really need splat anymore, and it's always nice to eliminate closures:
var addArrayElements = Function.apply.bind( function(x, y) { return x + y } , null );
addArrayElements([1, 2]); // === 3
I understand the general idea behind the this keyword but I'm having trouble figuring out what it actually refers to in practice. For example, in both these example exercises, I guessed the wrong number.
for question1, I said that the alert would be '5', because it is referring to the this.x outside the anonymous function in the function.
In question2, I thought the alert would be 5 because this line
var alertX = o.alertX;
would bind the value 5 for property x inside the variable o to the new variable 'alertX' which becomes the function call in the next line: alertX();
Can you explain why I'm wrong?
var question1 = function() {
this.x = 5;
(function() {
var x = 3;
this.x = x;
})();
alert(this.x);
};
var answer1 = 3;
var question2 = function() {
this.x = 9;
var o = {
'x':5,
'alertX':function() { alert(this.x); }
};
var alertX = o.alertX;
alertX();
}
var answer2 = 9;
In the first case, when you invoke a method with no explicit receiver this is the Global object (the window in a web browser).
Similarly in the second case: even though the function is defined on the object, and you are inside another, by invoking the function with alertx() the this is set to the Global/window.
In short:
For foo.bar(), the this inside of bar will be foo.
For bar(), the this will be the Global object.
This includes so-called "self-invoking lambdas", i.e. (function(){ ... })().
For bar.call(whee) and bar.apply(whee), the this will be whee (because that's what these methods do).
Another example:
var o1 = { name:"o1", f:function(){ console.log(this.name) } };
var o2 = { name:"o2" };
o2.gogogo = o1.f;
o2.gogogo(); // Will output "o2"
These are good examples of how interesting this becomes in Javascript. this always refers to the context in which it was invoked / called, not simply where it is at that moment! question2 is a perfect example of it.
I'm assuming you are invoking these globally like so:
question1();
question2();
In question1:
You have an anonymous function that is ran after you first set x to 5. This anonymous function if not set to a variable, inside a function etc, would have this set to the global variable of window. But you have it within a function & set to variable question1. So when it runs itself, it sets this's (which is question1 function) x variable to 3.
In question2:
X is originally set to 9, this being question2 in this instance. Now the part that is throwing you off is that, even though within the o {} object you set x : 5. And your alertX function is calling this.x. All of this would lead you to think it will alert 5! But you are invoking your alert function outside of the o {} object, hence the this refers to question2 function again!
Put the following into your browser's console
var x = -1, log = function(){ // set up some stuff
if(console) if(console.log) return console.log.apply(console, arguments),undefined;
return alert(arguments.join(', ')),undefined;
},
question1 = function() {
this.x = 5; // question1.x is 5
(function() { // anonymous function fires in global 'window'
var x = 3; // so window.x is now 3
this.x = x; // this is window
})();
log('ans1',this.x,this); // see below
},
question2 = function() {
this.x = 9; // question2.x is 9
var o = {
'x':5, // o.x is 5
'alertX':function() { log('ans2',this.x,this); }
};
var alertX = o.alertX; // alertX === o.alertX
alertX(); // being called in global scope
// to make alertX have scope of question2
this.alertX = o.alertX; // this is question2
this.alertX(); // so we're calling from question2
},
a1 = new question1(), // note the new operator
a2 = new question2();
undefined;
And you'll get
ans1 5 question1
ans2 3 Window
ans2 9 question2