Tôi có nên sử dụng các hàm đối tượng hay hàm tạo không?


94

Tôi đang bối rối về cách mà tôi nên tạo một đối tượng trong javascript. Có vẻ như có ít nhất hai cách. Một là sử dụng ký hiệu theo nghĩa đen của đối tượng trong khi cái kia sử dụng các hàm xây dựng. Có lợi thế của cái này hơn cái kia không?


1
Câu trả lời hay nhất: stackoverflow.com/questions/4597926/… - Tóm lại, bạn cũng có thể thiết lập một hàm để tạo các phiên bản dạng ký hiệu chữ. Thực hiện điều này, mỗi trường hợp mang tất cả các phương thức, trong khi với một phương thức khởi tạo, tất cả các trường hợp đều tham chiếu đến các phương thức nguyên mẫu. Nghĩa là hàm tạo có hiệu suất bộ nhớ tốt hơn.
Federico

Nếu nhớ không phải là một quyền truy cập tài sản đối tượng trực vấn đề rất nhiều độ lớn nhanh hơn - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Câu trả lời:


131

Nếu bạn không có hành vi liên kết với một đối tượng (tức là nếu đối tượng chỉ là một vùng chứa cho dữ liệu / trạng thái), tôi sẽ sử dụng một đối tượng theo nghĩa đen.

var data = {
    foo: 42,
    bar: 43
};

Áp dụng nguyên tắc KISS . Nếu bạn không cần bất cứ thứ gì ngoài một vùng chứa dữ liệu đơn giản, hãy chọn một từ đơn giản.

Nếu bạn muốn thêm hành vi vào đối tượng của mình, bạn có thể đi với một hàm tạo và thêm các phương thức vào đối tượng trong quá trình xây dựng hoặc cung cấp cho lớp của bạn một nguyên mẫu.

function MyData(foo, bar) {
    this.foo = foo;
    this.bar = bar;

    this.verify = function () {
        return this.foo === this.bar;
    };
}

// or:
MyData.prototype.verify = function () {
    return this.foo === this.bar;
};

Một lớp như thế này cũng hoạt động giống như một lược đồ cho đối tượng dữ liệu của bạn: Bây giờ bạn có một số loại hợp đồng (thông qua phương thức khởi tạo) những thuộc tính mà đối tượng khởi tạo / chứa. Một chữ miễn phí chỉ là một khối dữ liệu vô định hình.

Bạn cũng có thể có một verifychức năng bên ngoài hoạt động trên một đối tượng dữ liệu cũ thuần túy:

var data = {
    foo: 42,
    bar: 43
};

function verify(data) {
    return data.foo === data.bar;
}

Tuy nhiên, điều này không thuận lợi khi liên quan đến tính đóng gói: Lý tưởng nhất là tất cả dữ liệu + hành vi được liên kết với một thực thể nên sống cùng nhau.


12
Lời giải thích tuyệt vời, nhưng còn việc đặt các hàm trong một đối tượng theo nghĩa đen thì sao? Tôi đã thấy điều này được thực hiện trước đây. Thực ra bài viết dưới đây có một ví dụ về điều này.
chobo

23
Nếu bạn bao gồm các định nghĩa hàm như một phần của đối tượng theo nghĩa đen hoặc sử dụng this.fn = function ...cách tiếp cận trong một phương thức khởi tạo, thì mỗi cá thể đối tượng của bạn sẽ có các bản sao hàm của riêng chúng. Sử dụng phương pháp nguyên mẫu, bạn đính kèm từng hàm một lần và chỉ một lần: chúng sẽ được các phiên bản kế thừa thông qua kế thừa nguyên mẫu.
Ates Goral

14
Tôi tin rằng bạn đã bỏ lỡ một điều quan trọng. chỉ hàm khởi tạo mới có thể cung cấp các thành viên private cũng như các thành viên chung (tính đóng gói). trong đối tượng theo nghĩa đen - chúng đều là công khai.
Royi Namir

Đâu sẽ là cách tốt hơn để sử dụng công cụ trò chơi? Tôi đã sử dụng phương thức hàm tạo nhưng các nguyên mẫu của tôi không có quyền truy cập vào dữ liệu hàm tạo.
zachdyer

90

Về cơ bản, nó tóm tắt về việc bạn có cần nhiều phiên bản đối tượng của mình hay không; đối tượng được định nghĩa bằng một hàm tạo cho phép bạn có nhiều phiên bản của đối tượng đó. Các ký tự đối tượng về cơ bản là các tệp đơn với các biến / phương thức đều là công khai.

// define the objects:
var objLit = {
  x: 0,
  y: 0,
  z: 0,
  add: function () {
    return this.x + this.y + this.z;
  }
};

