Можно ли создать объект в Javascript, не объявляя каждое значение, и как?

Я хочу сделать следующее:

var Room = function(name, north, south, east, west) {
    this.name = name;
    this.north = north;
    this.south = south;
    this.west = west;
    this.east = east;
}

Где север, юг, восток и запад - это просто флаг, говорящий, есть ли там дверь.

Когда я создаю объект, я должен сделать это:

var bedroom = new Room('Bedroom', true, false, false, false);

Мне было интересно, есть ли способ, чтобы я мог просто сказать, какие направления имеют истинное значение, например:

var bedroom = new Room({
    name: 'Bedroom',
    north: true
});

Когда юг, восток и запад становятся ложными. Таким образом, если бы у меня было 20 различных вариантов, мне нужно было бы указать только те, которые меня интересуют, вместо длинных объявлений с большим количеством false и '', и мне не нужно было бы помнить, в каком порядке они должны были быть (север, юг, восток, запад? или север, восток, юг, запад?),


person Jonathan Owen Chute    schedule 23.02.2015    source источник


Ответы (8)


Если вам действительно нужны отдельные переменные экземпляра для north, south, east и west, я бы предложил что-то вроде этого, где вы можете передать только нужные вам направления в строке с разделителями-пробелами. Это значительно упрощает код вызова, поскольку вам не нужно ничего передавать для несуществующих направлений.

var Room = function(name, directions) {
    this.name = name;
    this.north = this.south = this.west = this.east = false;
    directions = directions.split(" ");
    directions.forEach(function(item) {
        this[item] = true;
    })
}

var bedroom = new Room('Bedroom', 'north south');

Или ваш объектный подход тоже отлично работает:

var Room = function(name, directions) {
    this.name = name;
    this.north = this.south = this.west = this.east = false;
    for (var dir in directions) {
        this[dir] = directions[dir];
    }
}

var bedroom = new Room('Bedroom', {north: true, south: true});

Третий подход заключается в использовании флагов (часто используемых в C/C++). Это позволяет передавать произвольное количество флагов в одном значении:

var Room = function(name, directions) {
    this.name = name;
    this.directions = directions;
}

Room.prototype = {
   isNorth: function() { return this.directions & Room.north},
   isSouth: function() { return this.directions & Room.south},
   isWest: function() { return this.directions & Room.west},
   isEast: function() { return this.directions & Room.east},
};

Room.north = 1;
Room.south = 2;
Room.east = 4;
Room.west = 8;

var bedroom = new Room('Bedroom', Room.north | Room.south);
person jfriend00    schedule 23.02.2015
comment
Что, если и север, и юг должны быть истинными? - person j08691; 23.02.2015
comment
@ j08691 - Я изначально не понимал, что это требование. Я изменил свой ответ, чтобы поддержать это сейчас. - person jfriend00; 23.02.2015
comment
Строка, разделенная пробелами, выглядит немного своеобразно (т. е. теперь так вы поступили бы во многих других ситуациях), но в данном случае это довольно мило. - person Nate; 23.02.2015
comment
Спасибо, попробовав другие, этот показался мне лучшим! - person Jonathan Owen Chute; 23.02.2015
comment
@JonathanOwenChute - я добавил третью версию, в которой используются двоичные флаги. - person jfriend00; 23.02.2015
comment
@ jfriend00 - Спасибо, объектный подход имеет для меня наиболее логичный смысл и работает как шарм, я ценю всю работу! - person Jonathan Owen Chute; 23.02.2015

Объекты JavaScript

Добавьте значение по умолчанию с помощью оператора ||

var Room = function(name, north, south, east, west) {
    this.name = name;
    this.north = north || false;
    this.south = south || false;
    this.west = west || false;
    this.east = east || false;
}

Это скажет ему использовать east, если для него были предоставлены данные, или использовать false, если east окажется undefined.

