Cách nào là tốt nhất để tạo một đối tượng trong JavaScript? Là `var` cần thiết trước một thuộc tính đối tượng?


177

Cho đến nay tôi đã thấy ba cách để tạo một đối tượng trong JavaScript. Cách nào là tốt nhất để tạo một đối tượng và tại sao?

Tôi cũng thấy rằng trong tất cả các ví dụ này, từ khóa varkhông được sử dụng trước một thuộc tính - tại sao? Có cần thiết phải khai báo vartrước tên của một thuộc tính như đã đề cập rằng các thuộc tính là các biến không?

Theo cách thứ hai và thứ ba, tên của đối tượng nằm trong chữ in hoa trong khi ở cách thứ nhất, tên của đối tượng ở dạng chữ thường. Trường hợp nào chúng ta nên sử dụng cho một tên đối tượng?

Cách thứ nhất:

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

Cách thứ hai:

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

Robot.killAllHumans();

Cách thứ ba - Các đối tượng JavaScript sử dụng cú pháp mảng:

var NewObject = {};

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

2
"var" được sử dụng tùy thuộc vào phạm vi của biến, nó xác định toàn cục hay không, tìm kiếm nó và bạn sẽ thấy sự khác biệt.
jackJoe

80
nếu bạn tạo robot giết người, luôn luôn sử dụng var, vui lòng .. bỏ qua nó sẽ khiến chúng trở nên toàn cầu
mykhal

9
"var được sử dụng tùy thuộc vào phạm vi của biến" - đây là cách thực hành BAD - nên sử dụng bất kể bạn đang ở phạm vi nào
giải mã tre

1
Thế còn phương pháp : Object.create()?
Tối đa

Sẽ thật tuyệt nếu như Viking đã đề cập rằng các thuộc tính là các biến đã được làm rõ. Đó là ai"? Nó được đề cập ở đâu? Bạn có thể trích dẫn một trích dẫn cụ thể?
dùng4642212

Câu trả lời:


181

Không có cách tốt nhất , nó phụ thuộc vào trường hợp sử dụng của bạn.

  • Sử dụng cách 1 nếu bạn muốn tạo một số đối tượng tương tự. Trong ví dụ của bạn, Person(bạn nên bắt đầu tên bằng chữ in hoa) được gọi là hàm tạo . Điều này tương tự như các lớp trong các ngôn ngữ OO khác.
  • Sử dụng cách 2 nếu bạn chỉ cần một đối tượng thuộc loại (như singleton). Nếu bạn muốn đối tượng này kế thừa từ một đối tượng khác, thì bạn phải sử dụng hàm xây dựng.
  • Sử dụng cách 3 nếu bạn muốn khởi tạo các thuộc tính của đối tượng tùy thuộc vào các thuộc tính khác của nó hoặc nếu bạn có tên thuộc tính động.

Cập nhật: Như các ví dụ được yêu cầu cho cách thứ ba.

Thuộc tính phụ thuộc:

Sau đây không hoạt động như thisnào không đề cập đến book. Không có cách nào để khởi tạo một thuộc tính với các giá trị của các thuộc tính khác trong một đối tượng bằng chữ:

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

thay vào đó, bạn có thể làm:

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

Tên thuộc tính động:

Nếu tên thuộc tính được lưu trữ trong một số biến hoặc được tạo thông qua một số biểu thức, thì bạn phải sử dụng ký hiệu ngoặc:

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
cảm ơn câu trả lời của bạn ... bây giờ tôi đã hiểu điểm đầu tiên của bạn, chúng tôi có thể sử dụng way1 nếu chúng tôi muốn một cái gì đó như myFather = new person ("John", "Doe", 50, "blue"); myMother = người mới ("gazy", "Doe", 45, "nâu"); myBrother = người mới ("thăm dò ý kiến", "Doe", 15, "màu xanh");
Jamna

Tôi nghĩ bạn có nghĩa là obj [name] = 42. Phải không?
Keith Pinson

Tôi muốn chỉ ra rằng các tùy chọn 2 và 3 gần như giống hệt nhau, chỉ là bạn đang gán các thuộc tính sau khi bạn tạo đối tượng. Đây là những gì được gọi là ký hiệu theo nghĩa đen , bởi vì bạn đang sử dụng một đối tượng theo nghĩa đen để tạo đối tượng của bạn. Dưới mui xe, cái này thực sự gọi là "Object mới ()". Bạn có thể đọc thêm về nó ở đây: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/
Kẻ

