Sự khác biệt giữa các mô hình Xem loại trực tiếp được khai báo là đối tượng bằng chữ và hàm


195

Trong js loại trực tiếp, tôi thấy Mô hình Xem được khai báo là:

var viewModel = {
    firstname: ko.observable("Bob")
};

ko.applyBindings(viewModel );

hoặc là:

var viewModel = function() {
    this.firstname= ko.observable("Bob");
};

ko.applyBindings(new viewModel ());

Sự khác biệt giữa hai, nếu có?

Tôi đã tìm thấy cuộc thảo luận này trên nhóm google knockoutjs nhưng nó không thực sự cho tôi một câu trả lời thỏa đáng.

Tôi có thể thấy một lý do nếu tôi muốn khởi tạo mô hình với một số dữ liệu, ví dụ:

var viewModel = function(person) {
    this.firstname= ko.observable(person.firstname);
};

var person = ... ;
ko.applyBindings(new viewModel(person));

Nhưng nếu tôi không làm điều đó có quan trọng tôi chọn phong cách nào không?


Tôi không tin có một sự khác biệt. Tôi thường sử dụng mẫu constructor, vì tôi thường có các phương thức mà tôi muốn khai báo trên prototype(ví dụ, thường lấy dữ liệu từ máy chủ và cập nhật mô hình khung nhìn phù hợp). Tuy nhiên, rõ ràng bạn vẫn có thể tuyên bố chúng là tài sản của một đối tượng theo nghĩa đen, vì vậy tôi thực sự không thể thấy sự khác biệt.
James Allardice

4
Điều này không liên quan gì đến việc loại trực tiếp và mọi thứ phải làm để dễ dàng khởi tạo các đối tượng tùy chỉnh trong JavaScript
zzzzBov

1
@Kev nếu viewModel là hàm xây dựng, bạn viết nó trong UpperCase giống như var PersonViewModel = function () {...};
Elisabeth

Câu trả lời:


252

Có một vài lợi thế khi sử dụng hàm để xác định mô hình khung nhìn của bạn.

Ưu điểm chính là bạn có quyền truy cập ngay vào một giá trị thistương đương với thể hiện được tạo. Điều này có nghĩa là bạn có thể làm:

var ViewModel = function(first, last) {
  this.first = ko.observable(first);
  this.last = ko.observable(last);
  this.full = ko.computed(function() {
     return this.first() + " " + this.last();
  }, this);
};

Vì vậy, tính toán có thể quan sát của bạn có thể được ràng buộc với giá trị phù hợp this, ngay cả khi được gọi từ một phạm vi khác.

Với một đối tượng theo nghĩa đen, bạn sẽ phải làm:

var viewModel = {
   first: ko.observable("Bob"),
   last: ko.observable("Smith"),
};

viewModel.full = ko.computed(function() {
   return this.first() + " " + this.last();
}, viewModel);

Trong trường hợp đó, bạn có thể sử dụng viewModeltrực tiếp trong tính toán có thể quan sát được, nhưng nó được đánh giá ngay lập tức (theo mặc định) để bạn không thể định nghĩa nó trong nghĩa đen của đối tượng, như viewModelkhông được định nghĩa cho đến khi đóng đối tượng theo nghĩa đen. Nhiều người không thích việc tạo mô hình xem của bạn không được gói gọn trong một cuộc gọi.

Một mẫu khác mà bạn có thể sử dụng để đảm bảo thisluôn phù hợp là đặt một biến trong hàm bằng với giá trị phù hợp thisvà sử dụng nó thay thế. Điều này sẽ giống như:

var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         self.items.remove(item);
    }
};

Bây giờ, nếu bạn ở trong phạm vi của một mục và cuộc gọi riêng lẻ $root.removeItem, giá trị thisthực sự sẽ là dữ liệu bị ràng buộc ở cấp đó (sẽ là mục đó). Bằng cách sử dụng self trong trường hợp này, bạn có thể đảm bảo rằng nó đang bị xóa khỏi mô hình xem tổng thể.

