function curry(fn, scope)
{
var scope = scope || window;
var args = Array.prototype.slice.call(arguments, 2) || [];
return function()
{
fn.apply(scope, args);
};
};
Refactorings
No refactoring yet !
macournoyer
October 18, 2007, October 18, 2007 18:26, permalink
hey richard could you provide an example usage of that function ?
kentaromiura
October 18, 2007, October 18, 2007 23:03, permalink
why these 2 are different?
alert(
curry(
function(){return this},
'a'
)()
);
alert(
function(){function(){return this;}.apply('a')}()
);
richardhealy
October 19, 2007, October 19, 2007 08:45, permalink
Let me show you how I am using it. It might help to show you how I am implementing this. This is my rating widget that I use my Currying function in (lines 43 and 44). You can see the example working here: http://code.richardhealy.co.uk/yui/rating/index.htm
function curry(fn, scope)
{
var scope = scope || window;
var args = Array.prototype.slice.call(arguments, 2) || [];
return function()
{
fn.apply(scope, args);
};
};
var rating = function(id, value)
{
this.construct.apply(this, arguments);
};
rating.prototype =
{
construct: function(id, stars, value)
{
this.__timeout = -1;
this.__listeners = {};
this.__timeouts = {};
this.id = id;
this.imageOff = 'assets/blank.gif';
this.imageOn = 'assets/gSelected.gif';
this.imageOut = 'assets/bSelected.gif';
this.timeout = 500;
this.value = value;
this.stars = stars;
var outsideEl = document.getElementById(id);
for(i=1; i<=this.stars; i++){
var imgID = 'img'+i;
var newimg = document.createElement('img');
newimg.id = imgID;
newimg.src = this.imageOff;
//Appends Image within the external container
outsideEl.appendChild(newimg);
YAHOO.util.Event.addListener(document.getElementById(imgID), "mouseover", curry(this.mouseOver, this, i)); //<--- Currying Used Here
YAHOO.util.Event.addListener(document.getElementById(imgID), "click", curry(this.clickMethod, this, i)); //<--- Currying Used Here
}
this.addMethodListener("mouseOut", this.id, "mouseout");
this.renderStars(this.value, false);
},
addMethodListener: function(method, el, event)
{
var that = this;
this.__listeners["method:" + name + ":" + el.id + ":" + event] = function()
{
that[method].apply(that, arguments);
};
YAHOO.util.Event.addListener(el, event, this.__listeners["method:" + name + ":" + el.id + ":" + event]);
},
mouseOver: function(rating)
{
this.clearTimeout(this.__timeout);
this.__timeout = -1;
this.renderStars(rating, true);
},
clickMethod: function(rating)
{
this.value = rating;
this.onClick(rating);
},
mouseOut: function()
{
if(this.__timeout != -1)
{
this.clearTimeout(this.__timeout);
}
this.__timeout = this.setTimeout('onTimeOut',this.timeout);
},
onTimeOut: function()
{
this.renderStars(this.value, false);
},
renderStars: function(units, startColor)
{
for (var i = 1; i <= units; i++)
{
if(startColor == true)
{
document.getElementById("img" + i).src = this.imageOn;
}
else
{
document.getElementById("img" + i).src = this.imageOut;
}
}
for (i = units + 1; i <= this.stars; i++)
{
document.getElementById("img" + i).src = this.imageOff;
}
},
setTimeout: function(method, period)
{
this.clearTimeout(method);
var that = this;
var args = Array.prototype.slice.call(arguments, 2) || [];
this.__timeouts[method] = setTimeout(function()
{
that[method].apply(that, args);
}, period);
},
clearTimeout: function(method)
{
if (this.__timeouts[method] > 0)
{
clearTimeout(this.__timeouts[method]);
this.__timeouts[method] = 0;
}
},
onClick: function(value)
{
this.value = value;
}
}
<div id="rater" class="bk-form-rating rater">
<div class="bk-form-inner"></div>
</div>
<div id="actions"><button id="getVal" onclick="alert(r.value);">Alert Value</button></div>
<script>
var r = new rating('rater', 5, 0);
</script>
macournoyer
October 19, 2007, October 19, 2007 15:16, permalink
why renderStars onMouseOver rather the onClick ? The delay feels like something is wrong.
But I think I understand w/ currying is good for in js. Thx Richard!
I don't know YUI lib but w/ Prototype I would write:
YAHOO.util.Event.addListener(document.getElementById(imgID), "mouseover", curry(this.mouseOver, this, i));
# W/ Prototype
$(imgID).observe("mouseover", curry(this.mouseOver, this, i));
# W/out currying
$(imgID).observe("mouseover", function() { this.mouseOver(i) }.bind(this));
Gary Haran
October 30, 2007, October 30, 2007 15:41, permalink
I would use bindAsEventListener here so that you can use the event.
# W/ Prototype and W/out currying
$(imgID).observe("mouseover",
function(event) {
this.mouseOver(i)
}.bindAsEventListener(this));
macournoyer
October 30, 2007, October 30, 2007 15:48, permalink
Prototype 1.6 is gonna support currying : http://www.prototypejs.org/2007/8/15/prototype-1-6-0-release-candidate
Here's the example the've put in the RC announcement
function sum(a, b) {
return a + b;
}
sum(10, 5) // 15
var addTen = sum.curry(10);
addTen(5) // 15
I use this little function everywhere in my javascript to deal with scope issues. Can anyone make it better?