【问题标题】:What is the difference between `new Object()` and object literal notation?`new Object()` 和对象字面量表示法有什么区别?
【发布时间】:2011-06-03 15:10:30
【问题描述】:

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

person = new Object()

...和这个字面语法:

person = {
    property1 : "Hello"
};

看起来两者都做同样的事情,尽管 JSLint 更喜欢你使用对象文字表示法。

哪个更好,为什么?

【问题讨论】:

  • 都一样:a = new Objecta = new Object()a = {},文字要简单得多,我前段时间运行的一些测试说它更快,较新的编译器可能导致我的语句错误的。同样适用于文字数组
  • 基本上,在程序执行过程中的任何时候,都会有一堆记录或块。每条记录都有一个在该范围内创建的变量列表。在 JavaScript 中,如果一个表达式包含一个变量并且解释器在该范围的堆栈记录中找不到它,它将继续查找下一条记录,直到找到该变量。更多信息davidshariff.com/blog/…
  • 避免使用 JSLint 是成为优秀开发人员的第一步。使用new 是一种超越平庸语言毫无意义的吹毛求疵的约定。使用new,因为它的含义很明确。在 99.9% 的情况下,性能提升是无关紧要的。
  • @Hal50000 根据谁的平庸语言?

标签: javascript object jslint


【解决方案1】:

在您的示例中,没有方法的简单对象没有区别。 但是,当您开始向对象添加方法时,会有很大的不同。

字面意思:

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 方法的副本。而通过原型方式,方法是在对象原型中定义的,并在所有对象实例之间共享。 如果你有很多对象或者很多方法,字面的方式会导致相当大的内存浪费。

【讨论】:

  • 对我来说,问题更多是关于使用 new Object(){} 创建空对象的区别。
  • @Lobabob 除了第一句话,这个答案实际上并没有提供任何关于 OP 问题的信息。它甚至在任何地方都不包含“new Object()”。坦率地说,我认为大卫先生误解了这个问题。
  • 当我发布这个时,接受的答案已经存在并被接受。它完美地回答了 OP 问题,所以我不会重复同样的事情。我发布我的答案主要是为了将主题扩展到空/简单的对象之外。在这种情况下,有一个值得一提的重要区别。
  • 这个答案是题外话。在您的代码中,Obj 是一个继承自 Object 的单独类。当您使用对象字面量表示法时,您使用的是 Object 类,而不是 Obj。当然,在其原型中设置一个带有方法的类将使内存占用比创建许多普通对象并添加方法作为它们的属性更小,但这与这里提出的问题完全无关。这个问题的正确答案是“不,绝对没有区别(也许除了可读性)”。
  • 我是为这个答案而来的,基于一个类似于我的问题,但最终确切地了解了我需要知道的内容。谢谢。
【解决方案2】:

他们都做同样的事情(除非有人做了不寻常的事情),除了你的第二个创建一个对象向它添加一个属性。但是文字符号在源代码中占用的空间更少。可以清楚地识别正在发生的事情,因此使用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 global:

// Don't do this
Object = 23;

在那种非常不寻常的情况下,new Object 会失败,但{} 会起作用。

在实践中,没有理由使用new Object 而不是{}(除非你做过非常不寻常的事情)。

【讨论】:

  • 作者选择此答案为正确,但不完整。当您进入内存分配时,请注意这两种语法之间存在差异。
  • 没有区别。如果您指的是下面的答案之一,那么它是题外话,因为它正在谈论基于原型的对象模型和继承(那里的代码设置了一个从普通 Object 继承的 Obj 类)。这个问题不是关于创建某个自定义类的实例 - 它是关于创建 Object 的实例,这个问题的正确答案是“没有区别”。
  • 仅供参考,也不需要() new Object()。 (谈论不需要的东西)
  • 我认为我们不需要按照当前规范使用 new。让我知道你的想法@kevin
  • 如果您想要一个不从继承链继承的对象,您也可以使用 Object create 并传递 null。它们不相等,各有用途。
【解决方案3】:

在 JavaScript 中,我们可以通过两种方式声明一个新的空对象:

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

我没有发现任何迹象表明这两者在幕后操作方面存在任何显着差异(如果我错了,请纠正我——我很想知道)。然而,第二种方法(使用对象字面量表示法)提供了一些优势。

  1. 更短(准确地说是 10 个字符)
  2. 动态创建对象更简单、更有条理
  3. 如果某些小丑无意中覆盖了 Object 也没关系

考虑一个包含成员 Name 和 TelNo 的新对象。使用新的 Object() 约定,我们可以这样创建它:

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

JavaScript 的Expando Properties 特性允许我们以这种方式即时创建新成员,并且我们实现了预期。但是,这种方式不是非常结构化或封装的。如果我们想在创建时指定成员,而不必依赖 expando 属性和创建后的赋值呢?

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

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

这里我们用一行代码实现了同样的效果,而且字符明显减少了。

上面的对象构造方法的进一步讨论可以在:JavaScript and Object Oriented Programming (OOP).

最后,那个覆盖 Object 的白痴呢?你认为这是不可能的吗?好吧,this JSFiddle 证明并非如此。使用对象字面量表示法可以防止我们犯这种小丑。

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

【讨论】:

  • 如果你更喜欢对象字面量而不是 new Object() 因为有可能覆盖了 Object 函数,那么当你使用像 Object.keys 这样的帮助器时,你也应该在所有地方都写守卫以确保它不是未定义的,这会变得荒谬。我总是建议人们使用字面符号,但我认为当你想到这样思考的后果时,这个特定的论点就会崩溃。
  • SyntaxError: 意外标记 '='。属性名称“TelNo”后面应该有一个“:”。
