Чим відрізняється `новий Object ()` від буквеного позначення об'єкта?


199

Яка різниця між цим синтаксисом на основі конструктора для створення об’єкта:

person = new Object()

... і цей буквальний синтаксис:

person = {
    property1 : "Hello"
};

Здається, що обидва роблять те саме, хоча JSLint вважає за краще використовувати буквене позначення об'єкта.

Який краще і чому?


7
Все одно: a = new Object, a = new Object(), a = {}, буквальне набагато простіше і деякі тести я провів деякий час назад сказати , що це швидше, більш нові компілятори можуть бути викликані моїм твердження помилковим. Те ж стосується і буквальних масивів
Хуан Мендес

8
Сподіваємось, ви декларуєте свої змінні varключовим словом у коді програми, щоб уникнути забруднення глобального простору імен та створити необхідність виходити за межі поточного запису у стеку для своїх змінних.
Само

1
В основному, в будь-який момент під час виконання програми є стек записів або блоків. Кожен запис містить перелік змінних, які були створені в цій області. У JavaScript, якщо вираз містить змінну і інтерпретатор не може знайти його в записі стека для цього діапазону, він продовжує переходити до наступного запису, поки не знайде змінну. Більше інформації davidshariff.com/blog/…
Само

2
Уникнення JSLint - це перший крок у тому, щоб стати хорошим розробником. Використання new- це умова, яка виходить за межі безглуздого приниження посередньої мови. Використовуйте, newоскільки його значення зрозуміле. У 99,9% випадків підвищення продуктивності не має значення.
Hal50000

1
@ Hal50000 посередньою мовою, відповідно до кого?
Xam

Відповіді:


124

Вони обидва роблять те саме (якщо хтось зробив щось незвичне), крім того, що ваш другий створює об’єкт і додає йому властивість. Але буквальне позначення займає менше місця у вихідному коді. Це добре зрозуміло, що відбувається, тому використовуючи new Object(), ви дійсно просто набираєте більше і (теоретично, якщо не оптимізовано механізмом JavaScript), виконуючи непотрібний функціональний виклик.

Ці

person = new Object() /*You should put a semicolon here too.  
It's not required, but it is good practice.*/ 
-or-

person = {
    property1 : "Hello"
};

технічно не робити те саме. Перший просто створює об’єкт. Другий створює один і присвоює властивість. Щоб перша була однаковою, тоді вам потрібен другий крок, щоб створити та призначити властивість.

"Щось незвичне", що хтось міг би зробити, - це затінити або призначити Objectглобальному за замовчуванням :

// Don't do this
Object = 23;

У такому надзвичайно незвичному випадку new Objectне вдасться, але {}буде працювати.

На практиці ніколи немає причини використовувати, new Objectа не {}(якщо ви не зробили цю дуже незвичну річ).


11
Автор обрав цю відповідь правильною, але вона неповна. Пам’ятайте, що існують відмінності між двома синтаксисами, коли ви потрапляєте у розподіл пам'яті.
новинники

2
Різниць немає. Якщо ви посилаєтесь на один із відповідей у ​​розділі, це поза темою, оскільки йдеться про прототипну модель об'єкта та успадкування (код там встановлює клас Obj, який успадковується від простого Object). Це питання не стосується створення екземпляра якогось спеціального класу - це створення екземпляра Object, і правильна відповідь на це питання "немає різниці".
дос

