2

Why am I getting a size of 1 returned by my_game.size()? I thought the arguments from make_game would get inserted into game and so arguments.length would be 3, but apparently it's not. What is the reason for this?

function game()
{
    var args = arguments;
    this.size = function() { return args.length; };
}

function make_game()
{
    return new game(arguments);
}

var my_game = make_game(4, 'a', true);

console.log(my_game.size()); // 1
David G
  • 90,891
  • 40
  • 158
  • 247

5 Answers5

6

You are passing the entire arguments object as a single argument

If you want to pass each argument within it as a separate argument then you must do so explicitly:

return new game(arguments[0], arguments[1], arguments[2]);

If you weren't using a constructor function, then you could use the apply method.

return game.apply(this, arguments); 

… but since you are you would get this result:

Uncaught TypeError: function apply() { [native code] } is not a constructor 

… as it tries to use apply as the constructor instead of game.

Quentin
  • 857,932
  • 118
  • 1,152
  • 1,264
4

When you do game(arguments) inside of make_game() you are calling game() with a single argument, which is the array of arguments that were passed to make_game().

If you want to pass each argument separately you would normally use game.apply(arguments), but to get this to work properly with new as well it gets a little more complicated:

function make_game()
{
    return new (Function.prototype.bind.apply(game, arguments));
}

This answer has a detailed explanation of how this method works.

Community
  • 1
  • 1
Andrew Clark
  • 192,132
  • 30
  • 260
  • 294
  • Whoa, that's pretty interesting right there, and far simpler than my solution. It works because `bind` returns a function all setup for just the right call. Very slick. – Alex Wayne May 29 '13 at 19:42
3
return new game(arguments);

You are passing in the arguments object, just one object. So that's one argument.

To forward arguments to a normal function, you would use apply:

var fn = function() {
  otherFn.apply(null, arguments);
};

But this does 2 things, it passes in the arguments array to use as arguments, but it also sets the execution context (value of this). But a constructor function creates it's own value of this. This presents a problem...


Forwarding the arguments to a constructor is much trickier in plain JS. In Coffee script, it's easy, but it compiles into some crazy JS. See here

The trick seems to be to make an a new subclass with a no-op constructor, and invoke the constructor manually.

var newConstructor = function() {}; // no-op constructor
newConstructor.prototype = Game.prototype; // inherit from Game
var child = new newConstructor(); // instantiate no-op constructor
var result = Game.apply(child, arguments); // invoke real constructor.

But that's pretty hairy. Perhaps you should rethink your approach.

Alex Wayne
  • 162,909
  • 46
  • 287
  • 312
1

You pass only one argument to your constructor, and it's arguments.

Change

var args = arguments;

to

var args = arguments[0];
Denys Séguret
  • 355,860
  • 83
  • 755
  • 726
0

Just because you are passing only one argument.

function game()
{
    var args = arguments;
    this.size = function() { return args.length; };
}

function make_game()
{
    return new game(arguments); // passing only one
}

function make_game2()
{
    return new game(arguments[0], arguments[1], arguments[2]); // passing three 
}

var my_game = make_game(4, 'a', true);

console.log(my_game.size()); // 1


var my_game2 = make_game2(4, 'a', true);

console.log(my_game2.size()); // 3

you can use another function to initialize the object

function game()
{
    var args;
    this.size = function() { return args.length; };
    this.init = function(){
        args = arguments;
    }
}

function make_game()
{
    var gm =  new game(); 
    gm.init.apply(gm, arguments);
    return gm;
}


var my_game = make_game(4, 'a', true);

console.log(my_game.size()); // 3

This is to demonstrate how it works. It is highly recommended to follow prototype based design.

Diode
  • 23,400
  • 8
  • 39
  • 50