Why use (function(){}).call(this);? [duplicate] - javascript

This question already has answers here:
Reason behind this self invoking anonymous function variant
(5 answers)
Closed 8 years ago.
I've been studying some JS libraries lately that were written by people who really knew what they were doing, and I keep seeing this pattern, and I can't find information about it. I read the docs on the .call() method, but it didn't really make sense to me. I'm hoping to get one of those good old classic in-depth SO explanations with examples.
(function(undefined){
/*(insert entire library here)*/
}).call(this);
What is this about? Why is this a good way to write a library?
Note, sometimes the undefined is omitted, though I have no idea what difference it makes to put it there or not. I don't even know where the arguments are coming from, or who the caller is.

Let's disassemble this piece of code.
First off there is an anonymous function with immediate invocation. It's similar to this:
(function () {/**/}).call();
(new Date()).getTime(); // timestamp since 1970 jan 1 in milliseconds
We don't assign new Date() to a variable, instead we use it immediately.
Now why use .call instead of just ()?
.call is a method all Functions have. The first argument is what this will be bound to, subsequent arguments will be passed as arguments to the function. So:
(function () {
console.log(this.foo); // bar
}).call({ "foo": "bar" });
This works in conjunction with undefined (see below).
.call is the same as .apply with one minor difference. .apply only takes 2 arguments, where the 2nd is an array of arguments. This would be similar:
(function () {}).call(this, "foo", "bar");
(function () {}).apply(this, [ "foo", "bar" ]);
A common use of apply is in conjunction with the magic variable arguments.
(function () {
console.log(Array.prototype.slice.call(arguments, 1)); // [ "bar" ]
})([ "foo", "bar" ]);
Array.prototype.slice.call(arguments, 1) may look scary but really it's just arguments.slice(1), but arguments isn't an Array so it doesn't have a slice function. We borrow Arrays slice function and use .call to set the this to arguments. Array.prototype.slice(arguments, 1??) is incorrect.
Now why is there this in .call(this)? this always points to the context you're in. If you're in an instance of a class it will point to the instance and if you're in the global scope it will point to that. In a browser environment it is also window.
Why undefined? Since we did a .call(this) with no second argument, all arguments to our anonymous function are undefined. I'm not really sure why you need to make an explicit variable named undefined there. Maybe this is support for some browsers or some lint tool that likes to see undefined defined.
Thanks to #TedHopp. undefined is fickle.
var undefined = "foo";
console.log(undefined); // undefined
(function (undefined) {
console.log(undefined); // "foo"
})("foo");
You can just as easily have:
(function () {
/* code here */
}());
This is completely valid and works just the same. There might be some performance or linting benefits to use the form you posted.

Related

Why doesn't Javascript bind my dot expression correctly? [duplicate]