FYI також () new Object()не потрібно. (говорити про не потрібно
речі

Я думаю, що нам не потрібно використовувати нові, як у поточній специфікації. Дайте мені знати ваші думки @kevin
Vamsi Pavan Mahesh

1
Ви також можете використовувати Object create і передавати null, якщо ви хочете об'єкт, який не успадковується з ланцюжка спадкування. Вони не рівні і мають корисні цілі відповідно.
Аарон

234

Немає різниці для простого об'єкта без методів, як у вашому прикладі. Однак є велика різниця, коли ви починаєте додавати методи до свого об’єкта.

Буквальний шлях:

function Obj( prop ) { 
    return { 
        p : prop, 
        sayHello : function(){ alert(this.p); }, 
    }; 
} 

Прототип способу:

function Obj( prop ) { 
    this.p = prop; 
} 
Obj.prototype.sayHello = function(){alert(this.p);}; 

Обидва способи дозволяють створювати Objподібні екземпляри :

var foo = new Obj( "hello" ); 

Однак буквальним способом ви переносите копію sayHelloметоду в кожен примірник своїх об'єктів. В той час, як за допомогою прототипу спосіб визначається в прототипі об'єкта і ділиться між усіма примірниками об'єкта. Якщо у вас багато об’єктів або багато методів, буквальний шлях може призвести до досить великої трати пам’яті.


39
Для мене питання було більше про відмінності між використанням new Object()vs {}для створення порожніх об'єктів.
Пітер

11
@Lobabob Окрім першого речення, ця відповідь насправді не дає жодної інформації щодо питання ОП. Він навіть ніде не містить 'нового Object () `. Чесно кажучи, я думаю, що пан Девід неправильно зрозумів питання.
JLRishe

17
Коли я опублікував це, прийнята відповідь вже була і була прийнята. І це прекрасно відповідає на питання ОП, тому я не збирався повторювати те саме. Свою відповідь я розмістив головним чином, щоб розширити тему поза порожніми / простими об'єктами. У цьому випадку є важлива різниця, яку варто згадати.
Rémy DAVID

3
Ця відповідь поза темою. У вашому коді Obj - це окремий клас, що успадковується від Object. Коли ви використовуєте буквене позначення об'єкта, ви використовуєте клас Object, а не Obj. Звичайно, встановлення класу з методом у його прототипі зробить слід пам’яті меншим, ніж створити безліч простих об’єктів та додасть метод як їх властивості, але це абсолютно не пов’язано із заданим тут питанням. Правильна відповідь на це запитання - «ні, різниці абсолютно немає (можливо, крім читабельності)».
дос

3
Я прийшов за цією відповіддю, ґрунтуючись на питанні, яке було подібне моєму, але в кінцевому підсумку я вивчив саме те, що мені потрібно було знати. Дякую.
Пат Мільяччо

55

У JavaScript ми можемо оголосити новий порожній об’єкт двома способами:

var obj1 = new Object();  
var obj2 = {};  

Я не знайшов нічого, що дозволяє сказати, що є якась суттєва різниця цих двох щодо того, як вони діють за кадром (будь ласка, виправте мене, якщо я помиляюся - я хотів би знати). Однак другий метод (використовуючи буквене позначення об'єкта) пропонує кілька переваг.

  1. Він коротший (10 точних символів)
  2. Легше та структурованіше створювати об’єкти на льоту
  3. Не має значення, чи якийсь буфон ненавмисно перекрив Об'єкт

Розглянемо новий об’єкт, який містить членів Name та TelNo. Використовуючи нову конвенцію Object (), ми можемо створити її так:

var obj1 = new Object();  
obj1.Name = "A Person";  
obj1.TelNo = "12345"; 

Функція Expando Properties JavaScript дозволяє нам створювати нових членів таким чином на ходу, і ми досягаємо того, що мали намір. Однак цей спосіб не дуже структурований або інкапсульований. Що робити, якщо ми хотіли вказати членів під час створення, не покладаючись на властивості розширення та призначення після створення?

Тут може допомогти буквальне позначення об'єкта:

var obj1 = {Name:"A Person",TelNo="12345"};  

Тут ми досягли такого ж ефекту в одному рядку коду і значно менше символів.

Подальше обговорення вищезазначених методів побудови об'єктів можна знайти на веб-сторінці: JavaScript та об'єктно-орієнтоване програмування (OOP).

І, нарешті, що з ідіота, який завис Об'єкт? Ви думали, що це неможливо? Що ж, цей JSFiddle доводить інакше. Використання буквеного позначення об'єкта заважає нам помилитися з цим буфонеєм.

http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/ )


1
Як щодо Object.Create? Дивіться: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Phil

Якщо ви збираєтеся віддавати перевагу об'єктним літералам new Object()через можливість того, що щось перестане функцію Object, вам також слід писати охоронців всюди, коли ви використовуєте помічники, Object.keysщоб переконатися, що це не визначено, що переходить у абсурд. Я завжди рекомендував би людям використовувати буквальне позначення, але я думаю, що цей конкретний аргумент розпадається, коли ви думаєте про наслідки такого мислення.
філарай

41

На своїй машині за допомогою Node.js я запустив наступне:

console.log('Testing Array:');
console.time('using[]');
for(var i=0; i<200000000; i++){var arr = []};
console.timeEnd('using[]');

console.time('using new');
for(var i=0; i<200000000; i++){var arr = new Array};
console.timeEnd('using new');

console.log('Testing Object:');

console.time('using{}');
for(var i=0; i<200000000; i++){var obj = {}};
console.timeEnd('using{}');

console.time('using new');
for(var i=0; i<200000000; i++){var obj = new Object};
console.timeEnd('using new');

Зауважте, це розширення того, що тут знайдено: Чому arr = [] швидше, ніж arr = новий масив?

мій вихід був таким:

Testing Array:
using[]: 1091ms
using new: 2286ms
Testing Object:
using{}: 870ms
using new: 5637ms

настільки чітко {} і [] швидше, ніж використання нових для створення порожніх об'єктів / масивів.


3
Я відчуваю, що це відповідь на те, що питання справді шукали, хоча я хотів би бачити це додатково перевірене на об’єкті з кількома властивостями, щоб переконатися.
Чейз Сандман

2
Цікаві цифри. Є люди, які повинні знати про це, але я забираю, що виділення навіть мізерних 200 000 об'єктів коштуватиме мені лише 5,6 мс, тому я не буду про це турбуватися.

У Node 10.13.0 речі ВИМІНЕНО Масив тестування: використовуючи []: 117,178ms з використанням нового: 116,947ms Тестовий об'єкт: з використанням {}: 116,252ms з використанням нового: 115,910ms
PirateApp

31

Усі тут говорять про схожість двох. Я хочу вказати на відмінності.

  1. Використання new Object()дозволяє передавати інший об’єкт. Очевидний результат полягає в тому, що новостворений об’єкт буде встановлений на ту саму посилання. Ось зразок коду:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. Використання не обмежується об'єктами, як в OOP-об'єктах. До нього можуть передаватися й інші типи. Функція відповідно встановить тип. Наприклад, якщо ми передамо йому ціле число 1, для нас буде створений об'єкт номера типу.

    var obj = new Object(1);
    typeof obj // "number"
  3. Об'єкт, створений за допомогою вищевказаного методу ( new Object(1)), буде перетворений у тип об'єкта, якщо до нього буде додано властивість.

    var obj = new Object(1);
    typeof obj // "number"
    obj.a = 2;
    typeof obj // "object"
  4. Якщо об’єкт є копією дочірнього класу об'єкта, ми можемо додати властивість без перетворення типу.

    var obj = new Object("foo");
    typeof obj // "object"
    obj === "foo" // true
    obj.a = 1;
    obj === "foo" // true
    obj.a // 1
    var str = "foo";
    str.a = 1;
    str.a // undefined

3
Я дуже розгублений з приводу останніх двох рядків .. Чому, якщо ви призначите для str.a значення 1, str.a не визначене? .. @Jermin Bazazin
Андреа Скарафоні

3
@AndreaScarafoni, тому що strмає тип, stringтому ви не можете призначити їй властивість. jsfiddle.net/grq6hdx7/1
Кріс Бір

1
Чи змінилася відповідь на 4? Мені стає неправдивим, не правдою, в останньому Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
William Hilton

21

Власне, існує кілька способів створення об’єктів у JavaScript. Коли ви просто хочете створити об'єкт, немає переваги створювати об'єкти на основі конструктора за допомогою " нового " оператора. Це те саме, що створити об’єкт за допомогою синтаксису " об'єкт буквально ". Але " об'єкти на основі конструктора ", створені з " новим " оператором, користуються неймовірною користю, коли ви замислюєтесь про " прототипне успадкування ". Ви не можете підтримувати ланцюжок успадкування з об'єктами, створеними з буквальним синтаксисом. Але ви можете створити функцію конструктора , приєднати властивості та методи до його прототипу."Оператор, він поверне об'єкт, який матиме доступ до всіх методів та властивостей, приєднаних до прототипу функції цього конструктора.

Ось приклад створення об'єкта за допомогою функції конструктора (див. Пояснення коду внизу):

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
}