Đối với trường hợp thứ hai, sẽ có ý nghĩa nếu chúng ta sử dụng toán tử trải rộng ...để kế thừa từ một đối tượng khác?
6pack bé 27/11/18

114

Có nhiều cách khác nhau để định nghĩa một chức năng. Nó hoàn toàn dựa trên yêu cầu của bạn. Dưới đây là một vài phong cách: -

  1. Đối tượng xây dựng
  2. Nhà xây dựng văn học
  3. Dựa trên chức năng
  4. Dựa trên protoype
  5. Dựa trên chức năng và nguyên mẫu
  6. Dựa trên đơn

Ví dụ:

  1. Đối tượng xây dựng
var person = new Object();

person.name = "Anand",
person.getName = function(){
  return this.name ; 
};
  1. Nhà xây dựng văn học
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 
  1. Hàm xây dựng
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
} 
  1. Nguyên mẫu
function Person(){};

Person.prototype.name = "Anand";
  1. Kết hợp chức năng / nguyên mẫu
function Person(name){
  this.name = name;
} 
Person.prototype.getName = function(){
  return this.name
} 
  1. Người độc thân
var person = new function(){
  this.name = "Anand"
} 

Bạn có thể thử nó trên bàn điều khiển, nếu bạn có bất kỳ sự nhầm lẫn nào.


HEy @Alex_Nabu - Tôi đã chia sẻ các ví dụ trong bài viết của mình. Nếu bạn vẫn gặp phải bất kỳ thử thách nào, hãy cập nhật cho tôi. Tôi sẽ giúp bạn.
Anand Deep Singh

1
sẽ không có ý nghĩa hơn để xây dựng mọi ví dụ mang lại cùng một var personví dụ chính xác ? ví dụ trong hàm tạo, bạn có thể chỉ cần thêm var person = new Person("Anand"). và những gì đang xảy ra với việc sử dụng nửa dấu hai chấm dường như ngẫu nhiên? : P
cregox

2
Nó sẽ thêm giá trị giải thích ưu và nhược điểm của từng cách.
RayLovless

10

Không có "cách tốt nhất" để tạo một đối tượng. Mỗi cách có lợi ích tùy thuộc vào trường hợp sử dụng của bạn.

Mẫu constructor (một hàm được ghép nối với newtoán tử để gọi nó) cung cấp khả năng sử dụng kế thừa nguyên mẫu, trong khi các cách khác thì không. Vì vậy, nếu bạn muốn thừa kế nguyên mẫu, thì một hàm xây dựng là một cách tốt để đi.

Tuy nhiên, nếu bạn muốn thừa kế nguyên mẫu, bạn cũng có thể sử dụng Object.create, điều này làm cho sự kế thừa rõ ràng hơn.

Tạo một đối tượng theo nghĩa đen (ví dụ var obj = {foo: "bar"};:) hoạt động tuyệt vời nếu bạn tình cờ có tất cả các thuộc tính bạn muốn đặt trên tay tại thời điểm tạo.

Để thiết lập các thuộc tính sau này, NewObject.property1cú pháp thường được ưu tiên hơn NewObject['property1']nếu bạn biết tên thuộc tính. Nhưng cái sau hữu ích khi bạn không thực sự có tên của tài sản trước thời hạn (ví dụ NewObject[someStringVar]:).

Hi vọng điêu nay co ich!


6

Tôi đoán nó phụ thuộc vào những gì bạn muốn. Đối với các đối tượng đơn giản, tôi đoán bạn có thể sử dụng các phương thức thứ hai. Khi các đối tượng của bạn phát triển lớn hơn và bạn đang dự định sử dụng các đối tượng tương tự, tôi đoán phương pháp đầu tiên sẽ tốt hơn. Bằng cách đó bạn cũng có thể mở rộng nó bằng cách sử dụng các nguyên mẫu.

Thí dụ:

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

Tôi không phải là một fan hâm mộ lớn của phương pháp thứ ba, nhưng nó thực sự hữu ích cho việc chỉnh sửa động các thuộc tính var foo='bar'; var bar = someObject[foo];.


3

Có nhiều cách để tạo các đối tượng của bạn trong JavaScript. Sử dụng hàm xây dựng để tạo một đối tượng hoặc ký hiệu bằng chữ của đối tượng là sử dụng rất nhiều trong JavaScript. Ngoài việc tạo một thể hiện của Object và sau đó thêm các thuộc tính và phương thức cho nó, có ba cách phổ biến để tạo các đối tượng trong JavaScript.

