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.
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
}
So I have been researching the keyword "this" in JS and im not sure if I fully understand it clearly. So in an attempt to understand the "this" keyword, I started off by creating a JS object and seeing if I can return a value based on some math executed with the this keyword. The following code below is my initial attempt:
let myObject = {
objectFunc: function() {
this.thing = 10;
},
addFunc: function(x) {
let result = this.thing + x;
return result;
}
}
console.log(myObject.addFunc(20));
So I expected this console log to return 30, however Im getting a "NaN" in the console. Can someone explain to me why? and also point me to some easier to understand documentation/explanation that isn't the MDN linked above?
You're on the right track. The reason why it's giving you NaN is because "this.thing" hasn't been defined yet. It's only defined when you call myObject.objectFunc() first.
let myObject = {
objectFunc: function() {
this.thing = 10;
},
addFunc: function(x) {
let result = this.thing + x;
return result;
}
}
myObject.objectFunc()
console.log(myObject.addFunc(20));
An easy to understand explanation would be that JavaScript 'this' keyword refers to the object it belongs to. The value of 'this' differs depending on how a function is invoked. There are four rules for 'this', in order of precedence that can be used to determine what 'this' gets bound to.
Rule 1. Default Binding: When invoking a function declaration 'this' keyword bounds to the global object.
Rule 2. Implicit Binding: When dot notation is used to invoke a function.
Rule 3. Explicit Binding: When .call(), .apply(), or .bind() are used on a function.
Rule 4. New Binding: When invoking a function by the new keyword, 'this' bounds to newly created object.
The following code doesn't throw an error but I'm not entirely sure why.
In the doubleIt method I use the name of the object, returnObject instead of this.
After newInstance is instantiated I would expect that the term returnObject would be copied into the new doubleIt method. Because returObject only exists in the factory function if doubleIt was called from newInstance it would confuse the JS engine and throw an error. However it doesn't, it works fine. Why does this still work?
"use strict"
function factoryFunction(x) {
let returnObject = {
oneParameter: x,
doubleIt: () => returnObject.oneParameter * 2
// doubleIt: () => this.oneParameter * 2
// Why don't I have to use the 'this' version?
}
return returnObject;
}
let newInstance = factoryFunction(10);
console.log(newInstance.doubleIt());
The way javascript deals with situations like this is described in painstaking detail in documents like this.
That's not easy to parse for most humans, but the gist is that the left hand side of an assignment is processed first. So in your example returnObject gets a reference to the object. After than the value of the object is evaluated. So it sees that you are using returnObject which it already has a reference to and is able to lookup the oneParameter property at runtime. All this is captured in a closure, which means the returned object has access to the name returnObject.
To show that it's actually evaluating at runtime, you can change oneParameter and then call the function. It works as expected:
"use strict"
function factoryFunction(x) {
let returnObject = {
oneParameter: x,
doubleIt: () => returnObject.oneParameter * 2
// doubleIt: () => this.oneParameter * 2
// Why don't I have to use the 'this' version?
}
return returnObject;
}
let newInstance = factoryFunction(10);
newInstance.oneParameter = 100
console.log(newInstance.doubleIt());
Also, returnObject is not copied into the new doubleIt — doubleIt just has a reference that points to returnObject.
A closure captures its environment variables. Since returnObject was defined as a variable outside the closure, it will be captured by the closure.
What will happen in this case, is that a circular reference will be created where the closure doubleIt() will have a reference to returnObject and returnObject will have a reference to doubleIt().
With regard to "this", in your example, it refers to the window object, since the factory function was not invoked with "new". If it is invoked with "new", then it will refer to the factoryFunction. However, it will never refer to returnObject, since returnObject itself was never invoked with "new". In order to have "this" point to returnObject within doubleIt(), you will need to define a function for returnObject that will be invoked with new. The following snippet will work if you invoke factoryFunction with or without "new":
function factoryFunction(x) {
let returnObject = function(x) {
this.oneParameter = x;
this.doubleIt = () => this.oneParameter * 2;
};
return new returnObject(x);
}
let newInstance = factoryFunction(10);
let anotherNewInstance = new factoryFunction(10);
console.log(newInstance.doubleIt());
console.log(anotherNewInstance.doubleIt());
JavaScript object orientation is different from "classic" object orientation. When you create the new object returnObject is assumed as "this", since it is the object.
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
Suppose I have functions like:
function foo() {
}
function bar() {
}
I can write above as Object Literal notation:
var Baz = {
foo: function() {
},
bar: function() {
}
};
As far as I understand in the later case, an instance of Baz will be created when the script loads regardless if any Baz function is ever called. In the former case, function object is only created when that function is called. Am I correct about these assumptions?
If I am correct then the former would have higher performance (less memory) than the later in application where these functions are rarely called.
But the advantage of the later is that it gives greater modularity and lower global namespace pollution.
What is your take on this from your professional experience?
Is there a speed difference?
In the former case, function object is only created when that function is called.
No, the functions are created regardless.
Note that you can also do this:
function foo() {
}
function bar() {
}
var Baz = {
foo: foo,
bar: bar
};
Or this:
var Baz = (function() {
function foo() {
}
function bar() {
}
return {
foo: foo,
bar: bar
};
})();
The primary purpose of putting the functions on Baz as properties is to make them available as "methods" on Baz. This might be for convenience, for "namespacing", etc. In your first form (and my first form above), if that code is at global scope, foo and bar are added to the global scope, which can get pretty crowded pretty fast (esp. on browsers). In your second example, the only global symbol is Baz because the functions are anonymous. In my final example above, the only global symbol is Baz but the functions aren't anonymous, they have names that debuggers and stack traces can show you (which is a good thing; more here).
In terms of trying to optimize when functions get created, here's how it works: When execution enters a given context (the global context, or the context related to calling a function), these things are done:
A behind-the-scenes execution context object is created.
A behind-the-scenes variable object for that execution context is created.
In the case of a function context:
A property is added to the variable object for arguments (the array-like thing you can use to access arguments)
A property is added to the variable object for each of the function's named arguments, with the value of the argument
If the function has a name, its name is added as a property of the variable object and has the value of the function object.
Properties are created on the variable object for each variable declared with var in the execution context; their values are initially undefined (regardless of whether the var has an initializer on it).
Every function declaration in the context is processed. (Function expressions are not processed yet; more on the difference below.) A property on the variable object for each function name is created and receives the function object as its value.
Step-by-step code execution begins.
Like all expressions, function expressions are evaluated when they're encountered in the step-by-step flow.
var statements that have initializers (e.g., var a = 2;) are treated exactly like assignment statements (a = 2;); the var aspect of it was done much earlier. (var is frequently misunderstood. For instance, we had this question just yesterday.)
You'll note the difference above between function declarations and function expressions. You can tell which is which by looking to see whether you're using the result as a right hand value — that is, are you assigning the result to a variable, using it as the right-hand side of a property definition in an object literal, or passing it into a function. If you are, it's a function expression. If you're not, it's a function declaration.
Function declaration example:
function foo() {
}
Function expression example:
var foo = function() {
};
Another:
var Baz = {
foo: function() { }
};
(The foo line is a property declaration in an object literal that uses a function expression for the value.)
Named function expression example:
var f = function foo() { // <== Don't do this (more below)
};
Named function expressions should be valid, but they're poorly-supported by implementations in the wild (particularly IE) and so for now they must be avoided. More here.