why call.call invokes function - javascript

Here if I have a function which logs "called my function"
function myFunction() {
console.log('called my function')
}
Function.prototype.call.call(myFunction) // => "called my function"
while during a single call like:
function myFunction() {
console.log('called my function')
}
Function.prototype.call(myFunction)

When you write someFunction.call(foo), it means to call someFunction while passing foo as the this parameter. Normally you have someObject.someFunction(), which passes someObject as this implicitly, but with .call you can set this to anything you want. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call.
So what does Function.prototype.call(myFunction) do? Well, it calls Function.prototype, passing myFunction as this. What does calling Function.prototype do? According to the ECMA specification:
The Function prototype object is itself a Function object (its [[Class]] is "Function") that, when invoked, accepts any arguments and returns undefined.
That's why Function.prototype.call(myFunction) has no visible effect.
On the other hand, Function.prototype.call.call(myFunction) calls Function.prototype.call (which is itself a function!), passing myFunction as this. What does this do? Exactly the same as myFunction.call(): When you look up the call property of a function object, you get it from Function.prototype anyway (through object inheritance). So what does this do? It calls myFunction with no (normal) arguments, but the value of this it sees is a bit tricky: If the function is in strict mode, this will be undefined; if it is non-strict, this will be the global object (a.k.a. window in browsers).
This is also the same behavior you get from myFunction() (i.e. not calling it on an object). In other words, Function.prototype.call.call(foo) is just a (very) roundabout way of writing foo().

In short, call itself does not expect a function as an argument and will not invoke it's argument as a function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
Rather, call is member function of all Function objects defined in their prototype which enables you to invoke a specific implementation of a member function while passing the argument to be used as this in the function invocation. Since call itself is a Function, it too has a call member function.
One use case of this is emulation of the super concept in e.g. Java. Consider another example with a function other than call:
function Foo() {
console.log('Foo');
}
Foo.prototype.bar = function () {
console.log('Foo bar');
};
function Baz() {
console.log('Baz');
}
Baz.prototype = Object.create(Foo.prototype);
Baz.prototype.bar = function () {
Foo.prototype.bar.call(this);
// Call the super class implementation of `bar`
console.log('Baz bar');
};
var baz = new Baz();
baz.bar();

A little context:
call is a function that belongs to the Function object, as you probably know.
So if we have this function: (note the this)
function invite(where) {
alert ("hi "+this.name+" do you want come to "+where);
}
and this object:
var obj = { name:"PETER" }
we could do
invite.call(obj, "the cinema")
The first parameter to call is the CONTEXT. The function will be executed within the context of that object, that's why the alert will display "PETER" for this.name
The second parameters and so on are the parameters, that's why the alert will display "the cinema".
The second case: Function.prototype.call.call
Function.prototype.call is the raw "call" function of the function object. So you are accessing this function directly, and want to call it for your object ("call the function call"):
Function.prototype.call.call
You want the function "call" to be called within the context of your function myFunction (first call paramerer):
Function.prototype.call.call(myFunction, ...);
That is, in fact, equivalent to
nyFunction.call(...);
The first case
The first case does nothing because prototype is itself a function (that you can ".call" :) , so
Function.prototype.call(whatever)
would just be equivalent to
Function.prototype();
executed in the context of your function

Related

Javascript: function binding does not work with caller

I have a function foo that calls function bar. foo is bound to an element test.
When being called, bar stores its caller function (foo) inside the set s. When I now run the function foo inside s, strangely this is now set to Window. But I did bind the function, so what am I getting wrong?
var s = new Set();
function bar() {
s.add(bar.caller)
}
var test = document.getElementById('test');
test.foo = (function() {
bar();
console.log(this);
}).bind(test);
test.foo(); // output: test div
s.forEach(fn => fn()); // output: Window object
<div id="test"></div>
A bound function basically calls the function it is binding over¹ with the bounded this, so the callstack of your code looks like
[Bound] test.foo -> test.foo -> bar
So from bar's point of view, it was called from test.foo not from the bound function.²
¹ as stated in the spec:
A bound function is an exotic object that wraps another function object. A bound function is callable (it has a [[Call]] internal method and may have a [[Construct]] internal method). Calling a bound function generally results in a call of its wrapped function
² wether function.caller returns the upmost callstack entry is not quite clear, as it is not specified. That's an assumption.

Function.prototype.call unexpected behavior when assigned to a variable