person Harben    schedule 23.02.2015
comment
Я думал, что весь смысл вопроса в том, чтобы не проходить сразу все направления в конструкторе. Это выглядит как-то глупо. - person jfriend00; 23.02.2015
comment
Просто будьте осторожны при использовании этого способа назначения значений по умолчанию с помощью true и false. Это будет работать в этом направлении, но таким образом вы не сможете присвоить ложные значения истинным значениям по умолчанию. - person Nate; 23.02.2015

Вы можете использовать цикл for .. in ..." для итерации входного объекта с параметрами. Пример:

Room = function(options) {
    for (var key in options) {
        this[key] = options[key];
    }
}

var bedroom = new Room({
    name: 'Bedroom',
    north: true
});
person Alex Kopachov    schedule 23.02.2015
comment
Я думаю, что перейду на этот подход, как только for .. of .. будет поддерживаться везде. Мне нравится, что любое другое значение равно undefined, но использование for .. in .. имеет свои проблемы. - person Hector; 21.04.2015

Вы можете использовать оператор ||

e.g.

var Room = function(name, directions) {
    this.name = name;
    this.north = directions.north || false;
    this.south = directions.south || false;
    this.west = directions.west || false;
    this.east = directions.east || false;
}

затем, когда вы вызываете var r = new Room("something", {north:true});, все остальные значения будут установлены в false.

person Hector    schedule 23.02.2015

Вы можете использовать какой-то подкласс.

В основном классе вы помещаете все значения по умолчанию.

function AbstractRoom(name, north, south, east, west){
    this.name = name;
    this.north = north;
    this.south= south;
    this.east= east;
    this.west= west;
}

В своем подклассе вы помещаете свои ценности

function RoomNorth(name){
  AbstractRoom.call(this, name, true, false, false, false);
}

в таком случае

var myNorthRoom = new RoomNorth('AGoodName');

где

myNorthRoom.north <-- true
myNorthRoom.south <-- false
person Matteo Rubini    schedule 23.02.2015

Как насчет:

var Room = function( name, directions ) {
    this.name = name;
    this.north = directions.north || false;
    this.south = directions.south || false;
    this.west = directions.west || false;
    this.east = directions.east || false;
}

А затем вызов конструктора, например:

var bedroom = new Room( 'Bedroom', { 'north': true } );

Если вы не определяете направление, || оператор сделает его ложным.

person armellini13    schedule 23.02.2015

Вот еще один способ использования шаблона «цепочка» (это не строитель как таковой):

function Room (name) {
   this.name = name;
}

Room.prototype = {
   north: function (v) {
       if (arguments.length > 0 } { this._north = v; return this; }
       else { return this._north; }
   },
   south: function (v) {
       if (arguments.length > 0 } { this._south = v; return this; }
       else { return this._south; }
   },
   // .. rest of getter-setters
   // The prototype can be used for defaults and/or lifting
   _north: false,
   _south: false,
   // .. rest of defaults
}

var room = new Room("bedroom")
  .north(true)
  .south(true); // => the Room object

var hasNorth = room.north(); // => true

Некоторым людям может не понравиться этот шаблон — и особенно эта реализация — потому что он изменяет тип возвращаемого значения геттера/сеттера на «иногда-цепочка» и «иногда-возврат-значения», как некоторые методы jQuery (например, $.val ).

Это также требует / поощряет доступ к направлениям (например, «север») с помощью методов получения. Определение свойств не допускает такого синтаксиса цепочки.

person user2864740    schedule 23.02.2015

person    schedule
comment
Не рекомендуется выполнять итерацию массива в Javascript с помощью for (var direction in cardinals), так как при этом перебираются все свойства массива, а не только элементы массива, и могут быть включены любые перечисляемые методы полифилла или пользовательские методы, добавленные к объекту Array. Вместо этого используйте .forEach() или стиль for (var i = 0; i < cardinals.length; i++). - person jfriend00; 23.02.2015
comment
Согласованный! Не уверен, почему я использовал этот путь изначально; рассеянность? Я обновил свой пример для потомков. - person Nate; 24.02.2015