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
  • 94,763
  • 41
  • 167
  • 253

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
  • 914,110
  • 126
  • 1,211
  • 1,335
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
  • 202,379
  • 35
  • 273
  • 306
  • 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
  • 178,991
  • 47
  • 309
  • 337
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
  • 372,613
  • 87
  • 782
  • 758
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
  • 24,570
  • 8
  • 40
  • 51