Person.prototype.fullname = function() {
    console.log(this.firstname + ' ' + this.lastname);
}

var zubaer = new Person('Zubaer', 'Ahammed');
var john = new Person('John', 'Doe');

zubaer.fullname();
john.fullname();

Тепер ви можете створити скільки завгодно об'єктів, інстанціюючи функцію побудови Person, і всі вони успадкують від неї повне ім’я ().

Примітка: ключове слово " це " позначатиметься порожнім об'єктом в рамках функції конструктора, і кожного разу, коли ви створюєте новий об'єкт від Person за допомогою оператора " new ", він автоматично повертає об'єкт, що містить усі властивості та методи, додані до ключового слова " this " . І ці об’єкти точно успадкують методи та властивості, приєднані до прототипу функції конструктора Person (що є основною перевагою такого підходу).

До речі, якщо ви хочете отримати однаковий функціонал із синтаксисом " об'єкт-буквальний ", вам доведеться створити fullname () для всіх об'єктів, як нижче:

var zubaer = {
    firstname: 'Zubaer',
    lastname: 'Ahammed',
    fullname: function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
};

var john= {
    firstname: 'John',
    lastname: 'Doe',
    fullname: function() {
        console.log(this.firstname + ' ' + this.lastname);
    }
};

zubaer.fullname();
john.fullname();