Một tùy chọn khác đang sử dụng bind, được hỗ trợ bởi các trình duyệt hiện đại và được thêm bởi KO, nếu nó không được hỗ trợ. Trong trường hợp đó, nó sẽ trông như:

var ViewModel = function() {
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         this.items.remove(item);
    }.bind(this);
};

Có rất nhiều điều có thể nói về chủ đề này và nhiều mẫu mà bạn có thể khám phá (như mẫu mô-đun và tiết lộ mẫu mô-đun), nhưng về cơ bản, sử dụng một hàm giúp bạn linh hoạt hơn và kiểm soát cách tạo đối tượng và khả năng tham chiếu các biến là riêng tư.


1
Câu trả lời chính xác. Tôi thường sử dụng một hàm (sử dụng mô hình mô-đun tiết lộ) cho các đối tượng phức tạp như viewmodels. Nhưng đối với các mô hình đơn giản, tôi sử dụng một chức năng để tôi có thể xử lý mọi thứ ở một nơi.
John Papa

1
@JohnPapa - vừa xem video PluralSight của bạn về loại trực tiếp (chỉ hơn nửa chặng đường - và thật trùng hợp, chỉ xem phần về đối tượng theo nghĩa đen so với chức năng). Thực sự được thực hiện tốt và đã giúp đồng xu giảm. Cũng đáng đăng ký một tháng cho điều đó một mình.
Kev

@Kev - Cảm ơn. Vui mừng bạn đang nhận được giá trị từ nó. Một số người không quan tâm đến mô-đun đó vì nó không thực sự là một khái niệm Knockout, nhiều mẫu JavaScript hơn. Nhưng tôi nhận thấy khi tôi tiến xa hơn với Knockout rằng những khái niệm đó thực sự giúp tôi tạo mã ổn định hơn. Dù sao, rất vui vì bạn thích nó :)
John Papa

không nên tự.items = ko.observableArray (); trong ví dụ thứ hai của bạn? Bạn đã sử dụng nó, nó có đúng không?
JackNova

1
@JackNova trong hàm tạo selfthisgiống nhau, vì vậy hoặc sẽ tương đương. Trong hàm removeItem, selfsẽ trở nên hữu ích hơn, vì thissẽ không còn là thể hiện hiện tại khi được thực thi trong ngữ cảnh của một mục con.
RP Niemeyer

12

Tôi sử dụng một phương pháp khác, mặc dù tương tự:

var viewModel = (function () {
  var obj = {};
  obj.myVariable = ko.observable();
  obj.myComputed = ko.computed(function () { return "hello" + obj.myVariable() });

  ko.applyBindings(obj);
  return obj;
})();

Vài lý do:

  1. Không sử dụng this, có thể gây nhầm lẫn khi sử dụng trong ko.computeds vv
  2. ViewModel của tôi là một singleton, tôi không cần tạo nhiều phiên bản (ví dụ new viewModel())

Đây là tiết lộ mô hình mô-đun nếu không nhầm. Câu trả lời tốt nhưng câu hỏi không phải là về mô hình này.
Phil

@paul: Xin lỗi khi hỏi chủ đề cũ. bạn nói My viewModel is a singleton, I don't need to create multiple instances (i.e. new viewModel()) nhưng không rõ bạn đang cố nói gì, bạn I don't need to create multiple instances có thể sử dụng nhiều hơn để người ta có thể hiểu được lợi thế của phương pháp của bạn không. cảm ơn
Mou

IMO, một trong những lý do bạn sẽ tuyên bố ViewModel functionlà vì bạn sẽ thực thi nó nhiều lần. Tuy nhiên, trong ví dụ của tôi, đó là một hàm ẩn danh được gọi ngay lập tức, vì vậy nó sẽ không được tạo nhiều lần. Nó rất giống với Object Literal trong ví dụ trên, nhưng mang lại cho bạn sự cô lập hơn
paulslater19
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.