This question already has answers here:
Cases where 'this' is the global Object in Javascript
(4 answers)
Closed 5 years ago.
I am wondering whether dot-abstraction methods (e.g. dog.bark) bind at runtime or at compile-time. My question concerns the following code, which throws an error:
(true ? ''.toLowerCase : ''.toUpperCase)()
But the following does not:
true ? ''.toLowerCase() : ''.toUpperCase()
Why is my string literal '' not getting resolved in the first example?
(true ? ''.toLowerCase : ''.toUpperCase)()
is equivalent to:
String.prototype.toLowerCase.call()
// or:
String.prototype.toLowerCase.call(undefined)
However,
true ? ''.toLowerCase() : ''.toUpperCase()
is equivalent to:
String.prototype.toLowerCase.call('')
In both cases, the first argument to call is converted to an object, which the this in String.prototype.toLowerCase will reference to.
undefined can't be converted to an object, but the empty string can:
function logThis () { console.log(this); }
logThis.call('');
The SO snippet console only shows {}, but it's actually the same thing that you get from new String(''). Read about the string wrapper on MDN.
This is actually quite simple once you get how methods work in javascript behind the scenes.
toUpperCase is a method. This is a function that operates on a specific object... usually via the this variable.
Javascript is a prototypal language... meaning that the functions attached to objects are just functions and can be copied. There is some work behind the scenes that makes sure this is set to the right thing when you call a method, but this work only happens when you call it as a method... as in the obj.method() form.
In other words: ''.toUpperCase() makes sure that this is set to the string '' when you call it.
When you call it as toUpperCase() this is not set to anything in particular (different environments do different things with this in this case)
What your code does could be rewritten as this:
var function_to_call;
if (true) {
function_to_call = ''.toLowerCase;
} else {
function_to_call = ''.toUpperCase;
}
function_to_call();
Because your function call: function_to_call() is not in the object.method() syntax, the thing that sets this to the correct object is not done, and your function call executes with this not set to what you want.
As other people have pointed out, you can use func.call(thing_to_make_this) or func.apply() to attach the correct thing to this explicitly.
I find it much more helpful to use .bind() - which is extremely under-used in my opinion. function_name.bind(this_object) gives you a new function that will always have this attached to the correct thing:
// assuming function_to_call is set
function_that_works = function_to_call.bind(my_object)
function_that_works(); // equivalent to my_object.function_to_call()
and this means you can pass around the function you get back from bind() as you would a normal function, and it will work on the object you want. This is especially useful in callbacks, as you can create an anonymous function that is bound to the object it was created in:
// this won't work because when this runs, 'this' doesn't mean what you think
setTimeout(function() { this.display_message('success'); }, 2000);
// this will work, because we have given setTimeout a pre-bound function.
setTimeout(function() { this.display_message('success'); }.bind(this), 2000);
TL;DR: You can't call a method as a function and expect it to work, because it doesn't know what this should be. If you want to use that function, you have to use .call(), .apply() or .bind() to make sure this is set correctly by the time the function executes.
Hope that helps.
Because these methods apply on the this context, and in your example the this is undefined
One way to override this variable by using bind method:
(true ? ''.toLowerCase : ''.toUpperCase).bind('Hello')();
this will return hello
Because when you do (true ? ''.toLowerCase : ''.toUpperCase)() you are not calling the function that is bound to a string. You are simply calling the function without any context.
Consider the following example:
var obj = {
objname: "objname",
getName: function() {
return this.objname;
}
}
When you call it with obj.getName(), it correctly returns the value, but when you do something like this:
var fn = obj.getName
fn() // returns undefined because `fn` is not bound to `obj`
In your first example the toLowerCase function is detached from its context (the empty string object) and then it's invoked. Since you don't reattach the function to anything it has undefined as its context.
This behavior exist to enable code reuse through mix-ins:
var obj1 = {
name: "obj1",
getName: function() { return this.name; }
}
var obj2 = {
name: "obj2",
}
obj2.getName = obj1.getName //now obj2 has the getName method with correct context
console.log(obj2.getName())

Keep babel class as `this` when using a member function in `setTimeout`