Нарешті, якщо ви зараз запитаєте, чому я повинен використовувати підхід функції конструктора замість об'єктного буквального підходу:

*** Прототипне успадкування дозволяє простий ланцюг успадкування, який може бути надзвичайно корисним і потужним.

*** Це економить пам'ять, успадковуючи загальні методи та властивості, визначені в прототипі функцій конструктора. В іншому випадку вам доведеться копіювати їх знову і знову в усі об'єкти.

Сподіваюся, це має сенс.


Дякую! Карл за додавання пропущеного "цього" в об'єктний буквал. Це була жахлива помилка. Я не повинен був робити такого типу помилок.
Пані Зубаер Ахаммед

"Ви не можете успадкувати об'єкт, створений з буквальним синтаксисом." - Неправда (я вірю). Ви можете використовувати Object.create(<object defined using literal notation>)або new Object(<object defined using literal notation>)створювати спадкові ланцюги за потребою.
balajeerc

@balajeerc Дякуємо за ваш коментар Насправді це повинно бути "Ви не можете підтримувати ланцюжок успадкування з об'єктами, створеними з буквальним синтаксисом". Відповідь в декілька кроків: 1. Object.create (): Так, можна передати йому об'єкт буквально, і він поверне новий об'єкт, прототип якого буде переданий об'єкта буквалом. Але він не знає, що це за конструкторська функція, або не пам’ятає той буквений об’єкт, з якого він створений. Отже, testobj1.constructor поверне порожню функцію, і немає можливості додати властивості / методи до цього об'єкта буквально, як це батько / пращур.
Пані Зубайер Ахаммед

@balajeerc 2. новий Object (): У цьому випадку відбувається майже те саме. Причому гірше, якщо подумати про пам’ять. Замість того, щоб властивості та методи вносити до прототипу, він просто копіює все з прямого об'єкта, що передається, і ставить його у повернутий об'єкт. Це не добре для пам’яті. З іншого боку, я зосередився на справжньому ланцюжку успадкування з функцією конструктора, де ви можете редагувати методи та властивості під час руху та інші об'єкти, створені методом конструктора, також впливають, оскільки вони вказують лише на цю функцію конструктора (замість копіювання) .
Пані Зубаєр Ахаммед

