Related
I've been experimenting with ES6 for a while now, and I've just come to a slight problem.
I really like using arrow functions, and whenever I can, I use them.
However, it would appear that you can't bind them!
Here is the function:
var f = () => console.log(this);
Here is the object I want to bind the function to:
var o = {'a': 42};
And here is how I would bind f to o:
var fBound = f.bind(o);
And then I can just call fBound:
fBound();
Which will output this (the o object):
{'a': 42}
Cool! Lovely! Except that it doesn't work. Instead of outputting the o object, it outputs the window object.
So I'd like to know: can you bind arrow functions? (And if so, how?)
I've tested the code above in Google Chrome 48 and Firefox 43, and the result is the same.
You cannot rebind this in an arrow function. It will always be defined as the context in which it was defined. If you require this to be meaningful you should use a normal function.
From the ECMAScript 2015 Spec:
Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.
To be complete, you can re-bind arrow functions, you just can't change the meaning of this.
bind still has value for function arguments:
((a, b, c) => {
console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()
Try it here:
http://jsbin.com/motihanopi/edit?js,console
From the MDN:
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.
This means you cannot bind a value to this like you want.
description: Stijn de Witt
You cannot use bind to change the value of this inside an arrow function. However, you can create a new regular function that does the same thing as the old arrow function and then use call or bind to re-bind this as usual.
We use an eval call here to recreate the arrow function you pass in as a normal function and then use call to invoke it with a different this:
code: me
const func = v => console.log(this);
const obj = {value: 10};
function arrowBindOld(context, fn) {
let arrowFn;
(function() {
arrowFn = eval(fn.toString());
arrowFn();
}).call(context);
}
arrowBindOld(obj, func);
update
const f = v => console.log(this, v);
const o = {value: 10};
/* new */
function arrowBind(context, fn) {
const arrowFnString = fn.toString();
return (function() {
return eval(arrowFnString);
}).call(context);
}
const fBound = arrowBind(o, f);
fBound(10);
/* use prototype */
Function.prototype.arrowBind = function(context) {
const arrowFnString = this.toString();
return (function() {
return eval(arrowFnString);
}).call(context);
}
const fBoundProto = f.arrowBind(o);
fBoundProto(20);
For years, js developers struggled with context binding, asked why this changed in javascript, so much confusion over the years due to context binding and the difference between the meaning of this in javascript and this in most of the other OOP languages.
All this leads me to ask, why, why! why would you wan't to rebind an arrow function! Those where created specially to solve all this issues and confusions and avoid having to use bind or call or whatever other way to preserve the scope of the function.
TL;DR
No, you cannot rebind arrow functions.
Short, You CANNOT bind arrow functions, but read on:
Imagine you have this arrow function below which prints this on the console:
const myFunc = ()=> console.log(this);
So the quick fix for this would be using normal function, so just change it to:
function myFunc() {console.log(this)};
Then you can bind it to any lexical environment using bind or call or apply:
const bindedFunc = myFunc.bind(this);
and call it in case of bind.
bindedFunc();
There are also ways to using eval() to do it, which strongly not recommended.
Do ES6 Arrow Functions Really Solve “this” In JavaScript
The above link explains that arrow functions this doesn't change with bind, call, apply functions.
It is explained with a very nice example.
run this in node v4 to see the "expected" behavior,
this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){
// bind the value of "this" on the method
// to try and force it to be what you want
this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar();
I think this is better solution
var f = (vm=this) => console.log(vm);
I asked the same question a couple days ago.
You cannot bind a value since the this is already bound.
Binding different this scope to ES6 => function operator
Maybe this example help to you :
let bob = {
_name: "Bob",
_friends: ["stackoverflow"],
printFriends:(x)=> {
x._friends.forEach((f)=> {
console.log(x._name + " knows " + f);
});
}
}
bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();
Well it's meant to be impossible to bind an object to an arrow function, never say never; I figured a hack that just might work.
function arrowToRegularFn(callback) {
let _callback = callback
const stringifiedCallback = callback.toString()
const isArrowFn = !stringifiedCallback.trim().startsWith("function")
if (isArrowFn) {
const isParamsInParantheses = stringifiedCallback.trim().startsWith("(")
const [fnParams, ...fnBody] = stringifiedCallback.split("=>")
_callback = eval("(function" + (!isParamsInParantheses ? "(" : "") + fnParams + (!isParamsInParantheses ? ")" : "") + "{" + fnBody.join("=>") + "})")
}
return _callback
}
// test cases
// our object to bind
const quiver = { score: 0 }
let arrow, regular;
// test - 1
arrow = () => this.score++
regular = arrowToRegularFn(arrow).bind(quiver)
regular()
console.log(quiver.score) // 1
// test - 2
arrow = (x, y) => this.score = x + y
regular = arrowToRegularFn(arrow).bind(quiver)
regular(1, 2)
console.log(quiver.score) // 3
// test - 3
arrow = (x, y) => { this.score = x + y }
regular = arrowToRegularFn(arrow).bind(quiver)
regular(3, 4)
console.log(quiver.score) // 7
// test - 4
arrow = function(x, y) { this.score = x + y }
regular = arrowToRegularFn(arrow).bind(quiver)
regular(5, 6)
console.log(quiver.score) // 11
Normal bind:
tag.on("Initialized", function(tag) {
nodeValueChanged(tag, currentNode)
}.bind(currentNode))
Arrow function bind:
tag.on("Initialized", (tag => { nodeValueChanged(tag, currentNode) }).bind(currentNode))
Arrow functions always have this based on its closest non-arrow function irrespective of where it is called. If there is no non-arrow parent it always refers to the global object.
While you are calling the arrow function using call/bind/apply it's doesn't point to the object which you are passing.
var obj = {a:1};
var add=(b)=>{
return this.a + b;
// basically here this.a will be undefined as it's trying to find in one level up which is parents of this function that is window.
}
add.call(obj,2);
So that's why passing object doesn't work in arrow function.
Everything started with this Question
Then an answer from #MinusFour
var slice = Function.call.bind(Array.prototype.slice);
I wanted to understand, whats happening under the hood,
my curiosity hence this Question.
what to achieve ? understanding of "Function.call.bind".
Step-by-step approach for the same
Started with MDN
NOTE : I am using NodeJS here
1)
var adder = new Function('a', 'b', 'return a + b');
console.log(adder(2, 6));
**OUTPUT **
8
This is expected, Nothing Fancy
2)
This is our end goal , calling function myFunc from the bounded
function (Function.call.bind(myFunc))
function myFunc(a, b) {
console.log(arguments.length, a, b, a + b);
}
3)
var adder = Function(myFunc);
console.log(adder.toString())
OUTPUT
function anonymous() { function myFunc(a, b) { console.log(a + b); } }
Expected! above code does nothing, because i am calling 'anonymous' ,
and it does nothing.
4)
var adder = Function.call(myFunc);
console.log(adder.toString())
OUTPUT
function anonymous() {
}
Expected!. '.call' calls 'Function', with 'this' set to 'myFunc' and with out any param or function body. so an empty anonymous function is the output. Now, I can do "var adder = Function.call(myFunc,myFunc);" to create the same function from step-3
So far so good
5)
var adder = Function.call.bind(myFunc);
console.log(adder.toString())
adder(2,6);
OUTPUT
function () { [native code] }
1 6 undefined NaN
Here first param is not passed to the 'myFunc' function.
this is taken as 'this' for function 'adder' (the bounded Function.call) ?
Now I understand(or did I misunderstood?) until now, but then
How does below code works ?
var slice = Function.call.bind(Array.prototype.slice);
function fn(){
var arr = slice(arguments);
}
in my case first param to adder is discarded(or Function.call consider it as 'this' for it), same should happen with slice above right ?
Anyway, i wanted to document it for a reference
I'm afraid you've gone off in slightly the wrong direction. This line:
var slice = Function.call.bind(Array.prototype.slice);
never calls Function and never arranges for it to be called later. The only thing Function is being used for there is its call property. Function could have been Object or Date or RegExp or any other function, or could have been Function.prototype; doesn't matter. Function.prototype would have been more direct and possibly less confusing.
This is a bit tricky to explain because it involves two layers of dealing with this, where this is different things at different times:
The call function calls functions with a specific this value you give it as its first argument, passing along any other arguments you give it. For example:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
foo.call(obj, "glarb"); // "this.name = bar, arg = glarb"
There, because we called call on foo, call called foo with this set to obj and passing along the "glarb" argment.
call knows what function it should call based on what this is during the call call. foo.call sets this during call to foo. That can be confusing, so let's diagram it:
foo.call(obj, "glarb") calls call:
call sees this = foo and the arguments obj and "glarb"
call calls this (which is foo):
foo sees this = obj and the single argument "glarb"
With regard to slice, you normally see call used with it used to create an array from something array-like that isn't really an array:
var divArray = Array.prototype.slice.call(document.querySelectorAll("div"));
or
var divArray = [].slice.call(document.querySelectorAll("div"));
There, we call call with this set to Array.prototype.slice (or [].slice, which is the same function) and passing in the collection returned by querySelectorAll as the first argument. call calls the function it sees as this, using its first argument as this for that call, and passing along any others.
So that's the first layer of this stuff.
bind is another function that functions have, and it's similar to call but different: Where call calls the target function with a given this and arguments, bind creates and returns a new function that will do that if you call it. Going back to our foo example:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObjAndGlarb = foo.bind(obj, "glarb");
fooWithObjAndGlarb(); // "this.name = bar, arg = glarb"
This is called binding things (obj and the "glarb" argument) to foo.
Unlike call, since bind creates a new function, we can add arguments later:
function foo(arg) {
console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObj = foo.bind(obj);
fooWithObj("glarb"); // "this.name = bar, arg = glarb"
Okay, now we have all our working pieces. So what's happening in your code? Let's break it into parts:
// Get a reference to the `call` function from the `call` property
// on `Function`. The reason `Function` has a `call` property is that
// `Function` is, itself, a function, which means its prototype is
// `Function.prototype`, which has `call` on it.
var call = Function.call;
// Get a reference to the `slice` function from `Array.prototype`'s `slice` property:
var rawSlice = Array.prototype.slice;
// Create a *bound* copy of `call` that, when called, will call
// `call` with `this` set to `rawSlice`
var callBoundToSlice = call.bind(rawSlice);
(callBoundToSlice is just called slice in your question, but I'm using callBoundToSlice to avoid confusion.) Binding rawSlice to call was the first layer of this handling, determining what call will see as this. Calling callBoundToSlice will call call with this set to rawSlice. Then call will call the function it sees as this (rawSlice), using its first argument as the value for this during the call (the second layer of this handling) and passing on any further arguments.
So our forEach with a collection from querySelectorAll can now look like this:
callBoundToSlice(document.querySelectorAll("div")).forEach(function(div) {
// Each div here
});
That passes the collecton returned by querySelectorAll into callBoundToSlice, which calls call with this as rawSlice, which calls Array.prototype.slice with this set to the collection. Array.prototype.slice uses this to copy the array.
All of that said, using slice to turn array-like objects into true arrays is a bit out of date. ES2015 introduces the Array.from method, which can be shimmed/polyfilled on JavaScript engines that don't have it yet:
var divArray = Array.from(document.querySelectorAll("div"));
This question already has answers here:
Why use named function expressions?
(5 answers)
Closed 7 years ago.
What's the point of naming function expressions if you can't really reference them by the names you give them?
var f = function g() {
console.log("test");
};
g(); // ReferenceError: g is not defined
Oh, but you can reference them by that name. Those names just only exist inside the scope of the function.
var f = function g() {
// In here, you can use `g` (or `f`) to reference the function
return typeof g;
};
console.log( typeof g );
// It only exists as `f` here
console.log( f() );
DOCS: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#Named_function_expression
One advantage that I find particularly useful is that it helps when debugging.
When an error occurs, you see the function name in the stacktrace in the console. Otherwise the line in the stacktrace would only refer to an anonymous function.
You can also make the purpose of the function clearer by giving it a name.
It's important if you create a recursive function that is passed around. When you name a function it then knows about itself, within its own scope.
Here I've created a sort of factory function that creates recursive functions. For the recursive functions to work properly they need to know about themselves.
You can imagine this applied in a broader sense, like returning a recursive function as a module export.
var
func = (function () {
return function rec (a) {
console.log(a);
return a >= 5 ? 'done' : rec(a + 1);
};
}),
invoke = function (f, args) {
return f.apply(null, args);
};
console.log(
invoke(func(), [1])
);
By very definition, what you have defined is not an anonymous function:
function [name]([param[, param[, ... param]]]) {
statements
}
Name:
The function name. Can be omitted, in which case the function
becomes known as an anonymous function.
Furthermore, a lot of peole would consider
var f = function() {
return 'test';
};
not to be an anonymous function since you can now invoke it by var name f() and can now pass the function as a parameter to other functions by the name functionThatTakesCallback(f).
In my head, a true anonymous function has no name whatsoever such as something passed to a call back:
$('#id').on('click', function(){
console.log("I am anonymous");
});
or as a function run immediately:
(function(when){
console.log("run me :", when);
})("right now");
With the syntax you are using now, in ES6 (most non IE browsers implement this feature), f.name is g. This is useful when debugging
You could use it to recur:
var f = function g (n, m) {
if (n>0) {
return g(n - 1, m = m + 'meta');
}
return m + 'test';
};
console.log(f(10, 'super'));
Reading about functional programming - got to currying, example has a simple currying function. I understand everything except the last else block.
var curry = function (fn, fnLength) {
fnLength = fnLength || fn.length;
return function () {
var suppliedArgs = Array.prototype.slice.call(arguments);
if (suppliedArgs.length >= fn.length) {
return fn.apply(this, suppliedArgs);
} else if (!suppliedArgs.length) {
return fn;
} else {
return curry(fn.bind.apply(fn, [this].concat(suppliedArgs)), fnLength - suppliedArgs.length);
}
};
};
If the supplied args are >=, call the function with the supplied arguments.
Else if suppliedArgs.length is falsy, return the original function without doing anything.
Else ???
I think recursively call the function?
I don't understand what .bind.apply accomplishes.
Is [this] just in an array because suppliedArgs.push wouldn't return the array?
Start by looking at how you call Function#bind():
fun.bind(thisArg[, arg1[, arg2[, ...]]])
Then consider how you use Function#apply():
fun.apply(thisArg, [argsArray])
So given for bind() we need to call it on a function, and give it multiple parameters (not an array), and all we have is an array of arguments (suppliedArgs in the code), then how can we do that? Well, the main way you can call a function that takes multiple arguments instead of a single argument that is an array is to use .apply() on the function. So then we have fn.bind.apply(...something...).
The first parameter to .apply() is the this value - which needs to be the function to be bound in the case of .bind() (see below for an explanation of why). Hence fn.bind.apply(fn, ...).
Then, the second parameter to .apply() is an array of all the arguments to the function you are invoking, which in the case of .bind() is thisArg[, arg1[, arg2[, ...]]]. Hence we need a single array, with the first value being the value for this within the function, followed by the other arguments. Which is what [this].concat(suppliedArgs) produces.
So the whole fn.apply.bind(fn, [this].concat(suppliedArgs)) thing produces a correctly bound function that will have the supplied arguments to the current function "prefilled", with the correct this context. This function that is produced is then passed as the fn parameter in a recursive call to curry(), which in turn will produce another function in the same way as the top level call will.
The overall effect is that whenever you call a function created by curry(), if you don't pass the expected number of parameters, you will get a new function which takes the remaining number of parameters, or you will evaluate the original function with the entire list of parameters passed in correctly.
e.g.
function addAllNums(a, b, c, d, e) {
return a + b + c + d + e;
}
var curriedAddAll = curry(addAllNums, 5);
var f1 = curriedAddAll(1); // produces a function expecting 4 arguments
var f2 = f1(2, 3); // f2 is a function that expects 2 arguments
var f3 = f2(4); // f3 is a function that expects 1 argument
var f4 = f3(5); // f4 doesn't expect any arguments
var ans = f4(); // ans = 1 + 2 + 3 + 4 + 5 = 15.
// OR var ans = f3(5); => same result
Why the different thisArg values?
Probably the most confusing thing about this line of code is the two different values for thisArg in .bind() and .apply().
For .apply(), the thisArg is what you want the value of this to be inside the function you are calling .apply() on. e.g. myFunction.apply(myObj, ['param1', 'param2']) is equivalent to myObj.myFunction('param1', 'param2').
In this particular case, .bind() is executed on the fn function, so we want fn to be the this value for .bind(), so it knows what function it is creating a bound version of.
For .bind(), the thisArg is what the value of this will be inside the bound function that is returned.
In our case, we want to return a bound function that has the same this value as we currently have. In other words, we want to maintain the this value correctly within the new function, so it doesn't get lost as you create new functions which happens when you call a curried function with less arguments than it expects.
If we did not maintain the this value correctly, the following example wouldn't log the correct value of this. But by maintaining it, the correct value will be output.
var myObj = {
a: 1,
b: curry(function (a, b, c, d) {
console.log('this = ', this);
return a + b + c + d;
})
};
var c = myObj.b(1,1,1); // c is a function expecting 1 argument
c(1); // returns 4, and correctly logs "this = Object {a: 1, b: function}"
// if "this" wasn't maintained, it would log the value of "this" as
// the global window object.
The last else block is the main and most important part of the curry function, as it is the actual line that carries the logic for currying.
return curry(fn.bind.apply(fn, [this].concat(suppliedArgs)), fnLength - suppliedArgs.length);
This is what returns the new function that needs n-1 arguments from your previous function. Why? It's a combination of multiple things:
fn.bind.apply simply calls a function in the context of the function itself, while supplying the needed args (suppliedArgs). Note how the next parameter to curry is fnLength - suppliedArgs.length, which reduces the arguments needed to what was passed.
Let's explain it with the help of ES6. Things are going to become more obvious.
// Imagine we have the following code written in ES5
function fn(a, b, c) {
console.log(a, b, c);
}
var arr = [1, 2, 3];
var funcWithBoundArguments = fn.bind.apply(fn, [null].concat(arr));
Let's convert ES5 to ES6 code
// ES6
function fn(a, b, c) { console.log(a, b, c) }
let arr = [1,2,3];
let funcWithBoundArguments = fn.bind(null, ...arr)
You see? When you bind a function we have to explicitly enumerate all the arguments like:
fn.bind(null, 1, 2, 3)
But how could we bind the content of an array if we don't know its content in advance?
Right, we have to use .bind.apply() where:
the 1st argument of apply is the function (fn) we bind
the 2nd argument is an array which gets the context (as the first item of array) that we bind our function to and the rest of the items of the array are the arguments (which number is variable) we bind to our function (fn).
I just started reading Functional JavaScript and immediately was introduced to a function that I don't understand:
function splat(fun) {
return function(array) {
return fun.apply(null, array);
};
}
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements([1, 2]);
//=> 3
How does splat(function(x, y) { return x + y }) work. It's called with the array [1,2], but it seems like the anonymous function inside the call to splat takes two parameters, not one array.
Putting console.log(fun) on line 2 of this code shows that fun is the entirety of the anonymous function(x, y) { return x + y }. console.log(array) after return function(array) { shows that array is [1, 2]. Where does array come from then?
Thanks much.
It might be simpler to see how this function would have been written without using the .apply method:
function splat(fun) {
return function(array) {
return fun(array[0], array[1]);
};
}
First you call splat, passing it a function:
var add = function(x,y){ return x + 1 };
var ff = splat(add);
At this point, ff refers to the function(array) function, meaning its an one-argument function. The private variable fun refers to the add function.
Now, you call ff passing its one argument
ff([1,2]);
and it uses the values in the array to call fun with two arguments
return fun(array[0], array[1]);
The only difference between this and the real example is that the apply method lets you work with any argument array length instead of hardcoding a specific length (2) like I did.
//Every time we call this function, we get another one back
function splat(fun) {
return function(array) { // <-- this one will be returned in splat();
return fun.apply(null, array);
};
}
//Step one, call splat, pass a function as parameter
var addArrayElements = splat(function(x, y) { return x + y });
/*
Get back a function that accepts an array, and will execute the function we just passed in on it
*/
// This will call the newly created function, func will be available because it's in a closure
addArrayElements([1, 2]);
The last thing is that, even if the anonymous function takes two parameters, we call apply on it so it will bind array[0] ==> x and array[1] ==> y
This is an example of a higher order function. That's a function that takes functions as arguments and returns functions instead of just regular values (though functions are "just regular values" in Javascript). In this case:
function splat(fun) {
splat takes a function as its argument...
return function(array) {
...and returns a new function which takes an array...
return fun.apply(null, array);
...and when called calls the first fun function with the array .applied as its arguments.
So splat takes one function which expects several parameters and wraps it in a function which takes an array of parameters instead. The name "splat" comes from languages like Ruby, where a * (a "splat" or "squashed bug") in the parameter list of a function accumulates an arbitrary number of arguments into an array.
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements is now basically:
function (array) {
// closed over variable:
// var fun = function(x, y) { return x + y }
return fun.apply(null, array);
}
Here this is realized by a closure, which closes over and "preserves" the original fun passed to splat in the new returned function.
addArrayElements = function(array) { fun.apply(null, array); };
BUT
it has a closure whereby the variable context of its containing scope (that of the splat function that created the anonymous function) remains visible and accessible.
In JavaScript, functions are first-class objects that can be referenced and passed as arguments or, as in this case, through the closure mechanism.
Edit: about JavaScript and scope
In most languages, variables are, by default, local to the scope they're defined in (which usually is a function's local symbol table). By contrast, in JavaScript a variable is local only if it is defined using the var keyword; otherwise, the symbol will be looked back in the chain of the containing scopes, up to the implicit root object (which in the case of web browsers is window. I.e.,
function foo() { someVar = "bar"; }
foo();
alert(someVar); // shows "bar"
Not being restricted to the local scope, the symbol has been (purposely or not) leaked to the root scope.
Taking it one step further:
function foo() {
var baz = function() {
someVar = "bar";
};
baz();
}
foo();
alert(someVar); // shows "bar"
However, if you declare someVar within foo:
function foo() {
var someVar;
var baz = function() {
someVar = "bar";
};
baz();
alert("someVar in foo=" + someVar); // shows "bar"
}
foo();
alert("someVar in root=" + window.someVar); // shows "undefined"
Note that in this last version I needed to use window.someVar instead of just someVar because someVar never got defined as a variable in the root scope nor as a property of the root object, which caused an error.
a more functional approach uses bind(), which is short enough you don't really need splat anymore, and it's always nice to eliminate closures:
var addArrayElements = Function.apply.bind( function(x, y) { return x + y } , null );
addArrayElements([1, 2]); // === 3