Почему я могу добавлять именованные свойства в массив, как если бы это был объект?

105

Следующие два разных фрагмента кода мне кажутся эквивалентными:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

и

var myObject = {'A': 'Athens', 'B':'Berlin'};

потому что они оба ведут себя одинаково, а также typeof(myArray) == typeof(myObjects)(оба дают «объект»).

Есть ли разница между этими вариантами?

Prinzdezibel
источник

Ответы:

131

Практически все в javascript является объектом, поэтому вы можете «злоупотреблять» объектом Array , задав для него произвольные свойства. Однако это следует считать вредным . Массивы предназначены для данных с числовым индексом - для нечисловых ключей используйте объект.

Вот более конкретный пример того, почему нечисловые ключи не подходят для массива:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

alert(myArray.length);

При этом будет отображаться не «2», а «0» - по сути, в массив не было добавлено никаких элементов, только некоторые новые свойства добавлены к объекту массива.

Пол Диксон
источник
4
myArray.length возвращает числовой индекс / ключ последнего элемента в массиве, но не фактическое количество элементов. Свойства объекта Array не совпадают со значениями массива?
Даша Сало
1
Я просто пытался проиллюстрировать предполагаемую семантику объекта Array, которым злоупотребляют, если вы просто относитесь к нему как к обычному объекту. Связанная статья работает лучше :)
Пол Диксон
13
В следующий раз, когда кто-нибудь скажет, что JavaScript - хороший язык для разработки, я покажу ему этот образец. Спасибо.
Оливье Понс
@Olivier, то, что вы называете «ошибкой», также может быть отличной «особенностью». Вы можете добавить капелька и описание массивов , не затрагивая их содержимое или длину и без завернуть их в объектах с title, descriptionи itemsсвойствами. Все зависит от того, насколько хорошо вы знаете язык и как вы им пользуетесь.
Тао
Использование настраиваемых свойств в массивах не является неправильным по своей сути. Неправильно ожидать, что они будут действовать как члены массива, когда вы это сделаете. Они являются свойствами массива, а не членами, поэтому на них не влияют методы массива. Об этом на самом деле говорит автор упомянутой выше статьи в комментариях. Сейчас, честно говоря, я бы не советовал использовать это как практику, так как это, вероятно, запутает людей, использующих ваш код. Или, если они только начинают, своим примером это наставит их на опасный путь. Но я бы не сказал, что JavaScript - это плохо, потому что он позволяет делать вещи, на которые многие не рассчитывают.
Тао
14

В JS массивы - это объекты, только слегка измененные (с еще несколькими функциями).

Такие функции, как:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
Кейси
источник
Хотя я не думаю, что все перечисленные функции встроены в каждую реализацию JS, вы поняли. Другое отличие будет заключаться в другом прототипе (что подразумевается этими дополнительными функциями).
Рашак
6

Мне кажется, я слишком метафоричен и загадочен с предыдущим ответом. Уточнение следует.

Экземпляр Array, Boolean, Date, Function, Number, RegExp, String является объектом, но с добавлением методов и свойств, специфичных для каждого типа. Например, массив имеет предопределенное lengthсвойство, а универсальные объекты - нет.

javascript:alert([].length+'\n'+{}.length)

отображает

0
неопределенный

По сути, интерпретатор FF Gecko также различает массивы и общие объекты с четкими различиями при оценке языковых конструкций.

javascript:
  ra=[  "one",   "two",   "three"]; ra.a=4;
  ob={0:"one", 1:"two", 2:"three"}; ob.a=4;
  alert(
    ra            +"\n\n"+
    ob            +"\n\n"+
    ra.toSource() +"\n\n"+
    ra.a          +"\t .toSource() forgot me! \n\n"+
    ra.length     +"\t and my length! \n\n"+
    ob.toSource());
  ps=""; for(i in ra)ps+=i+" "; alert(ps);  /* NB .length is missing! */
  ps=""; for(i in ob)ps+=i+" "; alert(ps);

отображение

раз два три

[Объект Object]

["раз два три"]

4 .toSource () забыл меня! 

3 и моя длина! 

({0: "один", 1: "два", 2: "три", a: 4})

и 0 1 2 aи 0 1 2 a.

Что касается утверждения, что все объекты являются функциями:

Ни синтаксически, ни семантически не корректно использовать произвольный экземпляр объекта в качестве функции, такой как 123()or "abc"()or []()or {}()or obj()where objявляется любым типом, кроме Function, поэтому произвольный объект INSTANCE не является a Function. Однако, учитывая объект objи его тип Array, Boolean, Date, ..., как оно objпоявилось Array, Boolean, Date, ...? Что такое Array, Boolean, Date, ...?

javascript:
    alert([Array, Boolean, Date, Function, 
              Number, Object, RegExp, String] . join('\n\n') );

отображает

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

В каждом случае, без двусмысленности, тип объекта проявляется как functionопределение, отсюда и утверждение, что все объекты являются функциями! (Ирония в том, что я намеренно скрыл и размыл различие между экземпляром объекта и его типом! Тем не менее, это показывает, что «у вас не может быть одного без другого», объекта и функции! Заглавные буквы подчеркивают тип как в отличие от экземпляра.)

И функциональная, и объектная парадигмы кажутся фундаментальными для программирования и реализации встроенных примитивов низкого уровня интерпретатора JS, таких как Mathи JSONи true.

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));

отображает

[object Math]

[object JSON]

(new Boolean(true))

Во время разработки Javascript в моде был объектно-ориентированный стиль программирования (ООП - стиль объектно-ориентированного программирования - «s» - это мой собственный каламбур!), И интерпретатор был также назван Java, чтобы придать ему большее доверие. . Методы функционального программирования были отнесены к более абстрактным и эзотерическим экзаменам, изучающим теории автоматов, рекурсивных функций, формальных языков и т. Д., И как таковые не были приемлемыми. Однако сильные стороны этих формальных соображений явно проявляются в Javascript, особенно в том виде, в котором они реализованы в движке FF Gecko (т.е. .toSource()).


Определение объекта для функции особенно приятно, так как оно определено как рекуррентное отношение! определяется с использованием собственного определения!

function Function() { [native code] }
и поскольку функция является объектом, то же самое относится и к
function Object() { [native code] }.

Большинство других определений стабилизируются до статического конечного значения. Однако eval()это особенно мощный примитив, поэтому String также может включать произвольные функции.

Еще раз обратите внимание, что используемый выше жаргон скрывает различие между типом объекта и экземпляром.

Эким
источник
5

В JavaScript все объекты, кроме примитивных типов.

Код

var myArray = Array();

создает экземпляр объекта Array, пока

var myObject = {'A': 'Athens', 'B':'Berlin'};

создает экземпляр объекта Object.

Попробуйте следующий код

alert(myArray.constructor)
alert(myObject.constructor)

Таким образом, вы увидите разницу в типе конструктора объекта.

Экземпляр объекта Array будет содержать все свойства и методы прототипа Array.

Даша Сало
источник
2

Разница между массивами и другими объектами в JavaScript. В то время как массивы обладают волшебным образом обновляемым свойством длины, для объектов, отличных от массивов, нет способа реализовать такое свойство.

var arrName = [];
arrName[5] = "test";
arrName.length; // <- 6

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

Парт Раваль
источник
2

Вы можете добавлять именованные свойства практически ко всему в javascript, но это не значит, что вы должны это делать. Arrayв javascript следует использовать как список, если вы хотите использовать Objectвместо этого ассоциативный массив .

Помните, что если вы действительно хотите использовать Arrayименованные свойства вместо Objectэтих свойств, они не будут доступны в for...ofцикле, и вы также можете получить неожиданные результаты, когда JSON кодирует его для передачи. См. Пример ниже, где игнорируются все нечисловые индексы:

let arr = [];
let obj = {};

arr['name'] = 'John';
obj['name'] = 'John';

console.log(arr);    // will output [name: "John"]
console.log(obj);    // will output {name: "John"}

JSON.stringify(arr); // will return [] <- not what you expected
JSON.stringify(obj); // will return {"name":"John"}
Resu
источник
-1

{}-Notation просто синтаксический сахар , чтобы сделать код более хорошим ;-)

В JavaScript есть много похожих конструкций, таких как построение функций, где function () - это просто синоним для

var Func = new Function("<params>", "<code>");
Дарио
источник
3
Конструктор функции НЕ является синонимом литерала функции. Литерал имеет лексическую область видимости, а конструктор - глобальный. {}это буквальное обозначение объекта, []это буквальный массив, я не уверен, в чем смысл вашего ответа.
Хуан Мендес
Кроме того, объявленные функции доступны до выполнения любого кода, присвоения с помощью конструктора Function недоступны до тех пор, пока не будет выполнен код, который их создает.
RobG