Hàm xây dựng

Có các hàm xây dựng tích hợp mà tất cả chúng ta có thể sử dụng chúng theo thời gian, như Date (), Number (), Boolean (), v.v. như thế này:

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

và bạn có thể gọi nó, chỉ cần sử dụng new (), để tạo một thể hiện mới của hàm tạo, tạo một cái gì đó như bên dưới và gọi hàm xây dựng với các tham số được điền:

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

Đối tượng

Sử dụng các đối tượng bằng chữ là trường hợp tạo đối tượng được sử dụng trong JavaScript, đây là một ví dụ về việc tạo một đối tượng đơn giản, bạn có thể gán bất cứ thứ gì cho các thuộc tính đối tượng của mình miễn là chúng được định nghĩa:

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

Tạo mẫu

Sau khi tạo Đối tượng, bạn có thể tạo nguyên mẫu cho nhiều thành viên hơn, ví dụ như thêm màu vào Hộp của chúng tôi, chúng tôi có thể thực hiện việc này:

Box.prototype.colour = 'red';

2

Mặc dù nhiều người ở đây nói rằng không có cách tốt nhất để tạo đối tượng, nhưng có một lý do là tại sao có rất nhiều cách để tạo đối tượng trong JavaScript, kể từ năm 2019, và điều này phải làm với tiến trình của JavaScript qua các lần lặp khác nhau phát hành EcmaScript có từ năm 1997.

Trước ECMAScript 5, chỉ có hai cách tạo đối tượng: hàm xây dựng hoặc ký hiệu bằng chữ (một cách thay thế tốt hơn cho Object mới ()). Với ký hiệu hàm tạo, bạn tạo một đối tượng có thể được khởi tạo thành nhiều trường hợp (với từ khóa mới), trong khi ký hiệu bằng chữ sẽ cung cấp một đối tượng, giống như một đơn.

// constructor function
function Person() {};

// literal notation
var Person = {};

Bất kể phương thức bạn sử dụng là gì, các đối tượng JavaScript chỉ là các thuộc tính của các cặp giá trị khóa:

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

Trong các phiên bản đầu tiên của JavaScript, cách thực sự duy nhất để bắt chước kế thừa dựa trên lớp là sử dụng các hàm tạo. hàm tạo là một hàm đặc biệt được gọi với từ khóa 'mới'. Theo quy ước, định danh hàm được viết hoa, albiet nó không bắt buộc. Bên trong hàm tạo, chúng tôi đề cập đến từ khóa 'this' để thêm các thuộc tính cho đối tượng mà hàm constructor đang tạo ngầm. Hàm constructor hoàn toàn trả về đối tượng mới với các thuộc tính được điền trở lại hàm gọi, trừ khi bạn sử dụng rõ ràng từ khóa return và trả về một cái gì đó khác.

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

Có một vấn đề với phương thức sayName. Thông thường, trong các ngôn ngữ lập trình dựa trên lớp hướng đối tượng, bạn sử dụng các lớp làm nhà máy để tạo đối tượng. Mỗi đối tượng sẽ có các biến đối tượng riêng, nhưng nó sẽ có một con trỏ tới các phương thức được định nghĩa trong kế hoạch chi tiết của lớp. Thật không may, khi sử dụng hàm xây dựng của JavaScript, mỗi khi được gọi, nó sẽ xác định một thuộc tính sayName mới trên đối tượng mới được tạo. Vì vậy, mỗi đối tượng sẽ có thuộc tính sayName riêng. Điều này sẽ tiêu tốn nhiều tài nguyên bộ nhớ hơn.

Ngoài việc tăng tài nguyên bộ nhớ, việc xác định các phương thức bên trong hàm xây dựng sẽ loại bỏ khả năng kế thừa. Một lần nữa, phương thức sẽ được định nghĩa là một thuộc tính trên đối tượng mới được tạo và không có đối tượng nào khác, vì vậy tính kế thừa không thể hoạt động như thế nào. Do đó, JavaScript cung cấp chuỗi nguyên mẫu như một hình thức thừa kế, biến JavaScript thành ngôn ngữ nguyên mẫu.

Nếu bạn có cha mẹ và cha mẹ chia sẻ nhiều tài sản của một đứa trẻ, thì đứa trẻ nên được thừa hưởng những tài sản đó. Trước ES5, nó đã được thực hiện như sau:

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

