这种用于创建对象的基于构造函数的语法有什么区别:
person = new Object()
...和这个字面语法:
person = {
property1 : "Hello"
};
看起来两者都做同样的事情,尽管 JSLint 更喜欢您使用对象文字表示法。
哪个更好,为什么?
这种用于创建对象的基于构造函数的语法有什么区别:
person = new Object()
...和这个字面语法:
person = {
property1 : "Hello"
};
看起来两者都做同样的事情,尽管 JSLint 更喜欢您使用对象文字表示法。
哪个更好,为什么?
没有您的示例中的方法的简单对象没有区别。但是,当您开始向对象添加方法时,会有很大的不同。
字面意思:
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()
,您实际上只是在输入更多内容,并且(理论上,如果没有被 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
而不是{}
(除非你做过那件非常不寻常的事情)。
在 JavaScript 中,我们可以通过两种方式声明一个新的空对象:
var obj1 = new Object();
var obj2 = {};
我没有发现任何迹象表明这两者在幕后操作方面有任何显着差异(如果我错了,请纠正我——我很想知道)。然而,第二种方法(使用对象字面量表示法)提供了一些优点。
考虑一个包含成员 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 和面向对象编程 (OOP)。
最后,那个超越 Object 的白痴呢?你以为不可能吗?好吧,这个 JSFiddle证明并非如此。使用对象字面量表示法可以防止我们犯这种小丑。
(来自http://www.jameswiseman.com/blog/2011/01/19/jslint-messages-use-the-object-literal-notation/)
在使用 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 创建空对象/数组要快。
这里的每个人都在谈论两者的相似之处。我要指出不同之处。
Usingnew Object()
允许你传递另一个对象。显而易见的结果是新创建的对象将被设置为相同的引用。这是一个示例代码:
var obj1 = new Object();
obj1.a = 1;
var obj2 = new Object(obj1);
obj2.a // 1
用法不限于对象,如 OOP 对象。其他类型也可以传递给它。该函数将相应地设置类型。例如,如果我们将整数 1 传递给它,则会为我们创建一个 number 类型的对象。
var obj = new Object(1);
typeof obj // "number"
如果向其添加属性,则使用上述方法 ( new Object(1)
) 创建的对象将转换为对象类型。
var obj = new Object(1);
typeof obj // "number"
obj.a = 2;
typeof obj // "object"
如果对象是对象子类的副本,我们可以在不进行类型转换的情况下添加属性。
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
实际上,有几种方法可以在 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();
最后,如果你现在问我为什么要使用构造函数方法而不是对象字面量方法:
*** 原型继承允许一个简单的继承链,它非常有用和强大。
*** 它通过继承构造函数原型中定义的常用方法和属性来节省内存。否则,您将不得不在所有对象中一遍又一遍地复制它们。
我希望这是有道理的。
另外,根据一些 O'Really javascript 书籍....(引用)
使用文字而不是 Object 构造函数的另一个原因是没有范围解析。因为您可能已经创建了同名的本地构造函数,所以解释器需要从您调用 Object() 的位置一直查找范围链,直到找到全局 Object 构造函数。
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
对于 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 :
我唯一一次使用'new' keyowrd 进行对象初始化是在内联箭头函数中:
() => new Object({ key: value})
因为以下代码无效:
() => { key: value} // instead of () => { return { key: value};}
这里有很多很好的答案,但我想带着我的 50 美分来。
所有这些答案都缺少一个简单的类比,它适用于刚开始编程语言之旅的人。
希望我能用这个类比填补这个空白:
感受造句的不同。
如果我有一句话"I like cheese"
,我可以清楚而响亮地告诉你(字面意思或逐字):我喜欢奶酪。
这是我字面(逐字)创建的句子。
所有其他方式都是让您理解我准确创建的句子的一些棘手方式。例如,我告诉你:
"I"
,宾语是"cheese"
,谓词是"to like"
。这是另一种让你毫不含糊地学习同一句话的方式:“我喜欢奶酪”。或者,
在这种情况下,您也会得到相同的结果:您确切地知道句子是什么。
您可以设计任何其他与“逐字”句子创建(LITERAL)不同的方法,这将是句子创建的间接(非文字,非逐字)方法。
我认为这是这里的核心概念。
如果创建 10,000 个实例,内存使用量会有所不同。
new Object()
将只保留一份,而{}
将保留一万份。