var ObjCon = function(_x, _y, _z) {
  var x = _x; // private
  var y = _y; // private
  this.z = _z; // public
  this.add = function () {
    return x + y + this.z; // note x, y doesn't need this.
  };
};

// use the objects:
objLit.x = 3; 
objLit.y = 2; 
objLit.z = 1; 
console.log(objLit.add());    

var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line

1
Đây là một điểm rất cần lưu ý khi quyết định. Cám ơn.
zkent

Theo kinh nghiệm của tôi, đây chính xác là điều tạo nên sự khác biệt. Ví dụ rõ ràng tuyệt vời.
Air

9

Một cách khác để tạo các đối tượng một cách thống nhất là sử dụng một hàm trả về một đối tượng:

function makeObject() {
    var that = {
        thisIsPublic: "a public variable"
        thisIsAlsoPublic: function () {
            alert(that.thisIsPublic);
        }
    };

    var secret = "this is a private variable"

    function secretFunction() { // private method
        secret += "!"; // can manipulate private variables
        that.thisIsPublic = "foo";     
    }

    that.publicMethod = function () {
        secret += "?"; // this method can also mess with private variables
    }

    that.anotherPublicVariable = "baz";

    return that; // this is the object we've constructed
}

makeObject.static = "This can be used to add a static varaible/method";

var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!

Vì các hàm trong JavaScript là các hàm đóng nên chúng ta có thể sử dụng các biến và phương thức riêng và tránh new.

Từ http://javascript.crockford.com/private.html về các biến riêng trong JavaScript.


7

Đoạn mã dưới đây cho thấy ba phương pháp tạo một đối tượng, cú pháp Object Literal, một hàm tạo hàm và Object.create(). Cú pháp theo nghĩa đen của đối tượng chỉ đơn giản là tạo và đối tượng một cách nhanh chóng và như vậy nó __prototype__Objectđối tượng và nó sẽ có quyền truy cập vào tất cả các thuộc tính và phương thức của Object. Từ quan điểm của một mẫu thiết kế, một ký tự Object đơn giản nên được sử dụng để lưu trữ một phiên bản dữ liệu duy nhất.

Hàm tạo hàm có một thuộc tính đặc biệt được đặt tên .prototype. Thuộc tính này sẽ trở thành thuộc tính __prototype__của bất kỳ đối tượng nào được tạo bởi hàm tạo. Tất cả các thuộc tính và phương thức được thêm vào thuộc .prototypetính của một hàm tạo sẽ có sẵn cho tất cả các đối tượng mà nó tạo ra. Một phương thức khởi tạo nên được sử dụng nếu bạn yêu cầu nhiều phiên bản dữ liệu hoặc yêu cầu hành vi từ đối tượng của bạn. Lưu ý rằng hàm tạo hàm cũng được sử dụng tốt nhất khi bạn muốn mô phỏng một mẫu phát triển riêng / công khai. Hãy nhớ đặt tất cả các phương thức được chia sẻ trên .prototypeđể chúng sẽ không được tạo trong mỗi trường hợp đối tượng.

Tạo các đối tượng bằng cách Object.create()sử dụng một đối tượng theo nghĩa đen __prototype__cho các đối tượng được tạo bởi phương pháp này. Tất cả các thuộc tính và phương thức được thêm vào đối tượng theo nghĩa đen sẽ có sẵn cho tất cả các đối tượng được tạo từ nó thông qua kế thừa nguyên mẫu thực sự. Đây là phương pháp ưa thích của tôi.

//Object Example

//Simple Object Literal
var mySimpleObj = {
    prop1 : "value",
    prop2 : "value"
}

// Function Constructor
function PersonObjConstr()  {
    var privateProp = "this is private";
    this.firstname = "John";
    this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function()    {
    return "PersonObjConstr says: Hello " + this.firstname + 
    " " + this.lastname;
};

// Object Literal
var personObjLit = {
    firstname : "John",
    lastname: "Doe",
    greetFullName : function() {
        return "personObjLit says: Hello " + this.firstname +
        ", " + this.lastname;
    }
} 

var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);

1
Vì bạn đã khai báo hàm bên trong một đối tượng theo nghĩa đen. Điều đó có nghĩa là khi bạn tạo một đối tượng bằng cách sử dụng Object.createhàm bên trong chữ sẽ là duy nhất cho mỗi trường hợp?
JohnnyQ

6

Nó phụ thuộc vào những gì bạn muốn làm. Nếu bạn muốn sử dụng các biến hoặc hàm riêng (bán) trong đối tượng của mình, thì một hàm khởi tạo là cách để làm điều đó. Nếu đối tượng của bạn chỉ chứa các thuộc tính và phương thức, một đối tượng theo nghĩa đen là tốt.

