ความแตกต่างระหว่างโมเดลการดูสิ่งที่น่าพิศวงที่ประกาศเป็นตัวอักษรออบเจกต์และฟังก์ชั่น


195

ในสิ่งที่น่าพิศวง js ฉันเห็นดูแบบจำลองประกาศเป็น:

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

ko.applyBindings(viewModel );

หรือ:

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

ko.applyBindings(new viewModel ());

ความแตกต่างระหว่างสองถ้าอะไร?

ฉันพบการสนทนานี้ในกลุ่ม google knockoutjs แต่มันไม่ได้ให้คำตอบที่น่าพอใจ

ฉันสามารถดูเหตุผลหากฉันต้องการเริ่มต้นโมเดลด้วยข้อมูลบางอย่างตัวอย่างเช่น:

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

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

แต่ถ้าฉันไม่ทำอย่างนั้นมันเป็นเรื่องสำคัญที่ฉันจะเลือกสไตล์?


ฉันไม่เชื่อว่ามีความแตกต่าง ฉันมักจะใช้รูปแบบตัวสร้างเนื่องจากฉันมักจะมีวิธีการที่ฉันต้องการที่จะประกาศเกี่ยวกับprototype(วิธีการที่มักจะดึงข้อมูลจากเซิร์ฟเวอร์และปรับปรุงรูปแบบมุมมองตามลำดับ) อย่างไรก็ตามคุณสามารถประกาศได้อย่างชัดเจนว่าพวกเขาเป็นคุณสมบัติของวัตถุตามตัวอักษรดังนั้นฉันไม่เห็นความแตกต่าง
James Allardice

4
สิ่งนี้ไม่เกี่ยวกับสิ่งที่น่าพิศวงและทุกอย่างเกี่ยวกับการทำให้อินสแตนซ์ของวัตถุที่กำหนดเองใน JavaScript ง่ายขึ้น
zzzzBov

1
@Kev ถ้า viewModel เป็นฟังก์ชันคอนสตรัคเตอร์ที่คุณเขียนไว้ใน UpperCase เหมือนกับ var PersonViewModel = function () {... };
Elisabeth

คำตอบ:


252

มีข้อดีสองสามข้อในการใช้ฟังก์ชันเพื่อกำหนดโมเดลมุมมองของคุณ

ข้อได้เปรียบหลักคือคุณสามารถเข้าถึงคุณค่าthisที่เท่ากับทันทีที่สร้างขึ้น ซึ่งหมายความว่าคุณสามารถทำได้:

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

ดังนั้นค่าที่สามารถสังเกตได้ของคุณที่คำนวณได้สามารถเชื่อมโยงกับค่าที่เหมาะสมthisแม้ว่าจะถูกเรียกจากขอบเขตอื่น

ด้วยวัตถุตามตัวอักษรคุณจะต้อง:

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

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

ในกรณีนี้คุณสามารถใช้viewModelโดยตรงในการคำนวณที่สังเกตได้ แต่จะได้รับการประเมินทันที (โดยค่าเริ่มต้น) ดังนั้นคุณจึงไม่สามารถกำหนดได้ภายในวัตถุตามตัวอักษรตามที่viewModelไม่ได้กำหนดไว้จนกว่าจะปิดวัตถุตามตัวอักษร หลายคนไม่ชอบที่การสร้างโมเดลมุมมองของคุณนั้นไม่ได้ถูกห่อหุ้มด้วยการโทรครั้งเดียว

รูปแบบอื่นที่คุณสามารถใช้เพื่อให้แน่ใจว่าthisเหมาะสมเสมอคือการตั้งค่าตัวแปรในฟังก์ชันเท่ากับค่าที่เหมาะสมthisและใช้แทน จะเป็นเช่นนี้:

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

ตอนนี้ถ้าคุณอยู่ในขอบเขตของแต่ละรายการและการโทร$root.removeItemค่าของthisจริงจะเป็นข้อมูลที่ถูกผูกไว้ที่ระดับนั้น (ซึ่งจะเป็นรายการ) โดยใช้ตัวเองในกรณีนี้คุณสามารถมั่นใจได้ว่าจะถูกลบออกจากรูปแบบมุมมองโดยรวม

ตัวเลือกอื่นกำลังใช้bindงานซึ่งรองรับโดยเบราว์เซอร์ที่ทันสมัยและเพิ่มโดย KO หากไม่รองรับ ในกรณีนั้นจะมีลักษณะดังนี้:

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

