В чем разница между `new Object ()` и литеральной нотацией объекта?

199

В чем разница между этим основанным на конструкторе синтаксисом для создания объекта:

person = new Object()

... и этот буквальный синтаксис:

person = {
    property1 : "Hello"
};

Похоже, что оба делают одно и то же, хотя JSLint предпочитает использовать буквенное обозначение объекта.

Какой из них лучше и почему?

крайний тип телосложения
источник
7
Все равно: a = new Object, a = new Object(), a = {}, буквальное гораздо проще и некоторые тесты я провел некоторое время назад сказать , что это быстрее, более новые компиляторы могут быть вызваны моим утверждение ложным. То же самое относится к буквенным массивам
Хуан Мендес
8
Надеемся, что вы объявляете переменные с varключевым словом в коде приложения, чтобы не загрязнять глобальное пространство имен и создавать необходимость поиска переменных переменных за пределами текущей записи в стеке.
Само
1
По сути, в любой момент во время выполнения программы существует стек записей или блоков. Каждая запись имеет список переменных, которые были созданы в этой области. В JavaScript, если выражение содержит переменную и интерпретатор не может найти ее в записи стека для этой области, он будет продолжать переходить к следующей записи, пока не найдет переменную. Дополнительная информация: davidshariff.com/blog/…72
Само
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а не {}(если вы не сделали эту очень необычную вещь).

kemiller2002
источник
11
Автор выбрал этот ответ как правильный, но он неполный. Имейте в виду, что между двумя синтаксисами есть различия, когда вы занимаетесь выделением памяти.
шорты
2
Там нет никаких различий. Если вы ссылаетесь на один из ответов ниже, он не по теме, так как он говорит об объектной модели и наследовании на основе прототипов (там код устанавливает класс Obj, который наследуется от простого Object). Этот вопрос не о создании экземпляра какого-либо пользовательского класса, а о создании экземпляра Object, и правильный ответ на этот вопрос «нет никакой разницы».
дос
К вашему сведению также () new Object()не требуется. (говорим о не обязательных вещах)
Ройи Намир
Я думаю, что нам не нужно использовать новый с текущей спецификации. Дайте мне знать ваши мысли @kevin
Вамси Паван Махеш
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 Помимо первого предложения, этот ответ на самом деле не дает никакой информации по вопросу OP. Он даже нигде не содержит «new Object ()». Честно говоря, я думаю, что мистер Дэвид неправильно понял вопрос.
JLRishe
17
Когда я написал это, принятый ответ уже был там и принят. И это отлично отвечает на вопрос ОП, поэтому я не собирался повторять то же самое. Я опубликовал свой ответ главным образом, чтобы расширить тему за пределы пустых / простых объектов. В этом случае есть это важное различие , которое стоит упомянуть.
Реми ДЭВИД
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 позволяет нам создавать новых участников таким образом на лету, и мы достигаем того, что намеревались. Однако этот способ не очень структурирован и не заключен в капсулу. Что если мы захотим указать членов при создании, не полагаясь на свойства expando и назначение после создания?

Вот где могут помочь буквенные обозначения объекта:

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

Здесь мы добились того же эффекта в одной строке кода и значительно меньше символов.

Дальнейшее обсуждение методов конструирования объектов выше можно найти по адресу: JavaScript и объектно-ориентированное программирование (ООП).

И, наконец, что за идиот, который отверг Объект? Вы думали, что это невозможно? Ну, этот 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/…
Фил
Если вы предпочитаете объектные литералы new Object()из-за вероятности того, что что-то перезаписало функцию объекта, вы также должны повсеместно писать охранников, когда используете помощников, например, Object.keysчтобы убедиться, что они не определены, что приводит к абсурду. Я всегда рекомендовал бы людям использовать буквальную запись, но я думаю, что этот конкретный аргумент разваливается, когда вы думаете о последствиях такого мышления.
Philraj
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 = new Array?

мой вывод был следующим:

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

так ясно, что {} и [] быстрее, чем использование new для создания пустых объектов / массивов.

rjloura
источник
3
Я чувствую, что это ответ, который действительно искал вопрос, хотя я хотел бы видеть это дополнительно проверенным на объекте с несколькими свойствами, чтобы убедиться.
Чейз Сэндманн
2
Интересные цифры. Есть люди, которые должны знать об этом, но я убираю, что выделение даже скудных 200 000 объектов обойдется мне всего в 5,6 мс, поэтому я не буду беспокоиться об этом.
В Узле 10.13.0 все изменилось. Массив тестирования: с использованием []: 117,178 мс с использованием нового: 116,947 мс Объект тестирования: с использованием {}: 116,252 мс с использованием нового: 115,910 мс
PirateApp
31