Cách chúng tôi sử dụng chuỗi nguyên mẫu ở trên có một sự giải quyết. Vì nguyên mẫu là một liên kết trực tiếp, bằng cách thay đổi thuộc tính của một đối tượng trong chuỗi nguyên mẫu, bạn cũng sẽ thay đổi cùng một thuộc tính của đối tượng khác. Rõ ràng, thay đổi phương pháp kế thừa của một đứa trẻ không nên thay đổi phương pháp của cha mẹ. Object.create đã giải quyết vấn đề này bằng cách sử dụng một polyfill. Do đó, với Object.create, bạn có thể sửa đổi một cách an toàn tài sản của trẻ em trong chuỗi nguyên mẫu mà không ảnh hưởng đến tài sản tương tự của cha mẹ trong chuỗi nguyên mẫu.

ECMAScript 5 đã giới thiệu Object.create để giải quyết lỗi đã nói ở trên trong hàm tạo để tạo đối tượng. Phương thức Object.create () TẠO một đối tượng mới, sử dụng một đối tượng hiện có làm nguyên mẫu của đối tượng mới được tạo. Vì một đối tượng mới được tạo, bạn không còn gặp phải vấn đề khi sửa đổi thuộc tính con trong chuỗi nguyên mẫu sẽ sửa đổi tham chiếu của cha mẹ đối với thuộc tính đó trong chuỗi.

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.

Trước ES6, đây là một mẫu sáng tạo phổ biến để sử dụng các hàm tạo và 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);

Bây giờ Object.create kết hợp với các hàm xây dựng đã được sử dụng rộng rãi để tạo và kế thừa đối tượng trong JavaScript. Tuy nhiên, ES6 đã đưa ra khái niệm về các lớp, chủ yếu là đường cú pháp so với kế thừa dựa trên nguyên mẫu hiện có của JavaScript. Cú pháp lớp không giới thiệu một mô hình kế thừa hướng đối tượng mới cho JavaScript. Do đó, JavaScript vẫn là một ngôn ngữ nguyên mẫu.

Các lớp ES6 làm cho việc thừa kế dễ dàng hơn nhiều. Chúng ta không còn phải sao chép thủ công các hàm nguyên mẫu của lớp cha và đặt lại hàm tạo của lớp con.

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

Nói chung, 5 chiến lược khác nhau của Tạo đối tượng trong JavaScript đã trùng khớp với sự phát triển của tiêu chuẩn EcmaScript.


0

Tất nhiên có một cách tốt nhất. Các tính năng trong javascript có vô số thuộc tính và không thể đếm được.

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

Trong ví dụ trên bạn có thể thấy rằng một đối tượng trống thực sự có các thuộc tính.

Ok trước tiên hãy xem đó là cách tốt nhất:

var new_object = Object.create(null)

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

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

Trong ví dụ trên, nhật ký sẽ xuất sai.

Bây giờ hãy xem tại sao các cách tạo đối tượng khác không chính xác.

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

Như bạn có thể thấy ở trên, tất cả các ví dụ đều đăng nhập đúng. Điều đó có nghĩa là nếu bạn có một trường hợp mà bạn có một for invòng lặp để xem nếu đối tượng có thuộc tính sẽ dẫn bạn đến kết quả sai.

Lưu ý rằng cách tốt nhất không dễ dàng. Bạn phải xác định tất cả các thuộc tính của dòng đối tượng theo dòng. Các cách khác dễ dàng hơn và sẽ có ít mã hơn để tạo một đối tượng nhưng bạn phải biết trong một số trường hợp. Nhân tiện, tôi luôn sử dụng "các cách khác" và một giải pháp để cảnh báo ở trên nếu bạn không sử dụng cách tốt nhất là:

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

0

Chủ yếu có 3 cách tạo đối tượng-

Đơn giản nhất là sử dụng các đối tượng bằng chữ .

const myObject = {}

Mặc dù phương pháp này là đơn giản nhất nhưng có nhược điểm, tức là nếu đối tượng của bạn có hành vi (chức năng trong đó), thì trong tương lai nếu bạn muốn thực hiện bất kỳ thay đổi nào đối với nó, bạn sẽ phải thay đổi nó trong tất cả các đối tượng .

Vì vậy, trong trường hợp đó, tốt hơn là sử dụng Hàm Factory hoặc Con constructor. (Bất cứ ai bạn thích)

Hàm nhà máy là những hàm trả về một object.eg-

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

Hàm xây dựng là các hàm gán thuộc tính cho các đối tượng bằng cách sử dụng "this" keyword.eg-

function constructorFunc(exampleValue){
   this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.