I'm a JavaScript slightly-more-than-beginner.
While reading the source for EventEmitter, I stumbled upon this interesting and, to me, elegant function:
// alias a method while keeping the correct context
function alias(name) {
return function aliasClosure() {
return this[name].apply(this, arguments);
};
}
I have two main questions:
First: why is the aliasClosure a named function? Is it useful in some way other than clarity? Also, is is really a closure? To me, it looks just like a semi-anonymous function.
Second: I rewrote this function like this:
function alias2(name) {
return this[name].bind(this);
}
Is it equivalent? I think it should, since the this context is the same and it's preserved in both versions.
Is there a reason to prefer one over the other?
No, these are not at all equivalent. From looking at the alias() function I think you would use it something like this:
> Array.prototype.strjoin = alias('join'); // make 'strjoin' an alias of 'join'
> [1, 2, 3].strjoin(" + ");
"1 + 2 + 3"
Using alias2() in the above code will not work.
Providing a name in a function instantiation expression makes a name available for stack traces. (I'm told newer debuggers don't always need it if the function is created in certain contexts, like a var initialization.)
I think the second is equivalent, mostly, though .bind() has some obscure special cases it handles.
edit wait - no, they're not equivalent. The first one involves this explicitly, and performs the lookup on each call. The first function doesn't need this to be bound to anything when it's called, while yours will throw an exception in that case.
One change that would make the two functions almost equal is wrapping bind inside a closure, like this:
function alias2(name) {
return function() {
return this[name].bind(this);
}
}
Still, bind behaves obscurely in rare cases.
Related
I would like to know the difference between 2 implementations of callback functions.
This:
$("#button").on('click', function () {
//do something
});
Versus having the function already defined.
$("#button").on('click', btnFunction);
function btnFunction() {
//do something
}
Are there any implications with one compared to another? Performance-wise is one faster?
The first uses an anonymous function and the second does not. There's no difference in both.
See:
Why do you need to invoke an anonymous function on the same line?
Some folks prefer the second form because it gives a function name when using the debugger and tracing, but there are ways to get the same functionality in the first form.
If you are attaching and removing the event handler based on changing conditions, the second form is much easier to maintain, however.
There's no difference at all, and there's no performance issue with neither one of them. The only difference is that in one of them you're defining the callback function as an anonymous function, this way you cannot reuse it.
The other way, where you define it else where and named it and then pass it as a callback, you're defining a function that you can later reuse in another part of your code.
For example: if you want to do something when the document is ready, and then do se exact same thing when some one press a button you can use something like this:
function getData() {
//do something
}
$(function() {
// Call the function once the DOM is ready
getData();
});
// Call the same function when the button is clicked
$("#refresh_button").on('click', getData);
In most cases the first one will be used, called Anonymous Functions
The second one will be used when the function is not only used inlined here, but also needs to be reused somewhere else.
But anyway it could be a personal preference.
The only real difference you could see is that stack trace (if an exception is thrown for example) will be better, i.e. easier to debug, when using the second one.
Just reuse-ability.
In the second case, you could call btnFunction() somewhere else if need be.
Intellij IDEA shows a warning when ever I write Javascript like this:
someFunction(someOtherFunction());
But the explanation is not really helpful:
"This inspection reports any Javascript function calls used as
arguments to another function call."
This is something I do frequently, so what's the potential trap hiding there worth warning of? Or if it's just some coding convention, what's the reason for it?
It is a warning because most of the time, you want to pass a function reference as an argument. It is mostly used as a callback:
someFunction(someOtherFunction);
function someFunction(fn){
fn.call();
}
In that example, someOtherFunction() instead of someOtherFunction would not work as expect (unless someOtherFunction returns a function itself).
someFunction(someOtherFunction()); work more like a getter.
someFunction(someOtherFunction());
function someFunction(int){
alert(int === 1);//True;
}
function someOtherFunction(){
return 1;
}
It gives a warning because it is a common mistake for new developers.
Apologies - I have no idea to how to describe this. Example:
function OutputNumber(number) {
this.outputThisInstead = function (otherNumber) {
console.log(otherNumber);
}
console.log(number);
}
Desired usage:
new OutputNumber(1);
Console output: 1
new OutputNumber(1).outputThisInstead(2);
Console output: 2
Naturally, 1 will always be written to the console, irrespective of what else is called on the object.
I'm after this particular syntax, as well as the behaviour - attaching a function onto the initialisation. It feels impossible since the object must be constructed before any function is called on it, but is this achievable any other way?
It would be possible with a time delay (e.g., in a browser environment, setTimeout or similar) and a flag. Not desirable, but possible.
Without that, no, you can't base the action of the constructor on something that hasn't happened yet. You'd have to instead pass something into the constructor to let it know what was going on.
Browser example (again, I don't recommend this):
function OutputNumber(number) {
var handle = 0;
this.outputThisInstead = function (otherNumber) {
if (handle) {
clearTimeout(handle);
handle = 0;
}
console.log(otherNumber);
}
handle = setTimeout(function() {
console.log(number);
}, 0);
}
From your comment on the question:
This is the end of a sequence of chaining objects/functions, that I'm experimenting with. For example:
Assert.that(1).is.not(2).because('output this message if fails');
Here not(2) returns an object on which because can optionally be called. The behaviour of the object would depend on because being called.
Rather than have the behavior of an earlier function in the chain depend on a later function in the chain, I'd probably add an .end() at the end of something:
Assert.that(1).is.not(2).because('output this message if fails').end();
end would output whatever message/messages was/were stored by the previous functions. No need for black magic. Obviously this suffers from the fact that people could fail to put the .end() on, but you need some kind of trigger that it's okay to do the output, if you want the output to change based on an optional subsequent function call.
Not possible. By the time you do new OutputNumber(1) the function has already been called. A chained method will have no access to its preceding call.
It's possible to declare outputThisInstead as "static":
function OutputNumber(number) {
console.log(number);
}
OutputNumber.outputThisInstead = function (otherNumber) {
console.log(otherNumber);
}
new OutputNumber(1); //1
OutputNumber.outputThisInstead(2); //2
But if you want to create an object with the new operator the function will always log the number parameter.
You can also achieve similar behavior to the one you want with partial apply of the function (here). This is also called Currying or Schönfinkeling. The idea is that you can fill the function's parameters one after another and when the full set of parameters is available the function is being executed. You can see a currying example here.
I'm using mootools:
I can't figure out how to use a variable when using an addEvent.
I want to use a for next loop to set values in a loop:
for (x=0;x<num;x++){
var onclickText = 'function (){onclick="addPageMoveEvent('+x+'"); }';
$('pageNum'+x).addEvent('click', onclickText);
}
>
I've search forums but not found any help.
Any help would be great.
Thanks
The addEvent method in MooTools accepts two arguments:
myElement.addEvent(type, fn);
Arguments:
type - (string) The event name to monitor ('click', 'load', etc) without the prefix 'on'.
fn - (function) The function to execute.
It does not take a string and passing a string such as "myFunction()" or "function() { myFunction(); }" will not work.
Since you are inside a loop, and the variable x will share the environment, you need to wrap its value inside another closure. One way is to use an additional closure:
$("pagenum" + x).addEvent("click", (function(value) {
return function() { addPageMoveEvent(value); }
})(x));
See all questions on StackOverflow regarding this particular problem of creating closures within loops.
Also worth checking out is this MDC article - Creating closures in loops: A common mistake
Warning: this first example will not work! Read on for an explanation.
You are confusing onclick HTML syntax with the MooTools addEvent. Try
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', 'addPageMoveEvent('+x+');');
}
This is simpler and cleaner, but might still not do what you want. This code will call the function addPageMoveEvent every time the link is clicked... is that what you want?
Since MooTools doesn't allow the above method, you must use the following:
A programmatically more interesting and less hazardous way to do the same would be:
factory = function (x) { return function() { addPageMoveEvent(x); }; };
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', factory(x));
}
This uses a factory for creating closures that hold your values of x... rather complex code, but it's the purist way. It also avoids using the scary eval that occurs because you feed addEvent a string. (It seems that MooTools doesn't like the other option anyway.)
That a use case for mootools pass method.
for (x=0;x<num;x++){
$('pageNum'+x).addEvent('click', addPageMoveEvent.pass(x));
}
Pass internally creates a closure that holds x in the his scope, so when the click event is fired it has the right value cause its not the same from the for loop.
A friend of mine and I were having a discussion regarding currying and partial function application in Javascript, and we came to very different conclusions as to whether either were achievable. I came up with this implementation of Function.prototype.curry, which was the basis of our discussion:
Function.prototype.curry = function() {
if (!arguments.length) return this;
var args = Array.prototype.slice.apply(arguments);
var mmm_curry = this, args;
return function() {
var inner_args = Array.prototype.slice.apply(arguments);
return mmm_curry.apply(this, args.concat(inner_args));
}
}
Which is used as follows:
var vindaloo = function(a, b) {
return (a + b);
}
var karahi = vindaloo.curry(1);
var masala = karahi(2);
var gulai = karahi(3);
print(masala);
print(other);
The output of which is as follows in Spidermonkey:
$ js curry.js
3
4
His opinion was that since the Javascript function primitive does not natively support "partial function application", it's completely wrong to refer to the function bound to the variable karahi as partially applied. His argument was that when the vindaloo function is curried, the function itself is completely applied and a closure is returned, not a "partially applied function".
Now, my opinion is that while Javascript itself does not provide support for partial application in its' function primitives (unlike say, ML or Haskell), that doesn't mean you can't create a higher order function of the language which is capable of encapsulating concept of a partially applied function. Also, despite being "applied", the scope of the function is still bound to the closure returned by it causing it to remain "partially applied".
Which is correct?
Technically you're creating a brand new function that calls the original function. So if my understanding of partially applied functions is correct, this is not a partially applied function. A partially applied function would be closer to this (note that this isn't a general solution):
vindaloo.curry = function(a) {
return function(b) {
return a + b;
};
};
IIUC, this still wouldn't be a partially applied function. But it's closer. A true partially applied function would actually look like this if you can examine the code:
function karahi(b) {
return 1 + b;
};
So, technically, your original method is just returning a function bound within a closure. The only way I can think of to truly partially apply a function in JavaScript would be to parse the function, apply the changes, and then run it through an eval().
However, your solution is a good practical application of the concept to JavaScript, so practically speaking accomplishes the goal, even if it is not technically exact.
I think it's perfectly OK to talk about partial function application
in JavaScript - if it works like partial application, then it must
be one. How else would you name it?
How your curry function accomplishes his goal is just an implementation
detail. In a similar way we could have partial application in the ECMAScript spec,
but when IE would then implement it just as you did, you would have
no way to find out.
The technical details don't matter to me - if the semantics remain the same and, for all intents and purposes, the function acts as if it were really a partially-applied function, who cares?
I used to be as academic about things, but worrying about such particulars doesn't get real work done in the end.
Personally, I use MochiKit; it has a nice partial() function which assists in the creation of such. I loves it.
You should check out Curried JavaScript Functions. I haven't completely wrapped my head around his curry function, but it might have your answer.
Edit: I would agree with your assessment, however.
His opinion was that since the Javascript function primitive does not natively support "partial function application"
You can do currying in ES6 pretty elegantly:
> const add = a => b => a + b
> const add10 = add(10)
> [1,2,3].map(add10)
[ 11, 12, 13 ]