function SomeConstructor(){
    var x = 5;
    this.multiply5 = function(i){
        return x*i;
    }
}
var myObj = new SomeConstructor;

var SomeLiteral = {
    multiply5: function(i){ return i*5; }
}

Bây giờ phương pháp multiply5trong myObjSomeLiterallàm chính xác điều tương tự. Sự khác biệt duy nhất là myObj sử dụng một biến riêng. Cái sau có thể hữu ích trong một số trường hợp. Hầu hết các trường hợp một ký tự Object là đủ và là một cách tốt và gọn gàng để tạo một đối tượng JS.


Sự khác biệt giữa một hàm và một phương thức là gì? Tôi đến từ nền tảng ac # nên với tôi một hàm là độc lập và một phương thức chỉ là một hàm là một phần của một lớp.
chobo

1
Không có quá nhiều khác biệt, hãy xem ví dụ web-source.net/javascript_tutorial/… . Trên thực tế, trong DOMscripting (js phía máy khách trong trình duyệt), tất cả các hàm đều trở thành các phương thức của đối tượng cửa sổ (không gian tên chung), tôi sẽ nói (bạn có thể giải quyết tất cả các hàm 'độc lập' dưới dạng cửa sổ. [Một số chức năng].
KooiInc

5

nhập mô tả hình ảnh ở đây

Bạn có muốn một phiên bản duy nhất của đối tượng cho trang - Literal.

Bạn có muốn chỉ chuyển dữ liệu như các đối tượng DTO đơn giản HÃY ĐẶT: - Literal

Bạn có muốn tạo các đối tượng thực với các hành vi phương thức, nhiều thể hiện - Hàm tạo, Tuân theo các nguyên tắc OOP, kế thừa: - Các hàm tạo.

Dưới đây là video youtube giải thích chi tiết nghĩa đen là gì, hàm tạo là gì và chúng khác nhau như thế nào.

https://www.youtube.com/watch?v=dVoAq2D3n44


1

Đi với đối tượng theo nghĩa đen, nó phù hợp hơn và mở rộng tốt hơn với việc giới thiệu các giá trị ban đầu.


Làm thế nào để bạn tạo các biến riêng trong một đối tượng theo nghĩa đen?
EhevuTov

Bạn có thể không thực sự, nó không liên quan đến câu hỏi ban đầu vì vậy tôi chỉ sẽ cung cấp cho bạn một liên kết: javascript.crockford.com/private.html
Tom

1
Trên thực tế, nó có liên quan bởi vì nơi có sự khác biệt, có lý do để sử dụng cái này hay cái kia tùy thuộc vào các tình huống nhất định; trong trường hợp này, sẽ là bạn có muốn các biến riêng tư hay không. Bạn có thể tạo các biến private theo nghĩa đen bằng cách trước tiên tạo một hàm đóng theo nghĩa đen của bạn, nhưng theo ý kiến ​​của tôi thì nó xấu hơn rất nhiều và khó đọc.
EhevuTov

Tôi đã sửa lại, bài đọc ban đầu của tôi về câu hỏi là chobo đang hỏi về cách truyền các biến cho một hàm tạo như trong danh sách tham số so với tham số theo nghĩa đen của đối tượng đơn.
Tom

1

Như đã đề cập trong https://www.w3schools.com/js/js_object_definition.asp

Sử dụng một đối tượng theo nghĩa đen, bạn vừa định nghĩatạo , một đối tượng trong một câu lệnh.

Cũng thế

Đối tượng theo nghĩa đen chỉ tạo ra một đối tượng duy nhất. Đôi khi chúng ta thích có một kiểu đối tượng có thể được sử dụng để tạo nhiều đối tượng cùng một kiểu.



0

Trên thực tế, methinks, chúng ta có thể có các phương thức riêng trong các ký tự đối tượng. Hãy xem xét mã bên dưới:

var myObject = {

   publicMethod: function () {
      privateMethod1();
      privateMethod2(); 
      function privateMethod1(){
          console.log('i am privateMethod1');
      } 
      function privateMethod2(){
          console.log('i am privateMethod2');
      } 
   }

}

Vấn đề về hương vị, nhưng tôi thích sử dụng các ký tự đối tượng nếu có thể.


-1

// Object Literal và Object constructor

function MyData(foo, bar) {
        this.foo = foo;
        this.bar = bar;

    }
MyData.prototype.verify = function () {
        return this.foo === this.bar;
    };

//add property using prototype

var MD  = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null. 
var MD1  = new MyData(1,2); // intialized the value at the starting. 
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top 
MyData.prototype.verify = function (foo,bar) {
    return this.foo === this.bar;
};
var MD1  = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data 

1
Trong ví dụ của bạn, Object được khai báo ở đâu?
JohnnyQ
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.