哪种方式最适合在 JavaScript 中创建对象?在对象属性之前是否需要 `var`?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6843951/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Which way is best for creating an object in JavaScript? Is `var` necessary before an object property?
提问by Jamna
So far I saw three ways for creating an object in JavaScript. Which way is best for creating an object and why?
到目前为止,我看到了在 JavaScript 中创建对象的三种方法。哪种方式最适合创建对象,为什么?
I also saw that in all of these examples the keyword var
is not used before a property?—?why? Is it not necessary to declare var
before the name of a property as it mentioned that properties are variables?
我还看到,在所有这些例子中,关键字var
没有在属性之前使用?—?为什么?是否不需要var
在属性名称之前声明,因为它提到属性是变量?
In the second and third way, the name of the object is in upper-case whereas in the first way the name of the object is in lower-case. What case should we use for an object name?
在第二种和第三种方式中,对象的名称是大写的,而在第一种方式中,对象的名称是小写的。我们应该为对象名称使用什么大小写?
First way:
第一种方式:
function person(fname, lname, age, eyecolor){
this.firstname = fname;
this.lastname = lname;
this.age = age;
this.eyecolor = eyecolor;
}
myFather = new person("John", "Doe", 50, "blue");
document.write(myFather.firstname + " is " + myFather.age + " years old.");
Second way:
第二种方式:
var Robot = {
metal: "Titanium",
killAllHumans: function(){
alert("Exterminate!");
}
};
Robot.killAllHumans();
Third way?—?JavaScript objects using array syntax:
第三种方式?—?JavaScript 对象使用数组语法:
var NewObject = {};
NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }
回答by Felix Kling
There is no bestway, it depends on your use case.
没有最好的方法,这取决于您的用例。
- Use way 1if you want to create several similar objects. In your example,
Person
(you should start the name with a capital letter) is called the constructor function. This is similar to classesin other OO languages. - Use way 2if you only need one objectof a kind (like a singleton). If you want this object to inherit from another one, then you have to use a constructor function though.
- Use way 3if you want to initialize properties of the object depending on other properties of it or if you have dynamic property names.
- 如果要创建多个相似的对象,请使用方式 1。在您的示例中,
Person
(您应该以大写字母开头名称)称为构造函数。这类似于其他 OO 语言中的类。 - 如果您只需要一种对象(如单例),请使用方式 2。如果您希望这个对象从另一个对象继承,那么您必须使用构造函数。
- 如果要根据对象的其他属性初始化对象的属性,或者如果您有动态属性名称,请使用方式 3。
Update:As requested examples for the third way.
更新:作为第三种方式的请求示例。
Dependent properties:
依赖属性:
The following does not work as this
does notrefer to book
. There is no way to initialize a property with values of other properties in a object literal:
下列情况不上班this
也没有参考book
。无法使用对象字面量中的其他属性的值来初始化属性:
var book = {
price: somePrice * discount,
pages: 500,
pricePerPage: this.price / this.pages
};
instead, you could do:
相反,你可以这样做:
var book = {
price: somePrice * discount,
pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;
Dynamic property names:
动态属性名称:
If the property name is stored in some variable or created through some expression, then you have to use bracket notation:
如果属性名称存储在某个变量中或通过某个表达式创建,则必须使用括号表示法:
var name = 'propertyName';
// the property will be `name`, not `propertyName`
var obj = {
name: 42
};
// same here
obj.name = 42;
// this works, it will set `propertyName`
obj[name] = 42;
回答by Anand Deep Singh
There is various way to define a function. It is totally based upon your requirement. Below are the few styles :-
有多种定义函数的方法。它完全基于您的要求。以下是几种款式:-
- Object Constructor
- Literal constructor
- Function Based
- Protoype Based
- Function and Prototype Based
- Singleton Based
- 对象构造函数
- 字面构造函数
- 基于功能
- 基于原型
- 基于功能和原型
- 基于单例
Examples:
例子:
- Object constructor
- 对象构造器
var person = new Object();
person.name = "Anand",
person.getName = function(){
return this.name ;
};
- Literal constructor
- 字面构造函数
var person = {
name : "Anand",
getName : function (){
return this.name
}
}
- function Constructor
- 函数构造器
function Person(name){
this.name = name
this.getName = function(){
return this.name
}
}
- Prototype
- 原型
function Person(){};
Person.prototype.name = "Anand";
- Function/Prototype combination
- 功能/原型组合
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
return this.name
}
- Singleton
- 单身人士
var person = new function(){
this.name = "Anand"
}
You can try it on console, if you have any confusion.
如果您有任何困惑,可以在控制台上尝试。
回答by jimbo
There is no "best way" to create an object. Each way has benefits depending on your use case.
没有创建对象的“最佳方法”。每种方式都有好处,具体取决于您的用例。
The constructor pattern (a function paired with the new
operator to invoke it) provides the possibility of using prototypal inheritance, whereas the other ways don't. So if you want prototypal inheritance, then a constructor function is a fine way to go.
构造器模式(一个与new
操作符配对来调用它的函数)提供了使用原型继承的可能性,而其他方式则没有。所以如果你想要原型继承,那么构造函数是一个很好的方法。
However, if you want prototypal inheritance, you may as well use Object.create
, which makes the inheritance more obvious.
但是,如果你想要原型继承,你也可以使用Object.create
,这使得继承更加明显。
Creating an object literal (ex: var obj = {foo: "bar"};
) works great if you happen to have all the properties you wish to set on hand at creation time.
var obj = {foo: "bar"};
如果您碰巧拥有希望在创建时设置的所有属性,则创建对象字面量(例如:)效果很好。
For setting properties later, the NewObject.property1
syntax is generally preferable to NewObject['property1']
if you know the property name. But the latter is useful when you don't actually have the property's name ahead of time (ex: NewObject[someStringVar]
).
对于稍后设置属性,如果您知道属性名称,则NewObject.property1
语法通常更可取NewObject['property1']
。但是当您实际上没有提前知道属性的名称时,后者很有用(例如:)NewObject[someStringVar]
。
Hope this helps!
希望这可以帮助!
回答by Daan Wilmer
I guess it depends on what you want. For simple objects, I guess you could use the second methods. When your objects grow larger and you're planning on using similar objects, I guess the first method would be better. That way you can also extend it using prototypes.
我想这取决于你想要什么。对于简单的对象,我想您可以使用第二种方法。当您的对象变大并且您计划使用类似的对象时,我想第一种方法会更好。这样你也可以使用原型扩展它。
Example:
例子:
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getCircumference = function() {
return Math.PI * 2 * this.radius;
};
Circle.prototype.getArea = function() {
return Math.PI * this.radius * this.radius;
}
I am not a big fan of the third method, but it's really useful for dynamically editing properties, for example var foo='bar'; var bar = someObject[foo];
.
我不是第三种方法的忠实粉丝,但它对于动态编辑属性非常有用,例如var foo='bar'; var bar = someObject[foo];
.
回答by Alireza
There are a many ways to create your objects in JavaScript. Using a constructer function to create an object or object literal notation is using alot in JavaScript. Also creating an instance of Object and then adding properties and methods to it, there are three common ways to do create objects in JavaScript.
有很多方法可以在 JavaScript 中创建对象。使用构造函数来创建对象或对象文字符号在 JavaScript 中使用很多。同样创建一个 Object 的实例,然后向它添加属性和方法,在 JavaScript 中有三种常见的方法来创建对象。
Constructer functions
构造函数
There are built-in constructer functions that we all may use them time to time, like Date(), Number(), Boolean() etc, all constructer functions start with Capital letter, in the meantime we can create custom constructor function in JavaScript like this:
内置的构造函数我们都可以不时使用,比如Date()、Number()、Boolean()等,所有构造函数都以大写字母开头,同时我们可以在JavaScript中创建自定义构造函数像这样:
function Box (Width, Height, fill) {
this.width = Width; // The width of the box
this.height = Height; // The height of the box
this.fill = true; // Is it filled or not?
}
and you can invoke it, simply using new(), to create a new instance of the constructor, create something like below and call the constructor function with filled parameters:
您可以调用它,只需使用 new() 来创建构造函数的新实例,创建如下所示的内容并使用填充参数调用构造函数:
var newBox = new Box(8, 12, true);
Object literals
对象字面量
Using object literals are very used case creating object in JavaScript, this an example of creating a simple object, you can assign anything to your object properties as long as they are defined:
使用对象字面量是在 JavaScript 中创建对象的非常常用的案例,这是创建一个简单对象的示例,您可以将任何内容分配给您的对象属性,只要它们被定义:
var person = {
name: "Alireza",
surname: "Dezfoolian"
nose: 1,
feet: 2,
hands: 2,
cash: null
};
Prototyping
原型制作
After creating an Object, you can prototype more members to that, for example adding colour to our Box, we can do this:
创建对象后,您可以为其创建更多成员的原型,例如为我们的 Box 添加颜色,我们可以这样做:
Box.prototype.colour = 'red';
回答by Donato
While many people here say there is no best way for object creation, there is a rationale as to why there are so many ways to create objects in JavaScript, as of 2019, and this has to do with the progress of JavaScript over the different iterations of EcmaScript releases dating back to 1997.
虽然这里的许多人说没有最好的对象创建方法,但截至 2019 年,为什么在 JavaScript 中有这么多创建对象的方法是有道理的,这与 JavaScript 在不同迭代中的进展有关可追溯到 1997 年的 EcmaScript 版本。
Prior to ECMAScript 5, there were only two ways of creating objects: the constructor function or the literal notation ( a better alternative to new Object()). With the constructor function notation you create an object that can be instantiated into multiple instances (with the new keyword), while the literal notation delivers a single object, like a singleton.
在 ECMAScript 5 之前,只有两种创建对象的方法:构造函数或文字符号(new Object() 的更好替代方法)。使用构造函数表示法创建一个可以实例化为多个实例的对象(使用 new 关键字),而文字表示法提供单个对象,如单例。
// constructor function
function Person() {};
// literal notation
var Person = {};
Regardless of the method you use, JavaScript objects are simply properties of key value pairs:
无论您使用哪种方法,JavaScript 对象都只是键值对的属性:
// Method 1: dot notation
obj.firstName = 'Bob';
// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';
// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
value: 'Bob',
writable: true,
configurable: true,
enumerable: false
})
// Method 4: Object.defineProperties
Object.defineProperties(obj, {
firstName: {
value: 'Bob',
writable: true
},
lastName: {
value: 'Smith',
writable: false
}
});
In early versions of JavaScript, the only real way to mimic class-based inheritance was to use constructor functions. the constructor function is a special function that is invoked with the 'new' keyword. By convention, the function identifier is capitalized, albiet it is not required. Inside of the constructor, we refer to the 'this' keyword to add properties to the object that the constructor function is implicitly creating. The constructor function implicitly returns the new object with the populated properties back to the calling function implicitly, unless you explicitly use the return keyword and return something else.
在 JavaScript 的早期版本中,模仿基于类的继承的唯一真正方法是使用构造函数。构造函数是一个特殊的函数,使用“new”关键字调用。按照惯例,函数标识符是大写的,尽管它不是必需的。在构造函数内部,我们引用“this”关键字来向构造函数隐式创建的对象添加属性。构造函数将带有填充属性的新对象隐式返回给调用函数,除非您显式使用 return 关键字并返回其他内容。
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.sayName = function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var bob = new Person("Bob", "Smith");
bob instanceOf Person // true
There is a problem with the sayName method. Typically, in Object-Oriented Class-based programming languages, you use classes as factories to create objects. Each object will have its own instance variables, but it will have a pointer to the methods defined in the class blueprint. Unfortunately, when using JavaScript's constructor function, every time it is called, it will define a new sayName property on the newly created object. So each object will have its own unique sayName property. This will consume more memory resources.
sayName 方法有问题。通常,在面向对象的基于类的编程语言中,您使用类作为工厂来创建对象。每个对象都有自己的实例变量,但它有一个指向类蓝图中定义的方法的指针。不幸的是,在使用 JavaScript 的构造函数时,每次调用它时,都会在新创建的对象上定义一个新的 sayName 属性。所以每个对象都有自己唯一的 sayName 属性。这会消耗更多的内存资源。
In addition to increased memory resources, defining methods inside of the constructor function eliminates the possibility of inheritance. Again, the method will be defined as a property on the newly created object and no other object, so inheritance cannot work like. Hence, JavaScript provides the prototype chain as a form of inheritance, making JavaScript a prototypal language.
除了增加内存资源外,在构造函数内部定义方法消除了继承的可能性。同样,该方法将被定义为新创建的对象的属性,而不是其他对象,因此继承不能像这样工作。因此,JavaScript 提供原型链作为一种继承形式,使 JavaScript 成为一种原型语言。
If you have a parent and a parent shares many properties of a child, then the child should inherit those properties. Prior to ES5, it was accomplished as follows:
如果您有一个父级并且一个父级共享子级的许多属性,那么子级应该继承这些属性。在 ES5 之前,它是这样完成的:
function Parent(eyeColor, hairColor) {
this.eyeColor = eyeColor;
this.hairColor = hairColor;
}
Parent.prototype.getEyeColor = function() {
console.log('has ' + this.eyeColor);
}
Parent.prototype.getHairColor = function() {
console.log('has ' + this.hairColor);
}
function Child(firstName, lastName) {
Parent.call(this, arguments[2], arguments[3]);
this.firstName = firstName;
this.lastName = lastName;
}
Child.prototype = Parent.prototype;
var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair
The way we utilized the prototype chain above has a quirk. Since the prototype is a live link, by changing the property of one object in the prototype chain, you'd be changing same property of another object as well. Obviously, changing a child's inherited method should not change the parent's method. Object.create resolved this issue by using a polyfill. Thus, with Object.create, you can safely modify a child's property in the prototype chain without affecting the parent's same property in the prototype chain.
我们利用上述原型链的方式有一个怪癖。由于原型是一个实时链接,通过更改原型链中一个对象的属性,您也会更改另一个对象的相同属性。显然,改变子代继承的方法不应该改变父代的方法。Object.create 通过使用 polyfill 解决了这个问题。因此,使用 Object.create,您可以安全地修改原型链中子级的属性,而不会影响原型链中父级的相同属性。
ECMAScript 5 introduced Object.create to solve the aforementioned bug in the constructor function for object creation. The Object.create() method CREATES a new object, using an existing object as the prototype of the newly created object. Since a new object is created, you no longer have the issue where modifying the child property in the prototype chain will modify the parent's reference to that property in the chain.
ECMAScript 5 引入了 Object.create 来解决上述用于创建对象的构造函数中的错误。Object.create() 方法创建一个新对象,使用现有对象作为新创建对象的原型。由于创建了一个新对象,您不再遇到修改原型链中的子属性将修改父级对该链中该属性的引用的问题。
var bobSmith = {
firstName: "Bob",
lastName: "Smith",
sayName: function(){
return "My name is " + this.firstName + " " + this.lastName;
}
}
var janeSmith = Object.create(bobSmith, {
firstName : { value: "Jane" }
})
console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.
Prior to ES6, here was a common creational pattern to utilize function constructors and Object.create:
在 ES6 之前,这里是使用函数构造函数和 Object.create 的常见创建模式:
const View = function(element){
this.element = element;
}
View.prototype = {
getElement: function(){
this.element
}
}
const SubView = function(element){
View.call(this, element);
}
SubView.prototype = Object.create(View.prototype);
Now Object.create coupled with constructor functions have been widely used for object creation and inheritance in JavaScript. However, ES6 introduced the concept of classes, which are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript. Thus, JavaScript remains a prototypal language.
现在 Object.create 结合构造函数已经被广泛用于 JavaScript 中的对象创建和继承。然而,ES6 引入了类的概念,它主要是 JavaScript 现有的基于原型的继承的语法糖。类语法没有向 JavaScript 引入新的面向对象的继承模型。因此,JavaScript 仍然是一种原型语言。
ES6 classes make inheritance much easier. We no longer have to manually copy the parent class's prototype functions and reset the child class's constructor.
ES6 类使继承更容易。我们不再需要手动复制父类的原型函数并重置子类的构造函数。
// create parent class
class Person {
constructor (name) {
this.name = name;
}
}
// create child class and extend our parent class
class Boy extends Person {
constructor (name, color) {
// invoke our parent constructor function passing in any required parameters
super(name);
this.favoriteColor = color;
}
}
const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue
All in all, these 5 different strategies of Object Creation in JavaScript coincided the evolution of the EcmaScript standard.
总而言之,这 5 种不同的 JavaScript 对象创建策略恰逢 EcmaScript 标准的演变。
回答by roli roli
Of course there is a best way.Objects in javascript have enumerable and nonenumerable properties.
当然有一个最好的方法。javascript中的对象具有可枚举和不可枚举的属性。
var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]
In the example above you can see that an empty object actually has properties.
在上面的示例中,您可以看到一个空对象实际上具有属性。
Ok first let's see which is the best way:
好的,首先让我们看看哪个是最好的方法:
var new_object = Object.create(null)
new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc
console.log("toString" in new_object) //=> false
In the example above the log will output false.
在上面的示例中,日志将输出 false。
Now let's see why the other object creation ways are incorrect.
现在让我们看看为什么其他对象创建方式不正确。
//Object constructor
var object = new Object();
console.log("toString" in object); //=> true
//Literal constructor
var person = {
name : "Anand",
getName : function (){
return this.name
}
}
console.log("toString" in person); //=> true
//function Constructor
function Person(name){
this.name = name
this.getName = function(){
return this.name
}
}
var person = new Person ('landi')
console.log("toString" in person); //=> true
//Prototype
function Person(){};
Person.prototype.name = "Anand";
console.log("toString" in person); //=> true
//Function/Prototype combination
function Person2(name){
this.name = name;
}
Person2.prototype.getName = function(){
return this.name
}
var person2 = new Person2('Roland')
console.log("toString" in person2) //=> true
As you can see above,all examples log true.Which means if you have a case that you have a for in
loop to see if the object has a property will lead you to wrong results probably.
正如您在上面看到的,所有示例都记录为 true。这意味着如果您有一个for in
循环来查看对象是否具有属性,则可能会导致您得到错误的结果。
Note that the best way it is not easy.You have to define all properties of object line by line.The other ways are more easier and will have less code to create an object but you have to be aware in some cases. I always use the "other ways" by the way and one solution to above warning if you don't use the best way is:
请注意,最好的方法并不容易。您必须逐行定义对象的所有属性。其他方法更容易,并且创建对象的代码更少,但在某些情况下您必须注意。顺便说一句,我总是使用“其他方式”,如果您不使用最佳方式,则上述警告的一种解决方案是:
for (var property in new_object) {
if (new_object.hasOwnProperty(property)) {
// ... this is an own property
}
}
回答by shivam bansal
Majorly there are 3 ways of creating Objects-
主要有 3 种创建对象的方法-
Simplest one is using object literals.
最简单的一种是使用对象字面量。
const myObject = {}
Though this method is the simplest but has a disadvantage i.e if your object has behaviour(functions in it),then in future if you want to make any changes to it you would have to change it in all the objects.
虽然这种方法最简单但有一个缺点,即如果您的对象具有行为(其中包含函数),那么将来如果您想对其进行任何更改,则必须在所有对象中更改它。
So in that case it is better to use Factory or Constructor Functions.(anyone that you like)
所以在这种情况下,最好使用工厂或构造函数。(任何你喜欢的人)
Factory Functionsare those functions that return an object.e.g-
工厂函数是那些返回对象的函数。例如-
function factoryFunc(exampleValue){
return{
exampleProperty: exampleValue
}
}
Constructor Functionsare those functions that assign properties to objects using "this" keyword.e.g-
构造函数是那些使用“this”关键字为对象分配属性的函数。例如-
function constructorFunc(exampleValue){
this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);