I'm trying to understand the difference between curry vs bind.
The implementation of bind is :
/*1*/ Function.prototype.bind = function ()
/*2*/ {
/*3*/ var fn = this,
/*4*/ args = Array.prototype.slice.call(arguments);
/*5*/ var object = args.shift();
/*6*/ return function ()
/*7*/ {
/*8*/ return fn.apply(object,
/*9*/ args.concat(Array.prototype.slice.call(arguments)))
/*10*/ };
/*11*/ }
The implementation of curry is :
/*1*/ Function.prototype.curry = function ()
/*2*/ {
/*3*/ var fn = this,
/*4*/ args = Array.prototype.slice.call(arguments);
/*5*/ return function ()
/*6*/ {
/*7*/ return fn.apply(this,
/*8*/ args.concat(Array.prototype.slice.call(arguments)));
/*9*/ };
/*10*/ };
I already know that curry is not an internal function (unlike bind which is in IE9+). But still:
Why do I hear people keep talking about curry , While they can simply use bind operation ?
The only difference is the context which is actually found only at the bind function.
differences
Example :
Let's say I have this function :
function add(x,y,z)
{
return x+y+z;
}
I could do it with curry :
alert(add.curry(2).curry(1)(4)) //7
But I could also do it with :
alert(add.bind(undefined,2).bind(undefined,1)(4)) //7
I don't understand why this curry term function exists while it is possible to add a dummy context to the bind function.
What am I missing ?
bind forces you to attach a context to the function, while by using curry, you can delay the specification of function context until invoking the curried function, useful in many cases.
consider the following example (not the perfect one, just to illustrate the idea):
function Query(sessionKey, dataBuilder) {
this.sessionKey = sessionKey;
this.url = "http://www.example.com/search";
this.dataBuilder = dataBuilder
this.search = function (term) {
$.ajax({
type: "POST",
url: this.url,
data: this.dataBuilder(term);
})
}
}
function dataBuilder(entity, query) {
var payload = JSON.stringify({
'entity': entity,
'searchTerm': query
'session': this.sessionKey // will be always undefined if bind(undefined,...) is used
});
return payload
}
var bindEx= dataBuilder.bind(undefined, "username");
var curryEx= dataBuilder.curry("username");
var usernameQuery = new Query("id1234",bindEx); // won't work, this.sessionKey will be undefined
usernameQuery = new Query("id1234",curryEx); // will work, this.sessionKey will be id1234 in the DataBuilder
There is a difference in intention.
Currying is to reduce the number of arguments, usually to avoid calling a function a lot with the same initial arguments. For example:
var celsiusToKelvin = add.curry(273.15);
bind() is to make sure that a function is attached to an object. It also happens to offer a currying facility, so yes you can use bind() to curry(), but if you want to curry, curry() has fewer arguments and shows your intention.
I'd think it has something to do with compatibility with older browsers as bind is only available since ECMAScript 5.
See this for a list of .bind() support: http://kangax.github.io/es5-compat-table/
Also from what I've heard, most people still use curry because it looks cleaner as it doesn't need that extra undefined in the arguments.
Related
Since bind is not a cross browser (old ones) function , there is a polyfill for it : ( from John Resig's book)
/*1*/ Function.prototype.bind = function ()
/*2*/ {
/*3*/ var fn = this,
/*4*/ args = Array.prototype.slice.call(arguments),
/*5*/ object = args.shift();
/*6*/ return function ()
/*7*/ {
/*8*/ return fn.apply(object,
/*9*/ args.concat(Array.prototype.slice.call(arguments)));
/*10*/ };
/*11*/ };
But I don't understand why do we need arguments at line #9.
I mean :
If I have this object :
var foo = {
x: 3
}
And I have this function :
var bar = function(p,b){
console.log(this.x+' '+p+' '+b);
}
So , if I want bar to run in the foo context , with parameters - All I need to do is :
var boundFunc = bar.bind(foo,1,2)
boundFunc ()...
So When I run var.bind(foo,1,2) the arguments is [object Object],1,2.
Those arguments are saved at line #4.
Great.
Now , the bind function returns its own closured function :
function ()
{
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
}
Question
Why do we need arguments here ? it seems that they are for something like :
var boundFunc = bar.bind(foo,1,2)
boundFunc (more1,more2....) //<----- ??
Am I missing something ?
Oonce I set the first var boundFunc = bar.bind(foo,1,2) , I already declared the parameters. why do we need them twice ?
There are two places you can pass in arguments to the bound function:
1) When you call bind (the first arguments). These are always applied to the bound function when it is called.
2) When you call the bound function (the second arguments). These are the "more1, more2" that you mention. These change depending on what is provided when the bound argument is called.
Line 9 is combining the original bound arguments with the supplied extra arguments.
I guess the concept you might be confused about is that you don't have to bind ALL arguments initially - you can bind just the context object, or you can bind the first one argument as well but have callers of the bound function supply the rest. For example:
function sum() {
var _sum = 0
for (var i = 0; i < arguments.length ; i++) {
_sum += arguments[i];
}
return _sum;
}
var sum_plus_two = sum.bind({},2);
sum_plus_two(5,7) == 14;
.bind also serves as partial application solution. Event handlers might be the best example:
var handler = function(data, event) { };
element.addEventListener('click', handler.bind(null, someData));
If the arguments from the actual function call wouldn't be passed on, you couldn't access the event object.
In the functional inheritance pattern, Crockford introduces a new superior method via:
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function () {
return method.apply(that, arguments);
};
});
Where method is :
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Example:
var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.superior('get_name');
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
My question is Why don't just assign that.get_name to super_get_name ?
"My question is Why don't just assign that.get_name to super_get_name?"
Because the way the get_name method has its this value set to the that object is by invoking it as:
that.get_name();
When a function is invoked as the method of an object, the object becomes the value of this in that invocation of the function.
If you had done this instead:
var super_get_name = that.get_name;
super_get_name();
Now you're invoking a detached function, so it doesn't know what its this value should be, and so it uses the default, which is usually the window object.
I don't like the solution that crockford shows at all. Typically, in that situation, you'd simply make a new function right there instead of relying on extensions to Object.prototype to do it for you. (Extending Object.prototype is very ugly IMO.)
var coolcat = function (spec) {
var that = cat(spec),
_original_get_name = that.get_name,
super_get_name = function() {
return _original_get_name.apply(that, arguments);
};
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
Or in modern implementations, you'd use Function.prototype.bind to create a new function with its this value bound to whatever you provided as the first argument to .bind().
var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.get_name.bind(that);
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
In the sense of Crockford's Functional Inheritance Pattern it is completely valid to reference the base class method
var super_get_name = that.get_name;
This is how Crockford teaches it in his lecture JavaScript Master Class , see the part on Functional Inheritance.
Later - the method might be overriden by the derived class - you invoke it simply
super_get_name();
Crockford's superior method makes no sense in the Functional Inheritance Pattern.
Because in my opinion this is never needed in a method defined by a producer function. If you use this in your methods you'll run in all sorts of trouble because of dynamic scoping and manipulation of this:
function mammal(spec){
var that = {};
that.legs = Math.round(Math.random() * 4);
that.get_name = function(){
return spec.name + "with" + that.legs; // always use that not this
};
that.isProperThis = function(){
console.log( this === that );
};
return that;
};
var myMammal = mammal({name: 'Herb'});
myMammal.isProperThis(); // true
myMammal.isProperThis.call(window); // false
setTimeout(myMammal.isProperThis, 1); // false
If you insist on using this in your methods you can no longer treat them as "first-class" variables in JavaScript. Instead you have to convert them to "binders" by calling bind as described in the first answer in this post.
superior is a method defined in the prototype of the Object constructor function. It caches an object's method, so that it returns the original method even if it were changed later.
From JavaScript: The Good Parts, p.54:
The function will invoke the original method even if the property is changed.
The accepted answer given by cookie monster is correct, but I would like to add clarification.
As cookie monster says, if you write
var super_get_name = that.get_name;
invocation of super_get_name will no longer bind any value to this, making it an unbound function.
However, in the case of the example Crockford gives in The Good Parts, it would not matter if super_get_name were unbound by writing it in the way you propose, because this would never be used in its invocation.
You would essentially end up doing the following:
super_get_name = function () {
return that.says() + ' ' + spec.name +
' ' + that.says();
(where the right operand executes in the context of the function assigned to cat).
I assume that Crockford avoids unbound functions here to demonstrate a general principle, even though his specific example does not require binding.
when i try to call a function inside the object using "this" from a callback function, an error occur saying that the method is undefined.
How can I solve this issue!.
var object_log = {
user: "",
pass: "",
error_message: "an error occured while connecting",
init: function(user, pass) {
this.user = user;
this.pass = pass;
},
login: function() {
remote_submit(identify, this.success, this.error);
},
error: function() {
alert(this.error_message);
},
success: function() {
alert("success");
}
};
You need to use the .call() or .apply() methods on the callback to specify the context which the method is called upon.
The callback method remote_submit does not know what this will be anymore and thus when it calls the callback methods they're executed like normal functions not on an object.
You can "Bind" your functions by wrapping them on the way out:
var self = this;
remote_submit(
identify,
function() { return self.success.apply(self, arguments); },
function() { return self.error.apply(self, arguments); }
);
This allows you to pass the context in the closure of the anonymous function and execute the callbacks with an exclusive this context.
It appears that in EMCAScript5+ you can use bind on the function to bind it for use in a callback:
remote_submit(identify, this.success.bind(), this.error.bind())
However from the MDN Documentation:
The bind function is a recent addition to ECMA-262, 5th edition; as such it may not be present in all browsers. You can partially work around this by inserting the following code at the beginning of your scripts, allowing use of much of the functionality of bind() in implementations that do not natively support it.
The shim/polyfill is here:
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
Update:
To answer your additional question, let's first look at the call and apply documentation and break down how they work:
Fundamentally they work the same, the only difference is how they take their arguments:
myfunc.call(target, param1, param2, param3);
Will call myfunc(param1, param2, param3) with target as this.
var args = [param1, param2, param3];
myfunc.apply(target, args);
Will call myfunc(param1, param2, param3) with target as this.
Basically the difference is that .apply() takes an array of arguments, where the call function requires you to write in the arguments in the code.
Next, if we look at the example i gave you:
function() { return self.success.apply(self, arguments); }
This returns a function that will call your callback by passing all the arguments (arguments variable) that were passed into the anonymous function, onto the apply function. So:
var a = function() { return self.success.apply(self, arguments); };
a(1,2,3,4);
This will call self.success(1,2,3,4) with self as this. If you'd like to augment the arguments with something specific for example if you wanted a(1,2,3,4) to call self.success(self.test, 1, 2, 3, 4) then you'll have to provide an augmented array to the apply function:
var a = function() {
var args = [self.test];
for(var i = 0; i < arguments.length; i++) args[] = arguments[i];
return self.success.apply(self, args);
}
When you pass the function as a callback, do it like this:
whatever( object_log.login.bind( object_log ) );
That call to the .bind method will return a function that'll make sure your "login" function will be called such that this references the "object_log" object.
There's a good shim for .bind for older browsers at the MDN documentation site.
I am looking for var self = this alternative plan.
var Animal = function(name){
this.name = name;
this.arr = [1,2,3,4];
this.inc = function(num){
return num + 1;
};
this.fireArr = function(){
var self = this;
this.arr.forEach(function(item){
console.log(self.inc(item));
});
};
};
var dog = new Animal("dog");
console.log(dog.fireArr());
My fiddle is here.
http://jsfiddle.net/haradashinya/TtYpc/
Do you have any idea?
Thanks in advance.
You can set the second argument to forEach, which is the this value.
this.arr.forEach(function(item){
console.log(this.inc(item));
}, this);
You can use .bind() to make sure the function is called with the right this value:
function fireArr() {
this.arr.forEach(function(item){
console.log(this.inc(item));
}.bind(this));
}
But imho the self (that, _this) variable is easier to understand, because it directly states that not the normal this value is used, although one would expect it (e.g. in an event handler, or jQuery's each()). Especially on long functions, where you don't see the bind() in the end, this is of importance. Also, some ancient browsers do not support bind() and you would need to shim it.
So, for any in-place function expressions I recommend the use of a dereferencing variable.
But it can be of great use when you have a method defined somewhere, normally using this to point to the current object as it is common in that context, and then the method should be used somewhere else. Instead of a var self-wrapper, you can and should use bind for simplicity and clarity. Your example offers quite a good demo (assuming the inc method used the this keyword):
this.arr.forEach( this.inc.bind(this) );
(although forEach() allows us to pass a custom this argument - event attachers for example don't)
In your example, the inc function doesn't use the this value, so it doesn't need to be a method. You can define it as a local function:
var Animal = function ( name ) {
this.name = name;
this.arr = [ 1, 2, 3, 4 ];
var inc = function ( num ) {
return num + 1;
};
this.fireArr = function () {
this.arr.forEach(function ( item ) {
console.log( inc( item ) );
});
};
};
Function.prototype.bind = function() {
var $this = arguments[0];
return this.apply($this, Array.prototype.slice.call(arguments, 1));
};
Is it good enough to use in real-world application?
No. There are a few things I don't like about this code, and a few reasons why it won't work.
First, most people don't assign arguments that way. It takes up extra space for no extra effect. Only use the arguments variable if the variable names should change depending on the number of arguments/type of arguments. To assign $this you should do..
Function.prototype.bind = function($this) {
Second, bind should return a function. Your's returns whatever this returns. Your function acts more like a Function:call then a Function:bind.
What you need to do to fix it, is make it return a function that when run will return whatever the function returns.
Try this:
Function.prototype.bind = function($this) {
// `this` changes inside the function, so we have to give it a safe name.
var self = this;
return function () {
return self.apply($this, Array.prototype.slice.call(arguments, 1));
}
};
Also, more modern browsers have the ECMAScript 5 standard of this function built in. The function is written in plain JavaScript, so for older browsers, just include this code suggested by Mozilla:
if ( !Function.prototype.bind ) {
Function.prototype.bind = function( obj ) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () {},
bound = function () {
return self.apply( this instanceof nop ? this : ( obj || {} ), args.concat( slice.call(arguments) ) );
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}