The following code calls console.log prints "hello":
console.log.call(console, "hello")
However, the code below throws TypeError:
x = console.log.call
x(console, "hello")
throws:
Uncaught TypeError: x is not a function
at <anonymous>:1:1
Can anyone explain this weird scenario?
(Of course it's the same for both call and apply)
.call gets the function to call from its this parameter.
You're calling it via x with no this parameter, so it has no function to call (or rather, it tries to call window) and gives an error.
You need to bind your x variable to the log function:
x = console.log.call.bind(console.log);
Bonus: .call comes from Function.prototype, and is the same no matter how you access it. Therefore, Function.call.bind(console.log) also works (because Function is a function and therefore has .call). As does Date.call.
Note: I will use apply instead of call in my answer just because the wording/reading is a bit less confusing but the same answer stands for call.
You can imagine apply looking something like this:
Function.prototype.apply = function apply(context, rest) {
// `this` in here is the function object on which we call `apply` as a method
// we then invoke whatever is bound to `this` (it should be the function that was "applied")
// and change its context and pass the rest of the arguments
// Note: I'm using `call` since we don't have access to native function code that can call a function with an overwritten context
this.call(context, ...rest)
}
When you call the apply function (or any function for that matter) as a method on a function object (functions are first-class objects), this within it gets bound to the function (object) on which you called apply (this is one of the rules on how context is bound in JS when a function is called as a method of an object)
Function.prototype.apply = function apply(context, rest) {
this.call(context, ...rest)
// `this` is the function that `call` invokes
// in the example bellow, `this` is `console.log`
// so this function will do `console.log.call(console, 'example')`
}
console.log.apply(console, ['example'])
// ^^^^^^^^ console.log is the context because we are calling `apply` on it, with the dot (.) notation
However, when you store the apply function into a variable and invoke it then, then the rule for this binding is it to be undefined (in strict mode or the global window otherwise) and thus there's no function to call under the hood.
Function.prototype.apply = function apply(context, rest) {
this.call(context, ...rest)
// using the example bellow
// `this` is `undefined` now because `apply` was called like a regular function, not a method
// which means the code bellow does `undefined.call(console, 'example')`
}
// calling a function as a normal function (not a method via the dot notation), makes `this` be `undefined`
// therefore `apply` doesn't have a function which to call with an overwritten context
let apply = console.log.apply;
apply(console, ['example']) // error, `this.call is not a function`
In fact the scenario is normal.
You need to declare x as a function who encapsulate your logic like this:
ps: ...args is the spread operator in javascript (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
x = (...args) => console.log.call(...args)
x(console, "hello")

JavaScript "this" in a function block

this refers to the object it belongs to, for example:
var someObj = {
logObj : function() { return this }
}
obj.logObj() => someObj
and a function is an object. But then why does this in a function refer to the window, not the function? For example,
function someFunc() { return this }
won't return someFunc(), but window.
It's true, a function is an object. However, the statements inside the function are not called with this set to the function itself. That would keep this from referencing the object that it was called on, and therefore eliminate much of the usefulness of this. There are ways to accomplish what you seek though.
"When a function is called as a method of an object, the object is passed to the function as its this value." ECMAScript Specification 4.3.31
Functions are not called as methods of themselves. Functions not executed as methods of an object are called as methods of the global object (or undefined if in "strict" mode).
function test() {
console.log(this == window);
}
var obj = {'test': test};
test();
window.test();
obj.test();
If you really want for the this in a function to refer to itself, then you will have to add the function as a property of itself, or use a function such as apply, call, or bind which have a thisArg.
function test() { console.log(this) };
test.test = test;
test.test();
test.call(test);
test.apply(test);
test.bind(test)();
Context is most often determined by how a function is invoked. When a function is called as a method of an object, this is set to the object the method is called on:
var obj = {
foo: function(){
alert(this === obj);
}
};
obj.foo(); // true
The same principle applies when invoking a function with the new operator to create an instance of an object. When invoked in this manner, the value of this within the scope of the function will be set to the newly created instance:
function foo(){
alert(this);
}
foo() // window
new foo() // foo
When called as an unbound function, this will default to the global context or window object in the browser. However, if the function is executed in strict mode, the context will default to undefined.
There are at least two ways to create an object - with an object literal, or with an object constructor.
Only when you use the latter technique will this refer to the object it occurs within.
This is how to create an object with an object constructor (in your example, a literal was used) :
var objConstructor = function () {
this.logObj = function () {return this}
}
var obj1 = new objConstructor()

How to check if a function is called using call/apply

function foo(){
console.log('foo', this);
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
Is there any way to know if foo() was called using a normal invoke or call/apply?
http://jsfiddle.net/H4Awm/1/
No. You can't detect if a function is called from call/apply or normally.
They're not magical beings, all they do is set the arguments and this value. There is a subtle difference when it comes to undefined/undeclared values but that's it.
All .apply and .call do in ES5 is:
Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
It sets the internal caller attribute correctly so something naive like this would not work.
Unless you redefine Function.prototype.call and Function.prototype.apply (and pass another argument to your function), there is no way of doing so - the actual internal mechanics (the [[Call]] internal function) do not provide any method of signalling that it is called using ().
Compare the specification for a general function call and for Function.prototype.apply - each call the internal code of the function in exactly the same manner, and there is no external property set that is able to give you whether is called using that or not.
See the specification for the internal function [[Call]]:
13.2.1 [[Call]]
When the [[Call]] internal method for a Function object F is called with a this value and a list of arguments, the following steps are taken:
Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property. If F does not have a [[Code]] internal property or if its value is an empty FunctionBody, then result is (normal, undefined, empty).
Exit the execution context funcCtx, restoring the previous execution context.
If result.type is throw then throw result.value.
If result.type is return then return result.value.
Otherwise result.type must be normal. Return undefined.
There is no provision to change the running of a function from whether it is called using call/apply or not - the only thing that changes what it does are the arguments for the function itself and what is this meant to be within the function.
I hope this solve your problem:
function foo(){
console.log('foo', this);
if (typeof this.length === "number") {
//function has been apply
} else {
//function has been call
}
}
foo();
foo.call({ bar: 1 });
foo.apply([{ bar: 1 }]);
Try something like this:
function foo(){
console.log('foo', this);
console.log( arguments );
}
Function.prototype._apply = Function.prototype.apply;
Function.prototype.apply = function(ths,args){
args.unshift('apply');
this._apply(ths,args);
};
foo();
foo.call(this, { bar: 1 });
foo.apply(this, [{ bar: 1 }]);
Dirty, dirty hack:
function foo() {
var isNatural = !/foo\.(call|apply)/.test("" + foo.caller)
console.log(isNatural ? "foo()" : "foo.{call,apply}()")
}
function caller1() {
foo()
}
function caller2() {
foo.call(null, { bar: 1 })
}
function caller3() {
foo.apply(null, [{ bar: 1 }])
}
caller1()
caller2()
caller3()
It's just food for thought. Don't use it on production.
I can't think of a reason you should be checking for this but, you could check by comparing this === window, as that's the default scope (assuming browser based Javascript), but this could be faked by simply calling foo like so foo.call(window) which is basically what calling foo() is doing normally.
This also probably won't work using window for functions that are properties of other objects or prototypes.

Nested functions & the "this" keyword in JavaScript

"The this keyword always refers to the object that the containing function is a method of."
Great, sounds simple enough, but here's what I'm wondering about...
For example:
function func1() {
function func2() {
alert(this == window); // true
}
func2();
alert(this == window); // true
}
func1.func3 = function () {
alert(this == window); // false
alert(this == func1); // true
};
func1();
func1.func3();
Now, since func1 is actually a method of the global (window) object (a function object assigned to the property func1 of the global object) it makes sense that this inside func1 refers to the global object, and since func3 is a method of func1's function object it makes sense that this inside func3 refers to func1's function object.
The thing that bothers me is func2. I know that this inside a nested function is also supposed to reference the global object, but I'm not sure why since func2 is NOT a method of the global object. As far as I understand (and this is the part I might be completely wrong about) func2 is a method of func1's call (activation / variable) object. Now, if I'm right about this (and I'm not sure that I am) then shouldn't this inside func2 refer to func1's call object instead of the global object?
So, I guess my question would be: Is a nested function a method of the call (activation) object of the function it is nested in, and if so, shouldn't this refer to that call object instead the global object?
The this keyword always refers to the object that the containing function is a method of.
No. Unfortunately, it is not easy as that. The documentation of the this keyword at MDN gives a good overview. It is set to the object when the function is called as a method on it, but there are other possibilies. The default is that this is undefined when it is called without anything special, like you do with func1 and func2. For sloppy (non-strict) mode functions undefined (and null) are not used though, this does point to the global object (window in browsers) for them in that case - what you are observing.
But it could also point to fresh object instances when the function is called as a constructor (with the new keyword), or to an event target (like a DOM element) when used as a handler. Last, but not least, it could be set manually with call, apply or bind…
this has nothing to do with nesting. Nesting function declarations/expressions only affects the scope ("privacy", availability) of variables. While the variable scope of a function never changes, the value of this can be different on every invocation - it is more like an extra argument.
The meaning of the this keyword inside a function depends on the way the function is invoked. There are 4 different function invocation patterns in JavaScript.
function invocation pattern foo()
method invocation pattern o.foo()
constructor invocation pattern new foo
call/apply pattern foo.apply(...) or foo.call(...)
Only in #2 is it the case that this inside the function refers to the object of which the function is a method.
You are invoking func2() with the function invocation pattern. When doing so, this refers to the global object.
As suggested by #Bergi, see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this for more detail on the meaning of this and the different function invocation patterns.
but I'm not sure why since func2 is NOT a method of the global object.
Any thing defined inside a function is local to the scope of that function. So func2 belongs to the local scope of func1 and therefore is not attached to window.
In Javascript, the value of this is generally based on how you call the function. When you call a function without any leading object, this is usually set to the global parent object, which is window.
You can explicitly set the value of this in three ways:
myObj.func(a, b); //this set to myObj implicitly because myObj is the parent
func.call(myObj, a, b); //this set to myObj explicitly; the first argument
//to call sets the value of this for that function
func.apply(myObj, [a, b]); //this set to myObj explicitly; the first argument
//to apply also sets the value of this for that
//function.
this can be a tricky concept. MDN has a good article about this.

Categories