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

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

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

и

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

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

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


person prinzdezibel    schedule 17.05.2009    source источник


Ответы (8)


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

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

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

alert(myArray.length);

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

person Paul Dixon    schedule 17.05.2009
comment
myArray.length возвращает числовой индекс / ключ последнего элемента в массиве, но не фактическое количество элементов. Свойства объекта Array не совпадают со значениями массива? - person Dasha Salo; 17.05.2009
comment
Я просто пытался проиллюстрировать предполагаемую семантику объекта Array, которым злоупотребляют, если вы просто относитесь к нему как к обычному объекту. Однако связанная статья работает лучше :) - person Paul Dixon; 17.05.2009
comment
В следующий раз, когда кто-нибудь скажет, что JavaScript - хороший язык для разработки, я покажу ему этот образец. Спасибо. - person Olivier Pons; 19.04.2014
comment
@Olivier, то, что вы называете ошибкой, тоже может быть отличной функцией. Вы можете добавлять названия и описания к массивам, не влияя на их содержимое или длину и не помещая их в объекты со свойствами title, description и items. Все зависит от того, насколько хорошо вы знаете язык и как вы им пользуетесь. - person tao; 09.03.2020
comment
Использование настраиваемых свойств в массивах не является неправильным по своей сути. Неправильно ожидать, что они будут действовать как члены массива, как только вы это сделаете. Они являются свойствами массива, а не членами, поэтому на них не влияют методы массива. Об этом на самом деле говорит автор упомянутой выше статьи в комментариях. Честно говоря, я бы посоветовал не использовать это как практику, так как это, вероятно, запутает людей, использующих ваш код. Или, если они только начинают, своим примером это наставит их на опасный путь. Но я бы не сказал, что JavaScript - это плохо, потому что он позволяет делать вещи, на которые многие не рассчитывают. - person tao; 09.03.2020
comment
+1 дао: если это, вероятно, запутает людей, использующих ваш код, то это по своей сути язык, склонный к большему количеству проблем - person Olivier Pons; 11.03.2020

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

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

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

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

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

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

отображает

0
undefined

По сути, интерпретатор 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);

отображение

one,two,three

[object Object]

["one", "two", "three"]

4    .toSource() forgot me! 

3    and my length! 

({0:"one", 1:"two", 2:"three", a:4})

и 0 1 2 a и 0 1 2 a.

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

Ни синтаксически, ни семантически не корректно использовать произвольный экземпляр объекта в качестве функции типа 123(), "abc"(), [](), {}() или obj(), где obj - это любой тип, отличный от Function, поэтому произвольный объект INSTANCE не является 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 также может включать произвольные функции.

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

person Ekim    schedule 17.05.2011

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

Код

var myArray = Array();

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

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

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

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

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

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

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

person Dasha Salo    schedule 17.05.2009

Вы можете добавлять именованные свойства практически ко всему в 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"}
person resu    schedule 23.01.2017

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

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

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

person Parth Raval    schedule 19.04.2018
comment
для объектов, отличных от массивов, нет возможности реализовать такое свойство. могут использоваться, помимо прочего, геттеры, сеттеры и прокси. Это возможно, но не поведение по умолчанию. - person VLAZ; 21.04.2021

В JavaScript массивы - это особые типизированные объекты.

typeof new Array(); // returns "object" 
typeof new Object(); // returns "object

Используемые массивы нумерованные индексы и используемые объекты именованные индексы

чтобы мы могли добавлять именованные свойства в массив

const arr = []
arr["A"] = "Hello" //["A":"Hello"]

console.log(arr.length) // 0 

arr.length возвращает 0, потому что массив с именованными индексами предпочитает вызывать объекты

console.log(Object.keys(clothing)); // ["A"]
console.log(Object.keys(clothing).length); //1
person venky    schedule 17.12.2020

{}-нотация - это просто синтаксический сахар, делающий код лучше ;-)

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

var Func = new Function("<params>", "<code>");
person Dario    schedule 17.05.2009
comment
Конструктор функции НЕ является синонимом литерала функции. Литерал имеет лексическую область видимости, а конструктор - глобальный. {} - это буквальная запись объекта, [] - буквальный массив, я не уверен, в чем суть вашего ответа. - person Juan Mendes; 21.04.2011
comment
Кроме того, объявленные функции доступны до выполнения любого кода, присвоения с использованием конструктора Function недоступны до тех пор, пока не будет выполнен код, который их создает. - person RobG; 11.09.2014