Use of .call(this) on IIFE - javascript

I've seen an IIFE wrapped up with .call(this), rather than just (). Why would this be done?
The context: https://github.com/dmauro/Keypress/blob/development/keypress.js
(As I understand it, this would refer to the window object - which is where the IIFE would be called anyway. It seems redundant.)

If the IIFE is invoked without using call, the this inside it would refer to the global object window (or undefined in strict mode). Using .call(this) will pass to it whatever this is refereing to at the moment of the call (whatever the current context is). A situation where you want to use .call(this) instead of just calling it normally (), for example, is inside a class method where this will refer to the instance of the class and you want to pass that to your IIFE:
function A() {
(function() {
this.name = "A"; // "this" is not the instance of the class A
})();
}
var a = new A;
console.log(a.name);
function B() {
(function() {
this.name = "B"; // "this" is the instance of the class B
}).call(this); // because we explicitly passed it to the IIFE
}
var b = new B;
console.log(b.name);
Note:
It's worth mentioning that with arrow functions you can have the benifit of using the this of the enclosing execution without having to use .call(this) because arrow functions don't have their own this (they don't bind this):
function C() {
(() => {
this.name = "C"; // "this"'s value here is whatever value it has outside the IIFE
})(); // no need for .call(this) here
}
var c = new C;
console.log(c.name);

It's just a way of passing the value of lexical this into the IIFE - nothing more so that this inside the IIFE will have the same lexical value it had in the surrounding code. Depending upon where the IIFE is, this may not be the window object. It may have an actual lexical and local value.
If you don't use .call(this) on the IIFE, then the this value will be reset in the function to either the global object (which is the window object in a browser) or in strict mode, this will become undefined in the IIFE. Javascript resets the value of this according to how a function was called. You can see all the six different ways that this is controlled in this answer:
When you pass 'this' as an argument.
To tell you more about your situation, we'd have to see the actual code in context.
In the particular code you added a link to, I don't see any particular reason for doing it as I don't see any references to this at the top level of the IIFE. It appears to just be a coding habit that is generally used and is useful in some circumstances, but not needed or useful in others.

Related

Javascript hide the context

What's the best way for a method to call another method and pass the arguments in not-by-reference fashion?
i.e.
function main() {
let context = {};
// Pass context to someOtherFunction
// Such that console.log(context) in this function does not show `{whatever: true}`
}
function someOtherFunc(context) {
context.whatever = true;
}
I realize I can clone the context and pass that. But I was wondering if there was another way to do this, maybe using anonymous function wrap?
Okay, let's break this down a bit
const context = {x: true};
Above, you create an object (named context) in the global scope.
function(x) {
"use strict";
x.y = true;
}
You create an anonymous function that takes a reference to an object, and adds a new property y to that object
(/*...*/)(context);
You wrapped the above function into an IIFE so it immediately executes. For the parameter, you supplied a reference to the global context object, which is referenced by x inside the IIFE.
Objects are passed around by reference. Passing context in to the function doesn't create a new object x that is a copy of the context, it creates a new reference x that references the same object that context references.
If you need to actually copy the provided object into a new object, you need to do that yourself. As mentioned above, one mechanism is to stringify the object into JSON and then parse the JSON back to a new object. There are others depending on what you need to accomplish.
This isn't even a scope or context question at all - it's passing a reference to an object in to a function. Even if your IIFE had no way whatsoever of directly accessing the context variable, once you pass a reference to that object as an input to the function, the function has the reference and can do what it likes to it.
You also seem to misunderstand about how IIFEs hide data. You hide things inside the IIFE from things outside, not vice versa. Even then, it won't prevent you from passing a reference outside of the IIFE. Here's an example:
function changeName(animal) {
"use strict"
//myDog.name = "Rex"; // Error - myDog isn't a valid reference in this scope
//myCat.name = "Rex"; // Error - myCat isn't a valid reference in this scope either
animal.name = "Rex"; // Perfectly legal
}
(function () {
var myDog = {name: "Rover"};
var myCat = {name: "Kitty"};
console.log(myDog);
console.log(myCat);
changeName(myDog); // Even though changeName couldn't directly access myDog, if we give it a reference, it can do what it likes with it.
console.log(myDog);
})()
In this case, changeName has no access to myDog or myCat which are purely contained within the closure formed by the IIFE. However, the code that exists within that IIFE is able to pass a reference to myDog to changeName and allow it to change the name of the dog, even though changeName still couldn't access the object using the myDog variable.
This is because you are not technically redefining x, but adding properties to it.
I didn't really understood where your doubts came from so this is (to the best of my knowledge) an explanation of what your code is doing.
I'll try to translate the code to human-english.
Define the variable context in the "global scope". (It can be read from anywhere)
It cannot be redefined because its a constant.
Afterwards, define an anonymous self-invoking function (which "starts" a new "local scope" above the global scope so it has access to everything the global scope had access to)
This self invoking function grabs parameter x and adds the property y with a value of true to x and calls itself with the variable context
Read the value of context.
Please read:
JavaScript Scope
JavaScript Function Definitions (Self-Invoking Functions)

Shadowing `this` - lexical name resolution

EDIT: I think this isn't a duplicate; it being a hidden parameter, I wanted to ask about shadowing in relation to this, and lexical scoping, having read this SO Q/A re. shadowing.
I had thought that the meaning of the name this might be resolved kind of dynamically (in terms of scoping), so as to explain why it doesn't seem to me to be resolved lexically:
function foo() {return this;}
var a = {f: foo};
var b = {f: foo};
a.f() !== b.f();
a.f() !== foo();
a.f() !== window; //not strict mode
But then I read that every function receives this as an additional parameter, silently. (I realise arrow functions are different.)
Obviously helper() doesn't work as we might hope:
ob = {
meth: function(){
var helper = function() {return this;};
return helper();
}
};
ob.meth(); //Window or undefined
As far as I understand, rather than this being resolved by looking at the enclosing scope (the result being ob), instead the interpreter is calling helper() with this set to undefined (strict mode), silently passed as an argument.
So is the surrounding scope's this effectively being shadowed, hence lexical scoping is in fact in action?
You are correct. Except in the case of arrow functions, this is never resolved lexically. It always refers to one of the following:
the object upon which a function was called, such as valueOfThis.foo()
the first argument to apply or call, such as foo.apply(valueOfThis, params) or foo.call(valueOfThis, ...).
the DOM element, in the case of event handlers, such as <button onclick="alert(this.tagName.toLowerCase());"/>
the object being constructed, when a function is used as a constructor, such as Foo = function(){ ... }; new Foo()
the object bound to the function, if the function was created using bind, such as bar = function(){ ... this ...}; foo = bar.bind(valueOfThis); foo()
in a getter/setter, this refers to the object for which the property is being accessed or set, such as valueOfThis.someProperty = 123
window (usually) if none of the above cases, such as foo()
#Bergi provided a great reference for all these in the comments below.
In the case of bound functions, the function being called is actually a different function than was passed to the bind method, because the bind method creates a new function
So is the surrounding scope's this effectively being shadowed, hence lexical scoping is in fact in action?
Yes, one could view it from that perspective. The this bound to the helper scope shadows the one bound to the meth scope. (And if you had used an arrow function, it wouldn't).
However, you still need to remember that this is not an ordinary variable but a special keyword. It is only bound to function scopes, it's not writable, it has weird coerce-to-object semantics in sloppy mode, and it's always implicitly bound - as you say, a hidden parameter.
Unless you're trying to understand how this works in arrow functions (and their lexical resolution), the analogy with scopes and shadowing is pretty useless.

Why does this refer to window or object based on where parenthesis are placed? And return undefined

I am working on flexible javascript widget. In the course of some testing, I noticed that the context of this changes based on whether the parenthesis used to call a function are placed inside an object or in the global context of its call. Why do the parenthesis matter? And why would parenthesis inside the object refer to window and when placed in global context refer to the object. It seems like it would be the other way around.
Also undefined is returned in both instances. Is there a way to execute the function without returning anything?
I feel like I'm missing something important about this and don't want to miss out.
//this refers to window
var dataSource = {
read: read()
};
function read(){
console.log(this);
}
dataSource.read;
//this refers to dataSource object
var dataSource = {
read: read
};
function read(){
console.log(this);
}
dataSource.read();
Your code is doing two different things.
The first example is executing read() as the object definition is executed (read() is available because it's a function declaration and is hoisted, though this isn't related to the problem you're experiencing). It is called without any context so its this is window (as per the specification, where window is the browser's global object).
The second example has a reference to read(), which is then executed at the end of the block. Because it's executed as a property of dataSource, its this will become that. However, if you first assigned that reference to somewhere else and then invoked it via that reference, you'd again lose that this context.
For fine-grained control of this, take a look at bind(), call() and apply().
Also undefined is returned in both instances. Is there a way to execute the function without returning anything?
A function always has a return value (undefined if not explicitly set), but you're free to ignore it.
The scoping of this can be a tricky topic in javascript. That said, I can expand my answer on the general rules regarding the scope of this if need be.
But to answer your specific question, whenever you reference this inside an object literal, it by default, refers to the object literal itself.
Edit: as long as the function was invoked as a property of the object literal.
Where as, almost in any other situation I can call to mind, this will refer to the window object unless specified when invoking said function using apply() or call().
When this is used outside of objects it refers to the global object which in browser environment is window. Otherwise it refers to the last bareword before the last dot in the invocation.
For example:
function foo () {return this};
var bin = {bar:{foo:foo},foo:foo};
foo(); // returns window
bin.foo(); // returns bin
bin.bar.foo(); // returns bar
// ^
// |
// '------ last bareword before the last dot in the invocation
Now, as to why the location of the parenthesis matter. I think you should be able to guess by now:
When we add a parenthesis to a word (variable/name/reference) what we're doing is make a function call:
foo(); // call foo
If we don't add the parenthesis, what we're doing is refer to the object:
foo; // this contains the function foo
Note that not adding the parens is not calling the function. Therefore it should be obvious that when you do:
var bar = { foofoo : foo() }
What you're doing is passing the result of the function foo to bar.foofoo. The function is invoked without any "dots" in its invocation path. Therefore it doesn't belong to any object and therefore the rule of this == window applies.
On the other hand if you do:
var bar = { foo : foo }
What you're doing is assign the function foo to bar.foo. When you later call it as:
bar.foo()
the invocation contains a "dot" therefore the rule about the last object before the last dot applies.
See my previous answer to a related question for a detailed explanation on how this works in javascript: How does the "this" keyword in Javascript act within an object literal?

Scope of this in javascript function

If you have the following code:
var global = this;
function A () {
function B () {
return this;
}
return B();
}
var C = new A();
C === global // true
Why does the this in function B refer to the global space and not the this of the object A?
The value of this is determined upon every function call. Because B is called without any context, the value of this is the global object.
It's possible to preserve this in an outer context by simply copying it:
function A() {
var x = this;
function B() {
return x;
}
return B();
}
this has nothing to do with scope, it's not a variable. It's a keyword that evaluates to the currently executing function's object context. The function's object context is determined by how you call it. It doesn't matter where or how the function is defined.
When you call a function like fn() then it is not in object context and the language wrongly attempts to work around it when it should just throw an error at the mere sight of this. This is somewhat fixed in strict mode where it would evaluate to undefined.
When you call a function as a property of some object I.E. obj.fn() then obj is bound to this for that call.
Since it would be clunky having to attach a function to some object just to get the right object context for the call, all functions inherit a .call method that allows you to specify the object context explicitly:
return B.call(this);
To accompany Pointy's correct answer:
The reasoning for this is because you can do whatever you want with functions.
You can return function B from function A, and save it as a global variable.
Or you could append function B as a method to an Object, or a dozen objects.
Or you could use it in an AJAX callback, or use it as a callback from a timer.
Because the engine doesn't know what's going to happen with function B, the language says that this refers to whatever the function is being called on, at the time it's called.
This adds a lot of dynamism to the language, but it also adds a lot of headache, if you're not sure what "this" is pointing to at any given time.
Rule of thumb:
If the function is directly attached as the method of an object, or a function is being called with .call or .apply and being fed a context, like myFunc.call(myObj), then this refers to window.

How does "this" keyword work within a function?

I just came across an interesting situation in JavaScript. I have a class with a method that defines several objects using object-literal notation. Inside those objects, the this pointer is being used. From the behavior of the program, I have deduced that the this pointer is referring to the class on which the method was invoked, and not the object being created by the literal.
This seems arbitrary, though it is the way I would expect it to work. Is this defined behavior? Is it cross-browser safe? Is there any reasoning underlying why it is the way it is beyond "the spec says so" (for instance, is it a consequence of some broader design decision/philosophy)? Pared-down code example:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
Cannibalized from another post of mine, here's more than you ever wanted to know about this.
Before I start, here's the most important thing to keep in mind about Javascript, and to repeat to yourself when it doesn't make sense. Javascript does not have classes (ES6 class is syntactic sugar). If something looks like a class, it's a clever trick. Javascript has objects and functions. (that's not 100% accurate, functions are just objects, but it can sometimes be helpful to think of them as separate things)
The this variable is attached to functions. Whenever you invoke a function, this is given a certain value, depending on how you invoke the function. This is often called the invocation pattern.
There are four ways to invoke functions in javascript. You can invoke the function as a method, as a function, as a constructor, and with apply.
As a Method
A method is a function that's attached to an object
var foo = {};
foo.someMethod = function(){
alert(this);
}
When invoked as a method, this will be bound to the object the function/method is a part of. In this example, this will be bound to foo.
As A Function
If you have a stand alone function, the this variable will be bound to the "global" object, almost always the window object in the context of a browser.
var foo = function(){
alert(this);
}
foo();
This may be what's tripping you up, but don't feel bad. Many people consider this a bad design decision. Since a callback is invoked as a function and not as a method, that's why you're seeing what appears to be inconsistent behavior.
Many people get around the problem by doing something like, um, this
var foo = {};
foo.someMethod = function (){
var that=this;
function bar(){
alert(that);
}
}
You define a variable that which points to this. Closure (a topic all its own) keeps that around, so if you call bar as a callback, it still has a reference.
NOTE: In use strict mode if used as function, this is not bound to global. (It is undefined).
As a Constructor
You can also invoke a function as a constructor. Based on the naming convention you're using (TestObject) this also may be what you're doing and is what's tripping you up.
You invoke a function as a Constructor with the new keyword.
function Foo(){
this.confusing = 'hell yeah';
}
var myObject = new Foo();
When invoked as a constructor, a new Object will be created, and this will be bound to that object. Again, if you have inner functions and they're used as callbacks, you'll be invoking them as functions, and this will be bound to the global object. Use that var that = this trick/pattern.
Some people think the constructor/new keyword was a bone thrown to Java/traditional OOP programmers as a way to create something similar to classes.
With the Apply Method
Finally, every function has a method (yes, functions are objects in Javascript) named "apply". Apply lets you determine what the value of this will be, and also lets you pass in an array of arguments. Here's a useless example.
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
Function calls
Functions are just a type of Object.
All Function objects have call and apply methods which execute the Function object they're called on.
When called, the first argument to these methods specifies the object which will be referenced by the this keyword during execution of the Function - if it's null or undefined, the global object, window, is used for this.
Thus, calling a Function...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
...with parentheses - foo() - is equivalent to foo.call(undefined) or foo.apply(undefined), which is effectively the same as foo.call(window) or foo.apply(window).
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Additional arguments to call are passed as the arguments to the function call, whereas a single additional argument to apply can specify the arguments for the function call as an Array-like object.
Thus, foo(1, 2, 3) is equivalent to foo.call(null, 1, 2, 3) or foo.apply(null, [1, 2, 3]).
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
If a function is a property of an object...
var obj =
{
whereAmI: "obj",
foo: foo
};
...accessing a reference to the Function via the object and calling it with parentheses - obj.foo() - is equivalent to foo.call(obj) or foo.apply(obj).
However, functions held as properties of objects are not "bound" to those objects. As you can see in the definition of obj above, since Functions are just a type of Object, they can be referenced (and thus can be passed by reference to a Function call or returned by reference from a Function call). When a reference to a Function is passed, no additional information about where it was passed from is carried with it, which is why the following happens:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
The call to our Function reference, baz, doesn't provide any context for the call, so it's effectively the same as baz.call(undefined), so this ends up referencing window. If we want baz to know that it belongs to obj, we need to somehow provide that information when baz is called, which is where the first argument to call or apply and closures come into play.
Scope chains
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
When a Function is executed, it creates a new scope and has a reference to any enclosing scope. When the anonymous function is created in the above example, it has a reference to the scope it was created in, which is bind's scope. This is known as a "closure."
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
When you attempt to access a variable this "scope chain" is walked to find a variable with the given name - if the current scope doesn't contain the variable, you look at the next scope in the chain, and so on until you reach the global scope. When the anonymous function is returned and bind finishes executing, the anonymous function still has a reference to bind's scope, so bind's scope doesn't "go away".
Given all the above you should now be able to understand how scope works in the following example, and why the technique for passing a function around "pre-bound" with a particular value of this it will have when it is called works:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
Is this defined behavior? Is it
cross-browser safe?
Yes. And yes.
Is there any reasoning underlying why
it is the way it is...
The meaning of this is pretty simple to deduce:
If this is used inside a constructor function, and the function was invoked with the new keyword, this refers to the object that will be created. this will continue to mean the object even in public methods.
If this is used anywhere else, including nested protected functions, it refers to the global scope (which in the case of the browser is the window object).
The second case is obviously a design flaw, but it's pretty easy to work around it by using closures.
In this case the inner this is bound to the global object instead of to the this variable of the outer function.
It's the way the language is designed.
See "JavaScript: The Good Parts" by Douglas Crockford for a good explanation.
I found a nice tutorial about the ECMAScript this
A this value is a special object which is related with the execution
context. Therefore, it may be named as a context object (i.e. an
object in which context the execution context is activated).
Any object may be used as this value of the context.
a this value is a property of the execution context, but not a
property of the variable object.
This feature is very important, because in contrary to variables, this value never participates in identifier resolution process. I.e. when accessing this in a code, its value is taken directly from the execution context and without any scope chain lookup. The value of this is determinate only once when entering the context.
In the global context, a this value is the global object itself (that means, this value here equals to variable object)
In case of a function context, this value in every single function call may be different
Reference Javascript-the-core and Chapter-3-this
All the answers here are very helpful but I still had a hard time to figure out what this point to in my case, which involved object destructuring. So I would like to add one more answer using a simplified version of my code,
let testThis = {
x: 12,
y: 20,
add({ a, b, c }) {
let d = a + b + c()
console.log(d)
},
test() {
//the result is NaN
this.add({
a: this.x,
b: this.y,
c: () => {
//this here is testThis, NOT the object literal here
return this.a + this.b
},
})
},
test2() {
//64 as expected
this.add({
a: this.x,
b: this.y,
c: () => {
return this.x + this.y
},
})
},
test3() {
//NaN
this.add({
a: this.x,
b: this.y,
c: function () {
//this here is the global object
return this.x + this.y
},
})
},
}
As here explained Javascript - destructuring object - 'this' set to global or undefined, instead of object it actually has nothing to do with object destructuring but how c() is called, but it is not easy to see through it here.
MDN says "arrow function expressions are best suited for non-method functions" but arrow function works here.
this in JS:
There are 3 types of functions where this has a different meaning. They are best explained via example:
Constructor
// In a constructor function this refers to newly created object
// Every function can be a constructor function in JavaScript e.g.
function Dog(color){
this.color = color;
}
// constructor functions are invoked by putting new in front of the function call
const myDog = new Dog('red');
// logs Dog has color red
console.log('Dog has color ' + myDog.color);
Normal function or method
// Browswer example:
console.log(this === window) // true
function myFn(){
console.log(this === window)
}
myFn(); // logs true
// The value of this depends on the context object.
// In this case the context from where the function is called is global.
// For the global context in the browser the context object is window.
const myObj = {fn: myFn}
myObj.fn() // logs false
// In this case the context from where the function is called is myObj.
// Therefore, false is logged.
myObj.fn2 = function myFn(){
console.log(this === myObj)
}
myObj.fn2() // logs true
// In this case the context from where the function is called is myObj.
// Therefore, true is logged.
Event listener
Inside the function of an event handler this will refer to the DOM element which detected the event. See this question: Using this inside an event handler

Categories

Resources