Чому я можу додати властивості з назвою до масиву так, ніби це об'єкт?


105

Наступні два різних фрагменти коду здаються мені еквівалентними:

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

і

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

тому що вони обидва поводяться однаково, а також typeof(myArray) == typeof(myObjects)(обидва поступаються "об'єкту").

Чи є різниця між цими варіантами?

Відповіді:


131

Практично все в JavaScript є об'єктом, тому ви можете "зловживати" об'єктом Array , встановивши на нього довільні властивості. Це слід вважати шкідливим однак, . Масиви призначені для числово-індексованих даних - для нечислових ключів використовуйте Object.

Ось більш конкретний приклад, чому нечислові клавіші не "підходять" до масиву:

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
невизначений

Внутрішньо, інтерпретатор Ф. Ф. Гекко також розрізняє масиви та загальні об'єкти з чіткими відмінностями, що оцінюють мовні конструкції.

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);

показ

один два три

[об’єкт об’єкта]

["один два три"]

4 .toSource () забув мене! 

3 і моя довжина! 

({0: "один", 1: "два", 2: "три", 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, об'єктно-орієнтований стиль програмування (OOP - Об'єктно-орієнтований стиль програмування - "s" - це мій власний каламбур!) Був у моді, і інтерпретатор був аналогічно охрещений Java, щоб надати йому більшу надійність. . Методи функціонального програмування були перенесені на більш абстрактні та езотеричні дослідження, що вивчають теорії автоматів, рекурсивні функції, формальні мови тощо. Однак сильні сторони цих формальних міркувань чітко проявляються в Javascript, особливо як це реалізовано в двигуні Gecko FF (тобто .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"}

-1

{}-Notation просто синтаксичний цукор , щоб зробити код більш хорошим ;-)

У JavaScript є багато подібних конструкцій, таких як побудова функцій, де function () є лише синонімом

var Func = new Function("<params>", "<code>");

3
Конструктор функцій НЕ є синонімом функції буквал. Літерал охоплюється лексично, тоді як конструктор є глобальним. {}це буквальна нотація об'єкта, []це буквальний масив, я не впевнений, у чому сенс вашої відповіді.
Хуан Мендес

Також оголошені функції доступні перед виконанням будь-якого коду, призначення з використанням конструктора функцій недоступні, поки не виконається код, який створює їх.
RobG
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.