

JavaScript: Function Invocation Patterns - bazsouthafrica
http://doctrina.org/Javascript-Function-Invocation-Patterns.html

======
franze
please see the HN guidelines <http://ycombinator.com/newsguidelines.html>

    
    
      Please don't do things to make titles stand out, like using 
      uppercase or exclamation points, or adding a parenthetical 
      remark saying how great an article is. It's implicit in 
      submitting something that you think it's important.
    

plus i have a very strong distain about anyone or anything (i.e. headlines)
which tell me what i MUST do / know / think... - also the article above is
about a very basic language feature of JS that hopefully anyone who has every
touched JS already knows about.

~~~
raganwald
Amusingly, the original title has a spelling mistake: "Javascript: Function
Inovcation Patterns."

But enough burying the lede. The issue I have with this title is simple: It's
not clear WHY I must know these patterns: The focus of the post is not why I
must know them, but rather _This post explains the four patterns, how to use
them and what to watch out for._ Had the post kicked off by explaining that
not knowing one or more of these patterns could lead to disaster, I'd be
onside with the submission title rewrite (sans emphasis).

~~~
tantalor
It still does: the language is "JavaScript", not "Javascript".

~~~
vog
While we are at nitpicking: I think this is really about ECMAScript.

------
dnc
One portion of Douglas Crockford's book "JavaScript: The Good Parts" describes
invocation patterns thoroughly.

It might be that the author of the post was inspired by this book. Since he
hasn't mentioned it, I did it in case someone wants to know more about the
topic (and doesn't know about the book).

~~~
jszen
He does actually refer to Crockfords book roughly half way through.

~~~
dnc
Nope, he doesn't. :)

~~~
davesims
He does, but it's indirect. In the article he says: "There is a remedy which
was championed by Douglas Crockford: Augment Object with a create method that
accomplishes what the constructor invocation pattern tries to do."

That sentence contains a link to another page on OP's site which at the top
says "Douglas Crockford's wonderful book JavaScript: The Good Parts does a
fanastic job of explaining this topic, and I urge the interested reader to buy
his book."

~~~
dnc
Thanks for pointing it out. I didn't see it. Your comment motivated me to look
at the whole post about JavaScript prototypes again and read it. It is very
good, I refreshed my knowledge about Object.prototype, Function.prototype
design.

------
jlongster
He's wrong in the "Constructor Invocation" example.

function Foo(type) { this.type = type; return type; }

var bar = new Foo(5);

`bar` DOES equal 5. When you return something in a constructor, it returns it
instead of returning the newly constructed object. This is a neat way for
constructing different types of things.

And most of his complaints are just because he doesn't understand how `this`
scoping works in javascript. If you don't understand something, don't just
blame it on "bad patterns". It might not be the most intuitive, but once you
learn it, it's fine. Sure, I have to bind `this` to a different function here
and there, but these problems are not that bad in real world javascript.

~~~
lhorie
> `bar` DOES equal 5

No, it doesn't. Javascript is a bit weird when it comes to return statements
inside constructors. `bar` will be equal to `type` only if `(type instanceof
Object) == true`. Otherwise, it will be a new object.

    
    
        function Foo(type) { this.type = type; return type; }
        console.log(new Foo(/a/));   // Regexp /a/
        console.log(new Foo("a"));   // {type: "a"}
        console.log(new Foo(5));     // {type: 5}
        console.log(new Foo([1,2])); // [1,2]
        console.log(new Foo({a:1})); // {a: 1}

~~~
ynniv
a good time to point out that calling Object() without "new" returns a new
object. This is often unexpected when creating inheritance schemes that chain
the parent constructor.

<https://github.com/documentcloud/backbone/pull/1269>

~~~
lhorie
Not sure I understand your comment, given the link you gave.

IMHO the return value of calling `Object()` without parameters is exactly what
one would expect. Calling it _w/ parameters_ is what I think causes surprising
behavior

    
    
        var x = {a: 2}
        console.log(x === x)             // true
        console.log(Object(x) === x)     // true
        console.log(new Object(x) === x) // true
    

For the `Object.call(x)` case, I'd expect it to return a new object (and not
x), for the same reason I'd expect [].slice.call(arguments) to return a new
array (and not arguments).

~~~
ynniv
[].slice.call(arguments) returning a new argument is fundamentally different
because you would not want x.slice(1,2) to modify x in order to produce an
appropriate sublist to return. Perhaps it's just me, but I expect a
constructor to initialize "this" (optionally returning "this"), but not
returning {};

~~~
lhorie
Disagree. To illustrate:

    
    
        window.test = 2
        var b = Object.call(window) //this is the same as `var b = window.Object()` and therefore the same as `var b = Object()`
        assert(b.test == 2) //why should this be true?

