“ new Object()”和对象文字表示法有什么区别?


199

创建对象的基于构造函数的语法之间有什么区别:

person = new Object()

...以及这种文字语法:

person = {
    property1 : "Hello"
};

尽管JSLint偏爱您使用对象文字表示法,但两者似乎都做相同的事情。

哪一个更好,为什么?


7
都是一样的:a = new Objecta = new Object()a = {},文字更简单,一些测试,我跑前一阵子,说这是更快,更新的编译器可能导致我的发言是假的。同样适用于文字数组
Juan Mendes

8
希望您var在应用程序代码中使用关键字声明变量,以避免污染全局名称空间,并避免需要在堆栈的当前记录之外查找变量。
Samo

1
基本上,在程序执行过程中的任何时候,都有一堆记录或块。每个记录都有在该范围内创建的变量列表。在JavaScript中,如果表达式包含变量,并且解释器无法在该范围的堆栈记录中找到它,则它将一直前进到下一条记录,直到找到该变量为止。更多信息davidshariff.com/blog/…–
萨莫

2
避免使用JSLint是成为优秀开发人员的第一步。使用new是一种超越平庸语言的毫无意义的习惯。请使用,new因为其含义很清楚。在99.9%的情况下,性能提升无关紧要。
Hal50000

1
@ Hal50000平庸的语言是根据谁?
Xam

Answers:


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
作者选择了正确的答案,但并不完整。请注意,当您进行内存分配时,这两种语法之间存在差异。
newshorts 2015年

2
没有区别。如果您指的是以下答案之一,那么它就没什么用了,因为它谈论的是基于原型的对象模型和继承(那里的代码设置了从纯Object继承的Obj类)。这个问题不是关于创建某些自定义类的实例,而是关于创建Object的实例,并且对此问题的正确答案是“没有区别”。
dos

() new Object()也不要求提供FYI 。(谈论不需要的事)
Royi Namir

我认为我们不必在当前规范中使用new。让我知道您的想法@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除了第一句话外,该答案实际上没有提供有关OP问题的任何信息。它甚至在任何地方都不包含“ new Object()”。坦率地说,我认为戴维先生误解了这个问题。
JLRishe 2014年

17
当我发布此消息时,已经接受并接受了答案。它完美地回答了OP问题,所以我不再重复相同的事情。我发布我的答案主要是为了将主题扩展到空/简单对象之外。在这种情况下,有其中值得一提的一个重要区别。
雷米·戴维

3
这个答案是题外话。在您的代码中,Obj是一个继承自Object的单独的类。当使用对象文字表示法时,使用的是Object类,而不是Obj。当然,在其原型中使用方法设置类将比创建大量普通对象并添加方法作为其属性来减少内存占用,但这与此处提出的问题完全无关。这个问题的正确答案是“不,绝对没有区别(也许除了可读性之外)”。
dos

3
我来这个答案的依据是一个类似于我的问题,但最终却确切地了解了我需要知道的内容。谢谢。
Pat Migliaccio

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属性JavaScript功能使我们能够以这种方式即时创建新成员,并实现了预期的目标。但是,这种方式不是非常结构化或封装的。如果我们想在创建时指定成员,而不必依赖expando属性和创建后分配该怎么办?

这是对象文字符号可以提供帮助的地方:

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

在这里,我们在一行代码中实现了相同的效果,并且字符数明显减少。

可以在以下位置找到对上述对象构造方法的进一步讨论:JavaScript和面向对象编程(OOP)。

最后,取代Object的白痴是谁?您认为不可能吗?好吧,这个JSFiddle证明不是。使用对象文字表示法可以防止我们误以为是这种骗子。

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



如果new Object()由于某些东西覆盖了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创建空对象/数组要快。


3
我觉得这是问题的真正答案,尽管我希望已经对此进行了测试,以确保具有一些属性。
Chase Sandmann 2014年

2
有趣的数字。有些人需要意识到这一点,但是我认为即使分配一个微不足道的200,000个对象也只会花费我5.6毫秒,因此我不必担心。