มีอีกมากมายที่สามารถพูดได้ในหัวข้อนี้และรูปแบบมากมายที่คุณสามารถสำรวจได้ (เช่นรูปแบบของโมดูลและรูปแบบของโมดูลที่เปิดเผย) แต่โดยทั่วไปแล้วการใช้ฟังก์ชั่นจะช่วยให้คุณมีความยืดหยุ่นมากขึ้นและควบคุมวิธีสร้างวัตถุและความสามารถในการอ้างอิง ตัวแปรที่เป็นส่วนตัวของอินสแตนซ์


1
คำตอบที่ดี ฉันมักจะใช้ฟังก์ชั่น (โดยใช้รูปแบบการเปิดเผยโมดูล) สำหรับวัตถุที่ซับซ้อนเช่น viewmodels แต่สำหรับรุ่นเรียบง่ายฉันใช้ฟังก์ชั่นเพื่อให้ฉันสามารถจัดการทุกอย่างได้ในที่เดียว
John Papa

1
@JohnPapa - เพิ่งดูวิดีโอ PluralSight ของคุณในสิ่งที่น่าพิศวง (เพียงครึ่งทาง - และโดยบังเอิญเพียงแค่ดูส่วนของฟังก์ชั่นเทียบกับออบเจ็กต์ตามตัวอักษร) ทำได้ดีมากและช่วยให้เงินลดลง คุ้มค่ากับการสมัครสมาชิกเดือนเดียว
Kev

@Kev - ขอบคุณ ดีใจที่คุณได้รับประโยชน์จากมัน บางคนไม่สนใจเกี่ยวกับโมดูลนั้นเพราะมันไม่ใช่แนวคิดที่น่าพิศวงจริงๆ, มีรูปแบบ JavaScript มากขึ้น แต่ฉันพบเมื่อฉันได้รับสิ่งที่น่าพิศวงมากขึ้นกว่าเดิมแนวคิดเหล่านั้นช่วยให้ฉันสร้างโค้ดที่เสถียรยิ่งขึ้น อย่างไรก็ตามดีใจที่คุณสนุกกับมัน :)
John Papa

ไม่ควรเป็น self.items = ko.observableArray (); ในตัวอย่างที่สองของคุณ? คุณใช้สิ่งนี้ถูกต้องหรือไม่
JackNova

1
@JackNova ในฟังก์ชัน Constructor selfและthisเหมือนกันดังนั้นจะเท่ากับ ในฟังก์ชั่น removeItem selfจะมีประโยชน์มากขึ้นเนื่องจากthisจะไม่มีอินสแตนซ์ปัจจุบันอีกต่อไปเมื่อดำเนินการในบริบทของรายการย่อย
RP Niemeyer

12

ฉันใช้วิธีอื่น แต่คล้ายกัน:

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

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

เหตุผลสองประการ:

  1. ไม่ได้ใช้thisซึ่งอาจสร้างความสับสนเมื่อใช้ภายในko.computeds ฯลฯ
  2. viewModel ของฉันเป็นซิงเกิลฉันไม่จำเป็นต้องสร้างหลายอินสแตนซ์ (เช่นnew viewModel())

นี่เป็นการเปิดเผยรูปแบบของโมดูลหากไม่เข้าใจผิด คำตอบที่ดี แต่คำถามไม่ได้เกี่ยวกับรูปแบบนี้
Phil

@paul: ขออภัยที่จะขอด้ายเก่า คุณพูดMy viewModel is a singleton, I don't need to create multiple instances (i.e. new viewModel()) แต่ไม่ชัดเจนว่าคุณพยายามจะพูดอะไรบ้างคุณI don't need to create multiple instances สามารถใช้งานได้มากขึ้นดังนั้นเราสามารถเข้าใจข้อดีของวิธีการของคุณ ขอบคุณ
หมู

IMO หนึ่งในเหตุผลที่คุณจะประกาศ ViewModel เนื่องจากfunctionเป็นเพราะคุณจะดำเนินการมากกว่าหนึ่งครั้ง อย่างไรก็ตามในตัวอย่างของฉันมันเป็นฟังก์ชันที่ไม่ระบุชื่อที่ถูกเรียกใช้ทันทีดังนั้นมันจะไม่ถูกสร้างมากกว่าหนึ่งครั้ง มันคล้ายกับ Object Objectal ในตัวอย่างด้านบน แต่ให้ความโดดเดี่ยวมากขึ้น
paulslater19
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.