哪种方法最适合在JavaScript中创建对象?对象属性之前是否必须使用“ var”?


177

到目前为止,我看到了用JavaScript创建对象的三种方法。哪种方法最适合创建对象,为什么?

我还看到在所有这些示例中,var在属性之前未使用关键字-为什么?var提到属性是变量时,是否不必在属性名称之前声明?

在第二和第三种方式中,对象的名称为大写,而在第一种方式中,对象的名称为小写。我们应该在什么情况下使用对象名称?

第一种方式:

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.");

第二种方式:

var Robot = {
  metal: "Titanium",
  killAllHumans: function(){
    alert("Exterminate!");
  }
};

Robot.killAllHumans();

第三种方法-使用数组语法的JavaScript对象:

var NewObject = {};

NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }

2
根据变量的范围使用“ var”,它定义或不定义全局变量,搜索它,您将看到区别。
jackJoe 2011年

80
如果您创建杀人机器人,var请始终使用..省略它使它们成为全球性的
mykhal

9
“根据变量的范围使用var” –这是BAD的做法–无论您处于什么范围都应使用
treecoder

1
那方法Object.create()呢?
2014年

如果“如前所述,属性是变量”得到澄清,那就太好了。是谁呀”?在哪里提到?你能引用一个具体的报价吗?
user4642212

Answers:


181

没有最好的方法,这取决于您的用例。

  • 如果要创建多个相似的对象,请使用方法1。在您的示例中,Person(您应使用大写字母开头名称)称为构造函数。这类似于其他OO语言中的
  • 如果只需要一种对象(如单例),请使用方法2。如果要使该对象从另一个对象继承,则必须使用构造函数。
  • 如果要根据对象的其他属性初始化对象的属性,或者具有动态属性名称,请使用方法3

更新:如第三种方式要求的示例。

相关属性:

下列情况不为工作,this没有book。无法使用对象文字中的其他属性的值来初始化属性:

var book = {
    price: somePrice * discount,
    pages: 500,
    pricePerPage: this.price / this.pages
};

相反,您可以执行以下操作:

var book = {
    price: somePrice * discount,
    pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;

动态属性名称:

如果属性名称存储在某个变量中或通过某个表达式创建,则必须使用方括号表示法:

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;

1
谢谢您的回答...现在我明白您的第一点了,如果我们想要这样的东西,我们可以使用way1 = myFather = new person(“ John”,“ Doe”,50,“ blue”); myMother = new person(“ gazy”,“ Doe”,45,“ brown”); myBrother =新人(“投票”,“母鹿”,15,“蓝色”);
Jamna

我认为您的意思是obj [name] = 42。
基思·品森

我想指出的是,选项2和3实际上是相同的,只是在创建对象之后分配属性。这就是文字表示法,因为您正在使用对象文字来创建对象。实际上,这实际上称为“ new Object()”。您可以在此处了解更多信息:developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…–
dudewad

对于第二种情况,如果我们使用传播运算符...从另一个对象继承,是否有意义?
6pack小子

114

有多种定义函数的方法。这完全取决于您的要求。以下是几种样式:-

  1. 对象构造器
  2. 文字构造函数
  3. 基于功能
  4. 基于原型
  5. 基于功能和原型
  6. 基于单例

例子:

  1. 对象构造函数
var person = new Object();

person.name = "Anand",
person.getName = function(){
  return this.name ; 
};
  1. 文字构造函数
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 
  1. 函数构造器
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
} 
  1. 原型
function Person(){};

Person.prototype.name = "Anand";
  1. 功能/原型组合
function Person(name){
  this.name = name;
} 
Person.prototype.getName = function(){
  return this.name
} 
  1. 辛格尔顿
var person = new function(){
  this.name = "Anand"
} 

如果您有任何困惑,可以在控制台上尝试。


嗨@Alex_Nabu-我已经分享了我的帖子中的示例。如果您仍然遇到任何挑战,请随时告诉我,我会为您提供帮助。
Anand Deep Singh

1
构建每个var person最终产生完全相同的实例的示例更有意义吗?例如在函数构造函数中,您可以简单地添加var person = new Person("Anand")。看似随机的分号用法又是怎么回事?:P
cregox

2
这将增加解释每种方式的利弊的价值。
RayLoveless

10

没有“最佳方法”来创建对象。每种方式都有其优势,具体取决于您的用例。

构造函数模式(与 new运算符来调用它)提供了使用原型继承的可能性,而其他方式则没有。因此,如果您想原型继承,那么构造函数是一个不错的选择。

但是,如果您想要原型继承,则最好使用Object.create,这会使继承更加明显。

var obj = {foo: "bar"};如果您恰好在创建时希望拥有所有要设置的属性,则创建对象文字(例如:)非常有用。

对于以后设置属性,NewObject.property1通常最好使用语法(NewObject['property1']如果您知道属性名称)。但是,如果您实际上没有提前获得属性的名称,则后者很有用(例如:)NewObject[someStringVar]

希望这可以帮助!


6