在节点10.13.0上,事物发生了变化测试阵列:using []:117.178ms使用新:116.947ms测试对象:using {}: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传递给它,则会为我们创建一个类型为number的对象。

    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?
安德烈Scarafoni

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创建对象。当您只想创建一个对象时,使用“ new ”运算符创建“ 基于构造函数 ”的对象没有任何好处。这与使用“ 对象文字 ”语法创建对象相同。但是,当您考虑“ 原型继承 ” 时,使用“ new ”运算符创建的“ 基于构造函数 ”的对象将变得不可思议地使用。您不能维护使用文字语法创建的对象的继承链。但是您可以创建一个构造函数,将属性和方法附加到其原型。”运算符,它将返回一个对象,该对象可以访问该构造函数的原型附带的所有方法和属性。

这是使用构造函数创建对象的示例(请参见底部的代码说明):

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 ”关键字将引用构造函数中的一个空对象,每当您使用“ new ”运算符从Person中创建一个新对象时,它将自动返回一个包含所有带有“ 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();

最后,如果您现在问为什么我应该使用构造函数函数方法而不是对象文字方法:

***原型继承允许一个简单的继承链,这可能是非常有用和强大的。

***它通过继承构造函数实例中定义的通用方法和属性来节省内存。否则,您将不得不在所有对象中一遍又一遍地复制它们。

我希望这是有道理的。


谢谢!Karl在对象文字中添加了缺少的“ this”。这是一个可怕的错误。我不应该犯这种类型的错误。
祖拜尔·阿罕默德(Mr. Zubaer Ahammed)'16

“您不能从使用文字语法创建的对象继承。” -不正确(我相信)。您可以根据需要使用Object.create(<object defined using literal notation>)new Object(<object defined using literal notation>)创建继承链。
balajeerc

@balajeerc感谢您的评论。实际上应该是“您不能维护使用文字语法创建的对象的继承链”。答案有多个步骤:1. Object.create():是的,可以将对象文字传递给它,它将返回一个新对象,原型将传递该对象文字。但是它不知道它是什么构造函数,或者不记得创建它的对象文字。因此,testobj1.constructor将返回一个空函数,并且没有办法向该对象文字添加属性/方法,因为它是其父/祖先。
祖拜尔·阿罕默德(Mr. Zubaer Ahammed)'16

@balajeerc 2. new Object():在这种情况下几乎会发生同样的事情。此外,如果考虑内存,情况会更糟。它没有将属性和方法放入其原型,而是仅复制了传递的对象文字中的所有内容并将其放入返回的对象中。这对内存不好。另一方面,我专注于带有构造函数的真正继承链,您可以在其中动态编辑方法和属性,使用构造函数创建的其他对象也受到影响,因为它们仅指向该构造函数(而不是复制它们) 。
祖拜尔·阿罕默德(Mr. Zubaer Ahammed)'16

@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
M .. Zubaer Ahammed博士

9

另外,根据O'Really的一些javascript书籍。...(引用)

使用文字而不是对象构造函数的另一个原因是没有范围解析。因为可能已经创建了一个具有相同名称的本地构造函数,所以解释器需要从您一直调用Object()的位置一直查找范围链,直到找到全局Object构造函数为止。


24
等待O'Really是错字还是故意的双关语?他们应该将其用于营销他们的书籍!
Tim Ogilvy 2014年

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是一个label:语句构造;分号是可选的,因此它不会对此有所抱怨。

如果将另一个属性添加到对象,它将最终引发错误。

$ 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}; });可以使您获得相同的东西……
Heretic Monkey

当然,您可以使用常规的箭头功能,我所说的是速记版本,即param => return_value{}以及new Object()在这种情况下使用和之间的区别。
Andrei Simionescu '16

11
您仍然可以使用简写版本和常规箭头功能。只需在{n:v}上加上一对括号即可:[1, 2, 3].map(v => ({n: v}));
Stephen C

1

2019更新

我在OSX High Sierra 10.13.6节点版本10.13.0上运行了与@rjloura相同的代码,这些是结果

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.