Given this code:
const numberManipulator = (function() {
this.defaultNumber = 5;
const doubleNumber = function(num) {
console.log(this.defaultNumber);
return num !== undefined ? num * 2 : new Error('no number provided!');
}
return {
doubleNumber
}
})();
const test = numberManipulator.doubleNumber(20);
Why is console.log(this.defaultNumber showing undefined but if I console.log(defaultNumber, it shows 5? I thought that it would show undefined for the latter.
Thanks
You should read How does the “this” keyword work?
When the IIFE is called, its this is not set so it defaults to the global object, so in:
const numberManipulator = (function() {
this.defaultNumber = 5;
...
})();
this.defaultNumber = 5 creates a property of the global (window in a browser) object called defaultNumber and assigns it a value of 5.
If the return statement should really be:
return {doubleNumber: doubleNumber}
then the IIFE returns an object reference to numberManipulator. When called as:
numberManipulator.doubleNumber(20)
then this within doubleNumber is numberManipulator, which doesn't have a defaultNumber property so this.defaultNumber returns undefined.
Long story short:
1. The IIFE is executing in the context of the window I was wrong,
see RobG's comment.
2. this thus refers to the window inside the IIFE, since it is not set by default.
3. Your doing this.defaultNumber = 5; is hence equivalent to
window.defaultNumber = 5;
4. The second method executes in the context of numberManipulator and so logging this.defaultNumber is equivalent to numberManipulator.defaultNumber which was never set by you. Hence, it is undefined.
Explanation on this:
Inside any function, the this keyword refers to the current context in which the function is executing. It doesn't matter where you defined that function inside your codebase. All it matters in what context are you calling it. In your current case, you're calling the IIFE in the context of the window. Doing:
const numberManipulator = (function() {
// MAGIC
})();
amounts to:
running an IIFE in the window context.
assigning the result it returned to a constant.
However, the context of a function may be changed by using .call, .apply, or by simply calling that method as a property of another object. In your second log, this.defaultNumber, this refers to the object since you called the method using numberManipulator.doubleNumber(20);. Calling methods using object.prop() sets their context (=this) to that object.
Hope that helps! :D
Related
I did read that the this keyword can refer to either the global scope or to the object it is being referred in or to the object to which an event is bound but the below behavior is not understood.
function outer() {
var inner = 4;
function innerFunc() {
var inner = 5;
console.log('inner called with ' + this.inner);
}
return innerFunc;
}
var obj = outer();
obj();
Why does this log 4 instead of 5. AFAIK this should refer to the function it is being referred in and should be available via closure.
TL;DR - this doesn't work like you think it should.
Read more here, here and here.
The this (otherwise known as context) of a function is determined at call time, not at function definition time. This is widely known as this being dynamically bound, and variables from closure being lexically bound.
var obj = outer();
obj();
Calls outer with this = window (or global in the case of Node.js) because you are not in strict mode (otherwise, this = undefined). outer doesn't use this, so this doesn't impact it greatly.
outer then returns a function (innerFunc), and you assign it to obj. You then call obj, again, with this = window (because you didn't specify anything other with .bind() or .call() or .apply()).
You then log this.inner which is equivalent to window.inner which is undefined unless you happen to have a global variable named inner with some value.
The value of this, then, is determined by the caller.
If you had invoked obj like so:
obj.call({inner: 42}); // first argument to fn.call() is the context
You would have seen 42 in your console, regardless of how the function was defined.
A way to mitigate this and retain control over your this is to either use fn.bind() or an arrow function.
Your code snippet is returning undefined, not 4. The reason for this is because the window is calling innerFunc by invoking obj(). Thus, this is referring to the window as that is what called innerFunc (and window.inner is undefined). You can see this by adding a variable inner = 3 at the top of your code (this will make window.inner = 3) and so your function will log 3.
inner = 3; // ie: window.inner = 3
function outer() {
var inner = 4;
function innerFunc() {
var inner = 5;
console.log('inner called with ' + this.inner); // this is window
}
return innerFunc;
}
var obj = outer();
obj();
In this example you are using a function instead of an object. Additionally, you used a variable instead of the this keyword to assign the value. I think the concept that you're thinking of is local scoping
For example,
function parent(){
var n = 5
function child(){
var n = 4 //n is 4 here
}
//n is 5 here
}
If I am not wrong, under strict mode, functions don't get access to global object (The 'this' is undefined for the function). On the other hand, inner function need access to its parent's 'this' for closure to work. Does JavaScript make an exception for inner functions under strict mode?
Closures have nothing to do with the this pointer. Closures are a concept of functional programming not object oriented programming. The this pointer is a concept of object oriented programming. Both can work simultaneously and independently without causing problems.
For example consider the following function in strict mode:
function getCounter() {
"use strict";
var count = 0;
return function counter() {
return ++count;
};
}
Here a call to the getCounter returns a closure. The function counter closes over the value count. You can then use the returned counter as follows:
var counter = getCounter();
counter(); // 1
counter(); // 2
counter(); // 3
I think you're confusing closures with nested functions. Read the following thread. It explains closures really well: JavaScript closures vs. anonymous functions
In strict mode the this pointer is undefined when it would point to the global object. Otherwise you may use it normally. This prevents you from accidentally creating global variables. However it doesn't cause any hinderance.
Consider the following constructor function for example:
function Counter() {
"use strict";
var count = 0;
this.increment = function () {
count++;
};
this.getCount = function () {
return count;
};
}
You can create an instance and use it as follows:
var counter = new Counter;
counter.increment();
counter.getCount(); // 1
However if you forget to put the new then this will point to the global object which in strict mode is undefined. Hence trying to assign the method increment to this will throw an error.
Getting back to the original question, you can always store the value of the this pointer in another variable if you wish to access it in a nested function. For example:
function Counter() {
"use strict";
var that = this;
that.count = 0;
return function counter() {
return ++that.count;
};
}
I know that this is a really stupid example but it has all the elements required to get my point across. You can now use the above function as follows:
var counter = new Counter;
counter(); // 1
counter(); // 2
counter(); // 3
That's all that there is to it.
By your question, I believe you meant Constructors and instanced objects. use strict pragma does not affect it. Accessing and calling an object's property of type function through dot or square brackets notation inside an expression automatically sets the ThisBinding to the object from which you got the function reference.
function Foo() {}
Foo.prototype.someMethod = function() {
console.log(this.blah);
};
var foo = new Foo();
foo.blah = 1;
//this:
foo.someMethod();
//implicitly does this:
foo.someMethod.call(foo);
Fiddle
TJ has probably explained this behavior in a simpler manner in Mythical Methods:
[...] when you call a function using an expression that gets the function reference from an object property (e.g., object.functionName() or object['functionName']()), the object is set automatically as "this" within the function call.
use strict only makes a difference when the this binding is not set (null or undefined), which is not the case here.
Then as you know, when the this reference is not set when entering function code, in non-strict mode it refers to the global object (the window object in browser environment) while in strict mode it is undefined. See ES5.1 Section 10.4.3
Now if you mean closures as in a function inside of another, use the old lexical scope trick.
function outerFunction() {
var _this = this;
function innerFunction() {
// _this references the outerFunction's this
}
}
This behavior is not influenced by use strict either.
var arrayfunc = [function(){return this;}];
var func = arrayfunc[0];
arrayfunc[0](); //[function (){return this;}]
func(); //Window
i don't know why this is not same? Do you help me ?
Just think as below:
arrayfunc[0](); // this refer to arrayfunc
window['func'](); // this refer to window
Even through arrayfunc[0] === func return true, the caller is different.
arrayfunc[0](); called the function through the object arrayfunc,
window['func'](); called the function through the object window.
Because this is a dynamic pointer to a function's scope. It is no fixed reference as in Java for instance.
This is a common misunderstanding. When you make an alias to a method - i.e., as you have, commit it to a variable - understand that you lose the this context in which the original method ran.
So for example:
var arr = [function() { alert(this[1]); }, 'hello'];
arr[0](); //'hello' - 'this' is the array
var func = arr[0];
func(); //undefined - 'this' is Window
Line 2 returns 'hello' because the method is running in the context of the array - since we invoked it from within it.
Line 4, however, invokes the same method but from the context of the alias we set up (func). This resets its context, so this points to the default - in a browser, this means window.
If you want to make a shortcut to a function but keep its context, you can do this with bind() (ECMA5 browsers only).
var func = arr[0].bind(arr);
func(); //'hello'
bind() creates a new function but bound to a particular context - in your case, the initial array it was taken from.
var test = {
demo: function(){
//get the caller context here
}
}
//when this gets called, the caller context should be window.
test.demo();
I tried arguments.callee and arguments.callee.caller,and no luck...
Since this keyword referes to ThisBinding in a LexicalEnvironment, and javascript (or ECMAScript) doesn't allow programmatic access to LexicalEnvironment (in fact, no programmatic access to the whole Execution Context), so it is impossible to get the context of caller.
Also, when you try test.demo() in a global context, there should be no caller at all, neither an attached context to the caller, this is just a Global Code, not a calling context.
By context, I assume you mean this? That depends on how the function is invoked, not from where it is invoked.
For example (using a Webkit console):
var test = {
demo: function() {
console.log(this);
}
}
test.demo(); // logs the "test" object
var test2 = test.demo;
test2(); // logs "DOMWindow"
test.demo.apply("Cheese"); // logs "String"
Incidentally, arguments.caller is deprecated.
The value of a function's this keyword is set by the call, it isn't "context". Functions have an execution context, which includes its this value. It is not defined by this.
In any case, since all functions have a this variable that is a property of its variable object, you can't reference any other this keyword in scope unless it's passed to the function. You can't directly access the variable object; you are dependent on variable resolution on the scope chain so this will always be the current execution context's this.
Strange how we are talking about this except for
'Qix - MONICA WAS MISTREATED''s comment. Either you are able to capture
window,
worker self,
v8::Isolate v8::context is extended in fetch for cloudflare workers (or use this of the class), or
rename some other function-method's scope-this-context outside, so
this hypothetical situation has no use case.
var test = {
demo: function(){
//get the caller context here
}
}
test.demo();
For closure, one could have a dynamically named function factory for some reason, while maintaining its context like so:
function body () {}
var test = {
demo: {
[name]: function () {return body.apply(body, arguments);}
}[name];
Without for loop, thisArg argument would be {demo:fn()}
var test = {demo:{}}
const createNamedFunc = (body) => {
test.demo = return {
[name]: function () {
return body.apply(body, arguments);
} } [name];
}
createNamedFunc(function body (){})
I gather this 'functional-method-parameter-object' is
the deepest-functional-method-child of the object-declarations
of the global scope receiver[ object]
passing it on, until the next non-object nor -data-type returnable type definition or instantiation, not necessarily declaration but always implement/extension scope interface.
This code results in "!" being logged on the console.
var g = {};
(function() {
var t = this;
t.x = "x";
g.a = function() {
console.log(t.x);
};
})();
(function() {
var t = this;
t.x = "!";
g.b = function() {
console.log(t.x);
};
})();
g.a();
Do anonymous functions share a this? Am I using this wrong? I don't really understand what's going on here.
I'd like for g.a() to continue returning the value of x defined in the first anonymous function.
I'm using node.js if it makes a difference.
In the immediate functions, this refers to the global object [docs]. So in this case in both functions this indeed refers to the same element and you are overwriting x with the second call.
What object this refers to is determined by how the function is called.
If you just execute a function with funcName();, then this refers to the global object.
If the function is assigned to a property of an object, obj.funcName() , this refers to the object.
If you call the function with the new operator, new funcName();, this refers to an empty object that inherits from the functions prototype.
You can also explicitly set this by using call [docs] or apply [docs].
Instead referring to this, you could create a new object in both functions:
var t = {};
Additional note: It makes no difference whether you run the code in the browser or with node.js. The global object is part of the specification and has to be provided by the execution environment. In browsers it is the window object, I don't what it is in node.js, but it does not matter as long as it follows the specification.
Felix Kling is the right long answer. But I wanted to chime in with what I think you actually want:
var g = {};
(function() {
var x = "x";
g.a = function() {
console.log(x);
};
})();
(function() {
var x = "!";
g.b = function() {
console.log(x);
};
})();
g.a(); // "x"
g.b(); // "!"
Now g.a() and g.b() both print out x, but each function has their own separate x shared with the closure. If these vars should be private an only accessible internally to each of these functions, this is how you hide them and persist them through multiple calls.
When I look at this script in the debugger in Chrome as you've shown it, the "this" value in both anonymous functions is set to the global variable "window". That means that each anonymous function is setting the value of window.x so the last one executed wins and is the value that survives, thus window.x == "!" after the second anonymous function executes.
It's unclear to me what you expected "this" to be or what you're actually trying to accomplish with this code so I don't know what alternative to suggest. If you just want the previous state in the anonymous function to survive for the internal function, then you can just rely on local variables (which will survive in the closure) and not use the "this" reference at all. Squeegy's example shows that.