【解决方案4】:

在我使用 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');

注意,这是对此处找到的内容的扩展:Why is arr = [] faster than arr = new Array?

我的输出如下:

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

很明显 {} 和 [] 比使用 new 创建空对象/数组要快。

【讨论】:

  • 我觉得这是这个问题真正要寻找的答案,尽管我希望看到这在一个具有一些属性的对象上进行了额外测试以确保。
  • 有趣的数字。有些人需要意识到这一点,但我认为即使分配 200,000 个对象也只会花费我 5.6 毫秒,所以我不会担心。
  • 在节点 10.13.0 上的东西已经改变了测试数组:使用 []:117.178 毫秒使用新:116.947 毫秒测试对象:使用{}:116.252 毫秒使用新:115.910 毫秒
【解决方案5】:

这里的每个人都在谈论两者的相似之处。我会指出不同之处。

  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
    

【讨论】:

  • 我对最后两行感到非常困惑.. 为什么如果你给 str.a 赋值 1,str.a 是未定义的?.. @Jermin Bazazin
  • @AndreaScarafoni 因为strstring 类型,所以您不能为其分配属性。 jsfiddle.net/grq6hdx7/1
  • 4的答案变了吗?在最新的 Chrome 53 var obj = new Object("foo"); typeof obj; obj === "foo" // true
【解决方案6】:

实际上,有几种方法可以在 JavaScript 中创建对象。当您只想创建一个对象时,使用“new”运算符创建“constructor-based”对象没有任何好处。这与使用“object literal”语法创建对象相同。但是,当您考虑“原型继承”时,使用“new”运算符创建的“constructor-based”对象会非常有用。您不能使用使用文字语法创建的对象来维护继承链。但是您可以创建一个构造函数,将属性和方法附加到它的原型。然后,如果您使用“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 构造函数的 prototype 附带的方法和属性(这是这种方法的主要优点)。

顺便说一句,如果您想使用“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();

最后,如果你现在问我为什么要使用 constructor function 方法而不是 object literal 方法:

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

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

我希望这是有道理的。

【讨论】:

  • 谢谢! Karl 在对象文字中添加了缺少的“this”。这是一个可怕的错误。我不应该犯这种错误。
  • "您不能从使用文字语法创建的对象继承。" - 不正确(我相信)。您可以使用Object.create(&lt;object defined using literal notation&gt;)new Object(&lt;object defined using literal notation&gt;) 并根据需要创建继承链。
  • @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
【解决方案7】:

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

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

【讨论】:

  • 等待是奥真的错字还是故意的双关语?他们应该用它来推销他们的书!
【解决方案8】:

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

【讨论】:

    【解决方案9】:

    对于 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: ilabel: statement 构造;分号是可选的,所以它不会抱怨它。

    如果你向对象添加另一个属性,它最终会抛出一个错误。

    $ 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 :
    

    【讨论】:

    • 你仍然可以使用箭头函数,你只需要更多的大括号和一个返回:[1, 2, 3].map(v =&gt; { return {n: v}; }); 会为你提供同样的东西......
    • 当然你可以使用常规的箭头函数,我说的是速记版本,即param =&gt; return_value,以及在这种情况下使用{}new Object()的区别。跨度>
    • 您仍然可以使用速记版本和常规箭头功能。只需将 {n: v} 用一对括号括起来:[1, 2, 3].map(v =&gt; ({n: v}));
    【解决方案10】:

    我唯一一次使用'new' keyowrd 进行对象初始化是在内联箭头函数中:

    () => new Object({ key: value})
    

    因为下面的代码无效:

    () => { key: value} //  instead of () => { return { key: value};}
    

    【讨论】:

    • 内联函数中,可以() =&gt; ({key: value})
    【解决方案11】:

    这里有很多很棒的答案,但我想带着我的 50 美分来。

    所有这些答案都缺少一个简单的类比,它适用于刚开始编程语言之旅的人。

    希望我会用这个类比填补这个空白:

    对象文字创建与基于构造函数的语法

    感受造句的不同。

    如果我有一句话"I like cheese",我可以清楚而响亮地告诉你(字面意思或逐字):我喜欢奶酪。

    这是我按字面意思(逐字)创建的句子。

    所有其他方式都是让您理解我准确创建的句子的一些棘手方式。比如我告诉你:

    1. 在我的句子中,主语是"I",宾语是"cheese",谓语是"to like"。 这是另一种让您毫不含糊地学习同一句话的方式:“我喜欢奶酪”。

    或者,

    1. 我的句子有3个单词:第一个是英语词典中的第n个单词,第二个是英语词典中的第m个单词,最后一个是英语中的第l个单词字典。

    在这种情况下,您也会得到相同的结果:您确切地知道句子是什么。

    您可以设计与“逐字”造句 (LITERAL) 不同的任何其他方法,也可以是 INDIRECT(非字面、非逐字)造句方法。

    我认为这是这里的核心概念。

    【讨论】:

      【解决方案12】:

      如果您创建 10,000 个实例,内存使用情况会有所不同。 new Object() 只会保留一份,而{} 会保留一万份。

      【讨论】:

      • new 创建一个新对象。它们都占用相同数量的内存。
      猜你喜欢
      • 2018-10-27
      • 2014-02-10
      • 2011-08-12
      • 1970-01-01
      • 2012-03-10
      • 1970-01-01
      • 2018-08-02
      相关资源
      最近更新 更多