@balajeerc Приклад:function Person(firstname, lastname) { this.firstname = firstname; this.lastname = lastname; } Person.prototype.fullname = function() { console.log(this.firstname + ' ' + this.lastname); } var zubaer = new Person('Zubaer', 'Ahammed'); var john = new Person('John', 'Doe'); zubaer.fullname(); // Zubaer Ahammed john.fullname(); // John Doe zubaer.constructor.prototype.fullname = function() { console.log( 'Hello ' + this.firstname); } zubaer.fullname(); // Hello Zubaer john.fullname(); // Hoello John
Пан Зубайер Ахаммед

9

Також, згідно з деякими книгами O'Really javascript .... (цитується)

Інша причина використання літералів на відміну від конструктора Object полягає в тому, що не існує роздільної здатності. Оскільки можливо, що ви створили локальний конструктор з тим самим іменем, інтерпретатору потрібно шукати ланцюг діапазону з місця, яке ви викликаєте Object (), аж доки він не знайде глобальний конструктор Object.


24
чекати, чи був О'Справді помилковим друком чи навмисним каламбуром? Вони повинні використовувати це для продажу своїх книг!
Тім Огілві

3

Я знайшов одну різницю для ES6 / ES2015. Ви не можете повернути об'єкт за допомогою синтаксису функції короткої стрілки, якщо ви не оточуєте об'єкт new Object().

> [1, 2, 3].map(v => {n: v});
[ undefined, undefined, undefined ]
> [1, 2, 3].map(v => new Object({n: v}));
[ { n: 1 }, { n: 2 }, { n: 3 } ]

Це тому, що компілятор плутається в {}дужках і думає n: i, що це мітка: конструкція заяви ; крапка з комою необов’язково, тому вона не скаржиться на це.

Якщо до об'єкта додати ще одне властивість, воно остаточно видасть помилку.

$ node -e "[1, 2, 3].map(v => {n: v, m: v+1});"
[1, 2, 3].map(v => {n: v, m: v+1});
                           ^

SyntaxError: Unexpected token :

4
Ви все ще можете скористатися функцією стрілки, просто знадобиться більше дужок і повернення: [1, 2, 3].map(v => { return {n: v}; });буде тобі те саме ...
Єретична мавпа

Звичайно, ви можете використовувати звичайні функції стрілок, про що я говорив - це скорочена версія, тобто param => return_valueрізниця між використанням {}та new Object()в даному випадку.
Андрій Сіміонеску

11
Ви все ще можете використовувати скорочену версію І звичайні функції зі стрілками. Просто оберніть {n: v} парою з дужок:[1, 2, 3].map(v => ({n: v}));
Стівен C

1

Оновлення 2019 року

Я запустив той самий код, що і @rjloura на моєму вузлі OSX High Sierra 10.13.6 версії 10.13.0, і це результати

console.log('Testing Array:');
console.time('using[]');
for(var i=0; i<200000000; i++){var arr = []};
console.timeEnd('using[]');

console.time('using new');
for(var i=0; i<200000000; i++){var arr = new Array};
console.timeEnd('using new');

console.log('Testing Object:');

console.time('using{}');
for(var i=0; i<200000000; i++){var obj = {}};
console.timeEnd('using{}');

console.time('using new');
for(var i=0; i<200000000; i++){var obj = new Object};
console.timeEnd('using new');


Testing Array:
using[]: 117.613ms
using new: 117.168ms
Testing Object:
using{}: 117.205ms
using new: 118.644ms

-2

Використання пам'яті відрізняється, якщо ви створюєте 10 тис. Екземплярів. new Object()збереже лише один примірник, а {}10 тисяч примірників.


7
newстворює новий об’єкт. Вони обидва займають однаковий об'єм пам'яті.
Artyer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.