------
bazsouthafrica
Hi Guys

I just want to give you some feedbacks in the comments (I am the author of
this article).

Firstly, with regards to the title, I did not read the newsguidlines document
- I have submitted links in the way and style that other people did. For sure,
in the future, I will follow these guidlines, but this must be a huge problem
as lots of people do this.

Secondly, these are patterns (not language features). Yes, I was inspired by
Douglas Crockford's book where he describes this as patterns. To me describing
them as patterns makes sense: For instance, there is really nothing different
about calling a method and a function. If you have to make a difference, then
it is a pattern. And because putting new in front of a function also calls
that function, it is in my mind a pattern. And in that sense, so is apply.

But I welcome the debate, and thanks for the constructive comments. I will
take all these comments into consideration the next time I submit something.

~~~
robocat
Nice article.

I think you are missing a fifth way to call a function, a property accessor
function (although I have never used one, so not certain!).

Some mention of how somefunc.bind(someobj) affects the "patterns" might also
be worthwhile (although maybe confusing!).

------
FuzzyDunlop
_There is an easy way to get round this problem, but it is in my opinion a
hack. One gets around this problem by assigning a varialbe (by convention, it
is named that) to this inside the function_

Or use `bind` instead.

~~~
emehrkay
or use call or apply when invoking innerFunction, which he describes later in
the article

------
user24
Should have mentioned call along with apply.

Not sure these are patterns rather than just language features.

~~~
cjfont
I agree, this is similar to saying that i+=1 and i++ are increment patterns.

~~~
andrewflnr
Well, yes, except complicated enough to merit more explanation.

------
hafabnew
There's an error in his first 'Function Invocation' example, the answer is
500, not 501.

[Reason: 'this.value++;' in the method invocation refers to obj.value, since
'this' is bound to 'obj'. Only in the innerFunction function invocation does
'this' bind to the global object.]

------
willvarfar
The big bug as I see it is:

    
    
       obj = {
         get_name = function() { return "I am an object" },
         func = function() { alert(this.get_name()); }
       }
    

This looks dandy, and obj.func() works as expected.

but if you pass obj.func as a callback, the this when its invoked will be some
other object (by default, the window object):

    
    
       button.onclick = obj.func; // bang when invoked
    

The number of times I got screwed by that. You end up having to have little
anonymous functions for all callbacks:

    
    
        button.onclick = function(evt) { obj.func(); }
    

(apologies for bugs; just typing javascript from memory)

(would love to be wrong)

~~~
locci
bind was introduced in ES5 (and previously in most libraries) to fix this

[https://developer.mozilla.org/en-
US/docs/JavaScript/Referenc...](https://developer.mozilla.org/en-
US/docs/JavaScript/Reference/Global_Objects/Function/bind)

~~~
huskyr
And trivially easy to shim for older browsers. I would really recommend using
Function.prototype.bind instead of the 'var self = this' or library bind
functions (such as $.proxy), it's just the way it should be written :)

~~~
jessaustin
To confirm my understanding, would the erroneous line from the comment above
be rewritten like:

    
    
        button.onclick = obj.func.bind(obj);
    

So un-DRY! It's almost admirable, how blatant a hack this is.

------
dsego
Katz has an interesting article on this as well:
[http://yehudakatz.com/2011/08/11/understanding-javascript-
fu...](http://yehudakatz.com/2011/08/11/understanding-javascript-function-
invocation-and-this/)

------
TazeTSchnitzel
No mention of strict mode? Come on!

'use strict' makes the this variable undefined in functions invocation.

------
recursive
I have yet to find a use for constructors in a real world problem. I've been
able to do anything I ever wanted to with object literals. I'm not sure why
there is so much emphasis placed on object prototypes.

------
fatboy
Not using Javascript frequently enough to justify reading a book on it, I
found the article useful. These features have been counterintuitive for me.

------
rgbrgb
> Invoking a function suspends execution of the current function, passing
> controls and parameters to the invoked function.

False. JS functions execute asynchronously, without suspending the execution
of the current function.

~~~
rgbrgb
Did I miss something here? Why was this downvoted?

~~~
bazsouthafrica
Hi

I did not downvote your comment, but it is fundamentally incorrect. If your
JavaScript program has been designed well, then asynchronisity by using an
event driven model is the way to go. But that is very different to what I said
about functions stopping the execution of the current function. This is true.
For example

var func1 = function() { //Execute something here }

var func2 = function() { //Execute something here func1(); //Stop execution of
this function, and rather execute func2 //Execute something here }

I hope the above explains this a bit better.

------
taybin
Also makes for a good interview question.