我想这取决于你想要什么。对于简单的对象,我想您可以使用第二种方法。当您的对象变大并且您打算使用类似的对象时,我猜第一种方法会更好。这样,您还可以使用原型对其进行扩展。

例:

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;
}

我不是第三种方法的忠实拥护者,但是对于动态编辑属性确实非常有用,例如var foo='bar'; var bar = someObject[foo];


3

有很多方法可以用JavaScript创建对象。在JavaScript中大量使用构造函数创建对象或对象文字符号。此外,还创建Object的实例,然后向其添加属性和方法,有三种常见的方法可以在JavaScript中创建对象。

构造函数

有内置的构造函数,我们所有人都可能会不时使用它们,例如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?
}  

您可以简单地使用new()调用它,以创建构造函数的新实例,创建如下所示的内容,并使用填充的参数调用构造函数:

var newBox = new Box(8, 12, true);  

对象文字

使用对象文字是在JavaScript中创建对象的非常常用的情况,这是创建简单对象的示例,只要定义了对象,就可以为对象属性分配任何内容:

var person = { 
    name: "Alireza",
    surname: "Dezfoolian"
    nose: 1,  
    feet: 2,  
    hands: 2,
    cash: null
};  

原型制作

创建对象之后,您可以为该对象创建更多原型,例如,为Box添加颜色,我们可以这样做:

Box.prototype.colour = 'red';

2

尽管这里很多人说没有最好的对象创建方法,但是有一个合理的理由说明为什么到2019年为止,有这么多方法可以用JavaScript创建对象,这与JavaScript在不同迭代中的进展有关的EcmaScript版本可追溯到1997年。

在ECMAScript 5之前,只有两种创建对象的方式:构造函数或文字表示法(是new Object()的更好替代方法)。使用构造函数符号,您可以创建一个可以实例化为多个实例(使用new关键字)的对象,而文字符号可以提供单个对象(如单例)。

// constructor function
function Person() {};

// literal notation
var Person = {};

无论使用哪种方法,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
  }
});

在早期版本的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

sayName方法存在问题。通常,在基于对象的基于类的编程语言中,您将类用作工厂来创建对象。每个对象将具有其自己的实例变量,但是将具有指向类蓝图中定义的方法的指针。不幸的是,当使用JavaScript的构造函数时,每次调用它时,都会在新创建的对象上定义一个新的sayName属性。因此,每个对象将具有其自己唯一的sayName属性。这将消耗更多的内存资源。

除了增加内存资源外,在构造函数内部定义方法还消除了继承的可能性。同样,该方法将被定义为新创建的对象的属性,而没有其他对象,因此继承无法像继承一样工作。因此,JavaScript提供原型链作为一种继承形式,使JavaScript成为原型语言。

如果您有一个父母,而父母共享一个孩子的许多属性,则该孩子应该继承这些属性。在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

我们利用上述原型链的方式有一个怪癖。由于原型是实时链接,因此通过更改原型链中一个对象的属性,您也将更改另一个对象的相同属性。显然,更改子级的继承方法不应更改父级的方法。Object.create通过使用polyfill解决了此问题。因此,使用Object.create,可以安全地修改原型链中子级的属性,而不会影响原型链中父级的相同属性。

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.

在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);

现在,Object.create与构造函数结合使用,已广泛用于JavaScript中的对象创建和继承。但是,ES6引入了类的概念,这些类主要是对JavaScript现有的基于原型的继承的语法糖。类语法不会向JavaScript引入新的面向对象的继承模型。因此,JavaScript仍然是原型语言。

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

总而言之,这5种不同的JavaScript对象创建策略与EcmaScript标准的发展相吻合。


0

当然有最好的方法.javascript中的对象具有可枚举和不可枚举的属性。

var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]

在上面的示例中,您可以看到一个空对象实际上具有属性。

好的,首先让我们看看哪种方法是最好的:

var new_object = Object.create(null)

new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc

console.log("toString" in new_object) //=> false

在上面的示例中,日志将输出false。

现在让我们看看为什么其他对象创建方式不正确。

//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

如上所示,所有示例均记录为true。这意味着如果您有一个for in循环来查看对象是否具有属性,可能会导致错误的结果。

请注意,最好的方法并不容易,您必须逐行定义对象的所有属性,其他方法则更容易且创建对象的代码更少,但是您必须在某些情况下意识到这一点。我总是使用“其他方式”,如果您未使用最佳方式,则上述警告的一种解决方案是:

 for (var property in new_object) {
  if (new_object.hasOwnProperty(property)) {
    // ... this is an own property
  }
 }

0

主要有3种创建对象的方式-

最简单的一种是使用对象文字

const myObject = {}

尽管此方法最简单,但有一个缺点,即如果对象具有行为(其中具有功能),那么将来如果要对其进行任何更改,则必须在所有对象中进行更改

因此,在这种情况下,最好使用Factory或Constructor函数。(您喜欢的任何人)

工厂函数是那些返回对象的函数。例如-

function factoryFunc(exampleValue){
   return{
      exampleProperty: exampleValue 
   }
}

构造函数是使用“ this”关键字将属性分配给对象的函数。例如,

function constructorFunc(exampleValue){
   this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);
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.