I have an ES2015 class, call it Foo, which has at least two member functions, bar and baz. In bar there is a call to setTimeout whose first parameter is this.baz. Works fine up to here, I inspected it in the debugger, and this does refer to the instance of my class. (Actually since I'm using babel, I end up with a _this = this substitution beforehand but anyway the right thing is being passed into the setTimeout, confirmed.)
The problem is when the setTimeout callback fires, it calls the right function baz, but the this inside of baz the value of this refers to Window instead. Babel tries to do a _this2 = this at the beginning of baz but it seems to be too late already.
So my problem appears, somewhere in between the function baz being passed and the time it is called, it loses its this scoping. My question is, am I doing something wrong with ES2015 or babel here? I feel like this is a common enough use case that it shouldn't require too much strain. Personally I'd like to do this all with Promise but due to business requirements I can't add too much new JS stuff at once.
Alternatively, is there a standard idiom for passing the scope of this as I need here? It seems really messy and counter-intuitive to have to pass the calling object of a member function in as one of its parameters.
Here's a minimal working example for reference:
class Foo{
bar(){
setTimeout(this.baz, 1000);
}
baz(){
console.log("this message should repeat roughly once per second");
this.bar();
}
}
And here's a screenshot of me using it on a very simple page, along with the error message:
Edit: I have to object to my question being marked as a duplicate. Of course I had searched seen the setTimeout questions before asking this one. However the ES2015 and class-based aspect of my question is relevant and important, since the ES2015 syntax transformation of classes in babel changes the apparent behavior of this. My question was about whether there is another ES2015 design pattern to handle this, and why the intuitive class abstraction/encapsulation was being broken by passing a member function as a first-class value to be called externally. The most significant insight I gained was gleamed from a comment below by #FelixKing which I'll repeat here for posterity (in case anyone else is wondering):
Whether or not autobind class methods (like in Python) was discussed
but ultimately decided against, likely to keep consistency with the
rest of the language. There is also the question whether it would be
possible to autobind methods without memory/performance impact.
My question is, am I doing something wrong with ES2015 or babel here?
Actually, it's a expected JavaScript behavior and is related to how this is assigned in the language.
Consider the code below (no ES6, no babel...):
var obj = {
key1: 'value1',
key2: function() {
console.log(this);
}
}
obj.key2(); //will print obj
var callback = obj.key2; //assigned the function reference to some random variable
callback(); //will print Window/global object
As you can see, this is defined when the function is invoked, not when it's declared, and depends how it's being called.
That's exactly what's happening inside setTimeout, or in any function that receives a function as a parameter:
/* fake */
function setTimeout(fnCallback, time) {
/* wait and when the time comes, call your callback like this: */
fnCallback(); //'this' will be Window/global
}
"Workarounds":
In order to pass the desired context (in the example above), we can force the context:
using .bind:
var callback = obj.key2.bind(obj);
callback(); //will print obj
or using .call:
var callback = obj.key2;
callback.call(obj); //will print obj
Or we can pass an anymous function an call our object from inside:
setTimeout(function() {
//here, 'this' is Window/global, because the anonymous function is being called from a callback assignment
obj.key2(); //will print obj
}, 3000);
In your example
So, in your example, in order to properly set the setTimeout callback and ensure that baz() will receive the class context, you can:
bind the function when setting it as a callback:
setTimeout(this.baz.bind(this), 1000);
in your class constructor, bind the baz method once; so, everytime it's called, will be assigned the class context. Like this:
class Foo{
constructor() {
this.baz = this.baz.bind(this)
}
bar(){
setTimeout(this.baz, 1000);
}
baz(){
console.log("this message should repeat roughly once per second");
this.bar();
}
}
Use arrow functions. Another way of specifying the this context is using arrow functions, that, actually, ensure the this assignment is done through lexical scope (not anymore in the function invocation, but in the function declaration).
setTimeout(() => this.baz(), 1000);
// ^^^^
// 'this' here is your class, will pass your class as 'this'
// to the baz() method, due to the dot before
Different from:
setTimeout(function() { this.baz(); }, 1000);
// ^^^^
// 'this' here is Window/global, will thrown undefined method

Can you get the property name through which a function was called?

I've done a lot of searching and some playing around, and I'm pretty sure the answer to this question is no, but I'm hoping a JavaScript expert might have a trick up his sleeve that can do this.
A JavaScript function can be referenced by multiple properties, even on completely different objects, so there's no such thing as the object or property that holds the function. But any time you actually call a function, you must have done so via a single object (at the very least, the window object for global function calls) and property on that object.
(A function can also be called via a function-local variable, but we can consider the function-local variable to be a property of the activation object of the scope, so that case is not an exception to this rule.)
My question is, is there a way to get that property name that was used to call the function, from inside the function body? I don't want to pass in the property name as an argument, or closure around a variable in an enclosing scope, or store the name as a separate property on the object that holds the function reference and have the function access that name property on the this object.
Here's an example of what I want to do:
var callName1 = function() { var callName = /* some magic */; alert(callName); };
var obj1 = {'callName2':callName1, 'callName3':callName1 };
var obj2 = {'callName4':callName1, 'callName5':callName1 };
callName1(); // should alert 'callName1'
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'
From my searching, it looks like the closest you can get to the above is arguments.callee.name, but that won't work, because that only returns the name that was fixed to the function object when it was defined, and only if it was defined as a named function (which the function in my example is not).
I also considered that maybe you could iterate over all properties of the this object and test for equality with arguments.callee to find the property whose value is a reference to the function itself, but that won't work either (in the general case), because there could be multiple references to the function in the object's own (or inherited) property set, as in my example. (Also, that seems like it would be kind of an inefficient solution.)
Can this be done?
Short answer:
No, you cannot get "the property name" used to call your function.
There may be no name at all, or multiple names across different scopes, so "the property name" is pretty ill defined.
arguments.callee is deprecated and should not be used.
There exists no solution that does not use arguments or closure.
Long answer:
As thefourtheye commented, you should rethink what you are trying to do and ask that instead in a new question. But there are some common misconceptions, so I will try to explain why you cannot get the "simple property name".
The reason is because it is not simple.
Before we go ahead, let us clarify something. Activation Objects are not objects at all.
The ECMAScript 5.1 specification calls them Environment Records (10.2.1), but a more common term is Scope chain.
In a browser the global scope is (often) the window object, but all other scopes are not objects.
There may be an object that you use to call a function, and when you call a function you must be in some scope.
With few exceptions, scopes are not objects, and objects are not scopes.
Then, there are many names.
When you call a function, you need to reference it, such as through an object property. This reference may have a name.
Scope chain has declarations, which always have a name.
A Function (the real function, not reference) may also have a function name - your arguments.callee.name - which is fixed at declaration.
Not only are they different names, they are not (always) the "the property name" you are seeking.
var obj = { prop : function f(){} }, func = obj.prop;
// "obj" and "func" are declarations.
// Function name is "f" - use this name instead of arguments.callee
// Property name is "prop"
func(); // Reference name is "func"
obj.prop(); // Reference names are "obj" and "prop"
// But they are the same function!
// P.S. "this" in f is undefined (strict mode) or window (non-strict)
So, a function reference may comes from a binding (e.g. function declaration), an Object (arguments.callee), or a variable.
They are all References (8.7). And reference does have a name (so to speak).
The catch is, a function reference does not always come from an object or the scope chain, and its name is not always defined.
For example a common closure technique:
(function(i){ /* what is my name? */ })(i)
Even if the reference does have a name, a function call (11.2.3) does not pass the reference or its name to the function in any way.
Which keeps the JavaScript engine sane. Consider this example:
eval("(new Function('return function a(){}'))()")() // Calls function 'a'.
The final function call refers the eval function, which refers the result of a new global scope (in strict mode, anyway), which refers a function call statement, which refers a group, which refers an anonymous Function object, and which contains code that expresses and returns a function called 'a'.
If you want to get the "property name" from within a, which one should it get? "eval"? "Function"? "anonymous"? "a"? All of them?
Before you answer, consider complications such as function access across iframes, which has different globals as well as cross origin restriction, or interaction with native functions (Function.prototype.bind for example), and you will see how it quickly becomes hell.
This is also why arguments.caller, __caller__, and other similar techniques are now all deprecated.
The "property name" of a function is even more ill defined than the caller, almost unrealistic.
At least caller is always an execution context (not necessary a function).
So, not knowing what your real problem is, the best bet of getting the "property name" is using closure.
there is no reflection, but you can use function behavior to make adding your own fairly painless, and without resorting to try/catch, arguments.callee, Function.caller, or other strongly frowned-upon behavior, just wasteful looping:
// returning a function from inside a function always creates a new, unique function we can self-identify later:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//the one ugly about this is the extra "()" at the end:
var obj1 = {'callName2':callName(), 'callName3':callName() };
var obj2 = {'callName4':callName(), 'callName5':callName() };
//test out the tattle-tale function:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
if you REALLY want to make it look like an assignment and avoid the execution parens each time in the object literal, you can do this hacky routine to create an invoking alias:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//make an alias to execute a function each time it's used :
Object.defineProperty(window, 'callNamer', {get: function(){ return callName() }});
//use the alias to assign a tattle-tale function (look ma, no parens!):
var obj1 = {'callName2': callNamer, 'callName3': callNamer };
var obj2 = {'callName4': callNamer, 'callName5': callNamer };
//try it out:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
all that aside, you can probably accomplish what you need to do without all the looping required by this approach.
Advantages:
works on globals or object properties
requires no repetitive key/name passing
uses no proprietary or deprecated features
does not use arguments or closure
surrounding code executes faster (optimized) than
a try/catch version
is not confused by repeated uses
can handle new and deleted (renamed) properties
Caveats:
doesn't work on private vars, which have no property name
partially loops owner object each access
slower computation than a memorized property or code-time repetition
won't survive call/bind/apply
wont survive a setTimeout without bind() or a wrapper function
cannot easily be cloned
honestly, i think all the ways of accomplishing this task are "less than ideal", to be polite, and i would recommend you just bite the coding bullet and pass extra key names, or automate that by using a method to add properties to a blank object instead of coding it all in an object literal.
Yes.
Sort Of.
It depends on the browser. (Chrome=OK, Firefox=Nope)
You can use a factory to create the function, and a call stack parsing hack that will probably get me arrested.
This solution works in my version of Chrome on Windows 7, but the approach could be adapted to other browsers (if they support stack and show the property name in the call stack like Chrome does). I would not recommend doing this in production code as it is a pretty brittle hack; instead improve the architecture of your program so that you do not need to rely on knowing the name of the calling property. You didn't post details about your problem domain so this is just a fun little thought experiment; to wit:
JSFiddle demo: http://jsfiddle.net/tv9m36fr/
Runnable snippet: (scroll down and click Run code snippet)
function getCallerName(ex) {
// parse the call stack to find name of caller; assumes called from object property
// todo: replace with regex (left as exercise for the reader)
// this works in chrome on win7. other browsers may format differently(?) but not tested.
// easy enough to extend this concept to be browser-specific if rules are known.
// this is only for educational purposes; I would not do this in production code.
var stack = ex.stack.toString();
var idx = stack.indexOf('\n');
var lines = ex.stack.substring(idx + 1);
var objectSentinel = 'Object.';
idx = lines.indexOf(objectSentinel);
var line = lines.substring(idx + objectSentinel.length);
idx = line.indexOf(' ');
var callerName = line.substring(0, idx);
return callerName;
}
var Factory = {
getFunction: function () {
return function () {
var callName = "";
try {
throw up; // you don't *have* to throw to get stack trace, but it's more fun!
} catch (ex) {
callName = getCallerName(ex);
}
alert(callName);
};
}
}
var obj1 = {
'callName2': Factory.getFunction(),
'callName3': Factory.getFunction()
};
var obj2 = {
'callName4': Factory.getFunction(),
'callName5': Factory.getFunction()
};
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'

Object methods assigned to variables or function arguments fail when invoked

I'm learning javascript right now, seems like beautiful functional language to me, it is wonderful move from PHP, I should have done this earlier. Although, I cannot figure this one out:
var v1 = (/[abc]/).test;
v1('a');
says test method called on incompatible undefined, I'm trying to store the test method of that regex into variable and invoke it later.
but it works with my own functions:
function foo(){
return 'I\'m foo';
}
var f = foo;
f(); // returns I'm foo
It should work on methods too, since functions are just methods of parent object anyway, right?
Ultimately, the reason I'm trying this is to be able to write something like this:
var a = ['a', 'b', 'c'];
a.every( (/[abc]/).test );
to check each array member against that regex.
Why doesn't this work? Is it limitation in passing built-in functions around? Or am I just doing something wrong?
PS: If you grind your teeth now and muffling something about bad practices, screw good practices, I'm just playing. But I'd like to hear about them too.
it works with my own functions
You are not using this inside the function. Consider this example:
var obj = {
foo: 42,
bar: function() {
alert(this.foo);
}
};
var f = obj.bar;
f(); // will alert `undefined`, not `42`
It should work on methods too, since functions are just methods of parent object anyway, right?
"Method" is just a colloquial term for a function assigned to a property on object. And functions are standalone values. There is no connection to the object a function is assigned to. How would this even be possible, since a function could be assigned to multiple objects?
Why doesn't this work?
What this refers to inside a function is determined at run time. So if you assign the function to a variable and call it later
var v1 = (/[abc]/).test;
v1('a');
this inside the function will refer to window, not to the regular expression object.
What you can do is use .bind [MDN] to explicitly bind this to a specific value:
var a = ['a', 'b', 'c'];
var pattern = /[abc]/;
a.every(pattern.test.bind(pattern));
Note though that since .bind returns a function, the only advantage over using a function expression is that it is a tad shorter to write.
Is it limitation in passing built-in functions around?
No, the problem exists for every method/function because that's how functions work. The nice thing about built-in functions though is that they often explicitly tell you when this is referring to the wrong type of object (by throwing an error).
Learn more about this.
If you store just a method, it does not carry with it a reference to your object - it just stores a reference to the .test method, but no particular object. Remember, a method is "just" a property on an object and storing a reference to a method doesn't bind it to that object, it just stores a reference to the method.
To invoke that method on a particular object, you have to call it with that object.
You can make your own function that calls the method on the desired object like this:
var v1 = function(x) {
return /[abc]/.test(x);
}
Then, when you do this:
v1('a');
It will execute the equivalent of this in your function:
/[abc]/.test('a');
But, it isn't entirely clear why you're doing that as you could also just define the regex and call .test() on it several times:
var myRegex = /[abc]/;
console.log(myRegex.test('a'));
console.log(myRegex.test('b'));
console.log(myRegex.test('z'));
The test function expects this to be a regular expression. The expression /[abc]/.test gives an unbound function (it does not remember that it belongs to /[abc]/). When you invoke it like you do, this will be undefined and the function will fail.
You can use bind to make the function remember the object it belongs to:
var v1 = /[abc]/.test.bind(/[abc]/);
or
var v1 = RegExp.prototype.test.bind(/[abc]/);
Your reference to the method has lost its knowledge of what it was a method of.
This isn't so much good practice as just the way JS works.
You can do:
var v1 = /[abc]/;
v1.test('a');
If you must encapsulate the test method, then you could do:
var v1 = function(str){
return /[abc]/.test(str);
};
v1('a');
I don't know if this is an acceptable solution, but you can do:
v1 = function(exp) { return (/[abc]/).test(exp); }
v1('a');

Javascript Module Design

I was wondering if someone could explain the difference between these two JavaScript modules. I have been trying to learn how to design javascript modules by reading some underscore.js and jQuery source code, amongst others and have noticed these two patterns.
Example 1
(function() {
var _this = this;
_this.VERSION = '0.1';
}).call(this);
Example 2
(function(_this) {
_this.VERSION = '0.1';
}(this));
call(obj[, arg[, arg[, arg[, ...]]]]) runs function in obj context, function () {}(obj) will run function in current context passing obj in arguments. In this particular example there is no difference - both examples will do same thing. For some people it is just cleaner to run anonymous function with call or apply instead of just () and I think here it is the case.
In second example line with var _this = _this; is useless, _this is already defined within scope and that line is redefining already existing variable with same value (so its even incorrect).
Example 1 explicitly sets the value of the this variable within the function.
In Example 2 the function does not care about the value of this. It rather expects an argument that it can work with. You also could say that it does not rely on the value of this. An advantage of this pattern is that by the name of the parameter it can be made clear what you want (window, myObjectContext ...).
In your specific case it does not make a difference. But if the function contained code that made actual use of this, e.g. this.myObject = {}, it could make a difference, because this could have a different value in each case. But to be true, someone using the second pattern would never reference this within the function.

Categories

Resources