Все здесь говорят о сходстве двух. Я собираюсь указать на различия.

  1. Использование new Object()позволяет передавать другой объект. Очевидным результатом является то, что вновь созданный объект будет установлен на ту же ссылку. Вот пример кода:

    var obj1 = new Object();
    obj1.a = 1;
    var obj2 = new Object(obj1);
    obj2.a // 1
  2. Использование не ограничено объектами, как в объектах ООП. Другие типы могут быть переданы ему тоже. Функция установит тип соответственно. Например, если мы передадим ему целое число 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 не определено? .. @Джермин Базазин
Андреа Скарафони
3
@AndreaScarafoni, потому что strимеет тип, stringпоэтому вы не можете назначить ему свойство. jsfiddle.net/grq6hdx7/1
Крис Бьер
1
Изменился ли ответ на 4? Я ошибаюсь, не правда, в последнем Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
Уильям Хилтон
21

На самом деле, есть несколько способов создания объектов в JavaScript. Когда вы просто хотите создать объект, нет смысла создавать объекты на основе конструктора, используя оператор « new ». Это то же самое, что создание объекта с использованием синтаксиса « object literal ». Но « основанные на конструкторе » объекты, созданные с помощью оператора « new », находят невероятное применение, когда вы думаете о « наследовании прототипа ». Вы не можете поддерживать цепочку наследования с объектами, созданными с буквальным синтаксисом. Но вы можете создать функцию конструктора , прикрепить свойства и методы к ее прототипу.msgstr "Оператор возвращает объект, который будет иметь доступ ко всем методам и свойствам, связанным с прототипом этой функции конструктора.

Вот пример создания объекта с использованием функции конструктора (см. Объяснение кода внизу):

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, и все они унаследуют от нее fullname ().

Примечание. Ключевое слово « this » будет ссылаться на пустой объект в функции-конструкторе, и всякий раз, когда вы создаете новый объект из Person с помощью оператора « new », оно автоматически возвращает объект, содержащий все свойства и методы, связанные с ключевым словом « this ». , И эти объекты наверняка унаследуют методы и свойства, связанные с прототипом функции конструктора Person (что является основным преимуществом этого подхода).

Кстати, если вы хотите получить ту же функциональность с синтаксисом « object literal », вам придется создать 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();

Наконец, если вы сейчас спросите, почему я должен использовать подход с использованием функции конструктора вместо объектного литерального подхода:

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

*** Это экономит память путем наследования общих методов и свойств, определенных в прототипе функций конструктора. В противном случае вам придется копировать их снова и снова во всех объектах.

Я надеюсь это имеет смысл.

Д-р Зубаер Ахаммед
источник
Спасибо! Карла за добавление недостающего «this» в литерал объекта. Это была ужасная ошибка .. Я не должен был делать такого рода ошибки.
Г-н Зубаер Ахаммед
«Вы не можете наследовать от объекта, созданного с буквальным синтаксисом». - Не правда (я верю). Вы можете использовать Object.create(<object defined using literal notation>)или new Object(<object defined using literal notation>)создавать цепочки наследования по мере необходимости.
balajeerc
@balajeerc Спасибо за ваш комментарий. На самом деле это должно быть «Вы не можете поддерживать цепочку наследования с объектами, созданными с буквальным синтаксисом». Ответ в несколько этапов: 1. Object.create (): Да, возможно передать ему литерал объекта, и он вернет новый объект, прототип которого передан литералу объекта. Но он не знает, что это за функция конструктора, или не помнит тот литерал объекта, из которого он был создан. Таким образом, testobj1.constructor вернет пустую функцию, и не будет никакого способа добавить свойства / методы к этому литералу объекта в качестве его родителя / предка.
Г-н Зубаер Ахаммед
@balajeerc 2. new 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

Кроме того, согласно некоторым книгам О'Рейли на JavaScript ... (цитируется)

Другая причина использования литералов в отличие от конструктора Object - отсутствие разрешения области видимости. Поскольку возможно, что вы создали локальный конструктор с тем же именем, интерпретатору необходимо искать цепочку областей действия от места, где вы вызываете Object (), до тех пор, пока он не найдет глобальный конструктор Object.

adolfo_isassi
источник
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это метка: оператор construct; точка с запятой необязательна, поэтому не жалуется на это.

Если вы добавите другое свойство к объекту, оно, наконец, выдаст ошибку.

$ 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}));
Стивен С
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
PirateApp
источник
-2

Использование памяти отличается, если вы создаете 10 тысяч экземпляров. new Object()останется только одна копия, а {}будет 10 тысяч копий.

Ричард Мяо США
источник
7
newсоздает новый объект. Они оба занимают одинаковое количество памяти.
Artyer