0

JS newbie here, I've been looking through some code recently which uses syntax I'm not too familiar with. Here's an example, followed by my questions:

function Group(args) {
  this.showItem = showItem;
  function showItem(args) {
    ...
  }
}
var group = new Group (args);

Questions:

  1. As I understand it creating function Group and then instantiating via group = new Group is essentially prototypal equivalent of defining a class and then instantiating an object of that class. Is that correct?

  2. Regarding the properties (methods?) of Group, what is the above syntax for showItem called? Why not just define it like:

    this.showItem = function(args){...};
    

    Would changing the code to the above change any different behavior?

  3. If you did define it as above, what is that syntax called?

Andrew
  • 42,517
  • 51
  • 181
  • 281

2 Answers2

3
  1. The Group function is being used as a constructor; your intuition is basically correct.

  2. There is no good reason not to use an anonymous function expression like this.showItem = function(args){...};, unless you wanted to reuse the local variable showItem.

  3. I'm not sure which syntax you mean. The function(args){...} is an anonymous function expression, and the this.showItem is referring to a member of the object this. Taken all together, I suppose you could call it "setting a member function of an object".

Bonus tip (which maybe you already knew?): the reason you can use showItem before its definition is due to function hoisting.

EDIT:

You seem to be asking about function expressions versus function declarations as well as named versus anonymous functions. The primary differences are:

  • Function declarations always stand on their own. They are never part of another operation, e.g. assignment. Your first example uses the function declaration function showItem(args) {...}. Function expressions are used as an expression in some operation (e.g., assignment, passed as an argument, etc.). Your second case uses a function expression.

  • Function declarations are hoisted to the top of the current function scope, so showItem in your first case is defined and contains the function when you use it in your assignment operation. Function expressions are not hoisted.

  • Function declarations are always named. Function expressions may be named or anonymous. When a function is defined with a name, that name is accessible as the name property of the function object. A function's name is immutable and independent of any variables that hold a reference to the function. Also, code inside the function body can refer to the function by its name as a local variable (which is sometimes useful for recursion inside named function expressions).

To review:

  • Function definition: function showItems(args){...};
  • Anonymous function expression: this.showItems = function(args){...};
  • Named function expression: this.showItems = function showItemsName(args){...};

In the first case, there is a local variable called showItems defined and the definition of showItems is hoisted to the top. The difference between the latter two cases is that this.showItems.name will be "showItemsName" for the third case and undefined for the second. Also, showItemsName will be a local variable within the function body of the third function that holds a reference to the function object.

Community
  • 1
  • 1
apsillers
  • 112,806
  • 17
  • 235
  • 239
  • I guess what I mean is, is there a difference between setting the property to a named function and then declaring the function, vs. just setting the property to an anonymous function. You're saying there's no difference between the behavior, right? I'm asking if either style has a name. – Andrew Dec 31 '12 at 17:44
  • @Andrew I'll update my answer; in the meantime, you might look here: http://stackoverflow.com/questions/1013385/what-is-the-difference-between-a-function-expression-vs-declaration-in-javascrip – apsillers Dec 31 '12 at 17:45
2
  1. The Group function is used as a constructor. However, the way this is done is a bit inefficient. What this code is doing is creating a new function and attaching it to the constructed object. He may be doing this because he wants to create a closure (i.e. use a variable only present in the namespace of the constructor), but absent that reason it's better to do this:

    function Group(args){}
    Group.prototype.showItem = function(args) {};
    

    This way the same showItem function is shared among all objects constructed by Group via the prototype chain.

  2. The benefit of using the original code vs an anonymous function is that the function has a name--this is a great help in debugging because reading a traceback full of anonymous function calls is no fun! To expand, there are three types of things that use the function keyword:

    • Function declarations When at the top level of a program or a function (i.e., of something that creates/has its own namespace), you may declare a function with a name. (The name stays with the function object throughout the program and will appear in tracebacks.) This is function showItem(args) {} in your example. (Note that this is only a function declaration at the top level of a file or function. There's a very similar thing I'll get to last.) By convention most people seem to omit semicolons after these.
    • Function expressions When part of an expression (such as assignment, return, etc), it is a function expression. The identifier part of the function expression is optional, so these are both function expressions:

      var myfunc1 = function(){};
      var myfunc2 = function MyFunctionName(){};
      

      The second form is called a "named function expression". The great benefit of using this form is that MyFunctionName is no longer an anonymous function--this name will be attached to the function and will show up in tracebacks (for example). However there is a very serious bug in JScript (IE <= 8) that makes using these problematic. Read the article I linked above for details.

    • Finally, there is a common extension syntax called function statements. These look exactly like function declarations, except they are not top level! For example:

      function() {
          function foo(){} // function declaration
          if (1) {
              function bar(){} // function STATEMENT--not standard JS!
          }
      }
      

      You should not rely on this extension, but should do this instead:

      function() {
          var bar;
          if (1) {
              bar = function bar(){};
          }
      }
      
  3. this.showItem = function(){} would be called a "function expression in an assignment", and the original code is just using a "function declaration".

Francis Avila
  • 31,233
  • 6
  • 58
  • 96
  • "He may be doing this because he wants to create a closure (i.e. use a variable only present in the namespace of the constructor)" In this case I think the instance is using a variable that is set in the namespace of the constructor, however the variable is not *only* set in the namespace of the constructor, it could be retrieved from anywhere. So in this case would it be better to use the `prototype` definition you showed above? – Andrew Dec 31 '12 at 18:16
  • From what code you show, assigning to `prototype` outside the constructor would be better, but I can't be sure. (It occurs to me that maybe one of the many methods of pseudo-inheritance is involved as well.) The modern `Object.create` pattern would simply be `Group.prototype = {name:function(){},...};` or `Group.prototype = Object.create(Superclass.prototype);` [More info on this.](http://dailyjs.com/2012/06/04/js101-object-create/) – Francis Avila Dec 31 '12 at 18:41