2013-05-29 2 views
2

Почему я могу получить 1 размер, указанный my_game.size()? Я думал, что аргументы от make_game будут вставлены в game, и поэтому arguments.length будет 3, но, видимо, это не так. Что является причиной этого?Почему массив аргументов имеет размер 1?

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 

ответ

6

Вы проходите весь arguments объект как один аргумент

Если вы хотите передать каждый аргумент в нем в качестве отдельного аргумента то вы должны сделать это явно:

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

Если вы не используете функцию конструктора, то вы могли бы использовать apply method.

return game.apply(this, arguments); 

... но так как вы, вы получите этот результат:

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

... как он пытается использовать apply как конструктор вместо game.

1

Вы передаете только один аргумент в конструкторе, и это arguments.

Изменить

var args = arguments; 

в

var args = arguments[0]; 
3
return new game(arguments); 

Вы передаете объект arguments, всего один объект. Это один из аргументов.

Направить аргументы к нормальной функции, вы используете будет применяться:

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

Но это делает 2 вещи, она проходит в массиве аргументов, чтобы использовать в качестве аргументов, но он также устанавливает контекст выполнения (значение от this). Но функция-конструктор создает ее собственную ценность. Это представляет проблему ...


Пересылка аргументов конструктору намного сложнее в простой JS. В сценарии кофе это легко, но он компилируется в сумасшедший JS. See here

Трюк состоит в том, чтобы создать новый подкласс с конструктором no-op и вызвать конструктор вручную.

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. 

Но это довольно волосатые. Возможно, вам следует пересмотреть свой подход.

4

Когда вы game(arguments) внутри make_game() вы вызываете game() с одним аргументом, который является массивом аргументов, которые были переданы в make_game().

Если вы хотите передать каждый аргумент отдельно вы обычно используете game.apply(arguments), но чтобы получить это, чтобы правильно работать с new, а это становится немного сложнее:

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

This answer имеет подробное объяснение того, как этот метод работает.

+0

Ого, это довольно интересно прямо там и намного проще, чем мое решение. Он работает, потому что 'bind' возвращает функцию для всех настроек только для правильного вызова. Очень гладкий. –

0

Просто потому, что вы передаете только один аргумент.

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 

вы можете использовать другую функцию для инициализации объекта

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 

Это, чтобы продемонстрировать, как это работает. Настоятельно рекомендуется следовать за прототипом.

Смежные вопросы