เมื่อใดควรใช้การเขียนโปรแกรมต้นแบบใน JavaScript


15

ฉันใช้เวลาพอสมควรในการพัฒนาวิดเจ็ตอย่างง่ายสำหรับโครงการด้วยวิธีต่อไปนี้:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

แต่ฉันได้เริ่มเปลี่ยนรูปแบบของฉันเป็นดังต่อไปนี้:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

จริงอยู่ที่นี่เป็นตัวอย่างที่งี่เง่าดังนั้นอย่าห่อรอบแกน แต่อะไรคือความแตกต่างของหน้าที่การใช้งานและเมื่อใดที่ฉันควรเลือกอย่างใดอย่างหนึ่ง


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

ใช่ฉันตั้งใจวางprojectประกาศไว้ในฟังก์ชั่น Updated
JDillon522

กันที่นี่ ตัวอย่างแรกคือคงที่ที่สองคือการมุ่งเน้นวัตถุ
Aitch

1
หากคุณใช้เพียงหนึ่งอินสแตนซ์ของวัตถุก็ไม่มีเหตุผลใด ๆ ที่จะใช้คำนิยามต้นแบบ และสิ่งที่คุณต้องการ - เป็นรูปแบบโมดูล - มีตัวเลือกมากมายให้ดู: addyosmani.com/writing-modular-js
c69

1
หนึ่งเป็นครั้งแรกสำหรับรูปแบบเดี่ยวหนึ่งเคล็ดลับสำหรับผู้ที่ไม่ใช่เดี่ยว (เมื่อ 1 ชั้นสามารถมีวัตถุจำนวนมาก)
Kokizzu

คำตอบ:


6

ความแตกต่างแรกสามารถสรุปได้เป็น: thisหมายถึงอินสแตนซ์ของชั้นเรียน prototypeหมายถึงความหมาย

สมมติว่าเรามีคลาสต่อไปนี้:

var Flight = function ( number ) { this.number = number; };

ดังนั้นที่นี่เราจะแนบthis.numberไปกับทุกตัวอย่างของชั้นเรียนและมันก็สมเหตุสมผลเพราะทุกคนFlightควรมีหมายเลขเที่ยวบินของตัวเอง

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

ในทางตรงกันข้ามprototypeกำหนดคุณสมบัติเดียวที่สามารถเข้าถึงได้โดยทุกกรณี

ตอนนี้ถ้าเราต้องการรับหมายเลขเที่ยวบินเราสามารถเขียนตัวอย่างต่อไปนี้และอินสแตนซ์ทั้งหมดของเราจะได้รับการอ้างอิงไปยังวัตถุต้นแบบใหม่นี้

Flight.prototype.getNumber = function () { return this.number; };

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

แต่นั่นจะเกิดขึ้นเฉพาะกับคุณสมบัติต้นแบบ ดังนั้นหากคุณมีที่ใดที่หนึ่งในระดับที่สูงกว่าthis.whateverJavaScript จะไม่พิจารณาว่าเป็นการจับคู่และจะทำการค้นหาต่อไป

เรามาดูกันว่ามันเกิดขึ้นจริงอย่างไร

โปรดทราบว่า [เกือบ] ทุกอย่างเป็นวัตถุใน JavaScript ลองสิ่งนี้:

typeof null

ทีนี้เรามาดูกันว่ามีอะไรอยู่ในตัวObject(หมายเหตุตัวพิมพ์ใหญ่Oและตัว.สุดท้าย) ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของ Google Chrome เมื่อคุณป้อน.คุณจะได้รับรายการคุณสมบัติที่มีอยู่ภายในวัตถุนั้น

Object.

ตอนนี้ทำสิ่งเดียวกันสำหรับFunction:

Function.

คุณอาจสังเกตเห็นnameวิธีการ เพียงไปและยิงมันขึ้นมาและดูว่าเกิดอะไรขึ้น:

Object.name
Function.name

ตอนนี้มาสร้างฟังก์ชั่น:

var myFunc = function () {};

และลองดูว่าเรามีnameวิธีที่นี่ด้วยหรือไม่:

myFunc.name

คุณควรได้รับสตริงที่ว่างเปล่า แต่ก็ไม่เป็นไร คุณไม่ควรได้รับข้อผิดพลาดหรือข้อยกเว้น

ตอนนี้เราจะเพิ่มบางสิ่งลงในสิ่งที่คล้ายกับพระเจ้าObjectและดูว่าเราได้มันมาในที่อื่นด้วยหรือไม่?

Object.prototype.test = "Okay!";

และไปที่นั่น:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

"Okay!"ในทุกกรณีที่คุณควรจะเห็น

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

ทั้งหมดนั้นกล่าวว่าทั้งสองวิธีเป็นเพียงเครื่องมือทางภาษาและขึ้นอยู่กับคุณและปัญหาที่คุณพยายามแก้ไขเพื่อเลือกสิ่งที่เหมาะสมยิ่งขึ้น

thisถ้าคุณจะต้องมีคุณสมบัติที่จะมีความเกี่ยวข้องกับตัวอย่างของการเรียนทุกการใช้งานแล้ว prototypeถ้าคุณจะต้องมีคุณสมบัติที่จะทำงานเหมือนกันในทุกกรณีแล้วการใช้งาน

ปรับปรุง

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

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

ตัวอย่างข้อมูลที่สองของคุณไม่ได้ทำให้ความรู้สึกมากเพราะเป็นครั้งแรกที่คุณใช้thisและต่อมาคุณกำลังพยายามที่จะตัดมันด้วยprototypeซึ่งไม่ได้เพราะต้องใช้ความสำคัญมากกว่าthis prototypeฉันไม่แน่ใจว่าคุณคาดหวังอะไรจากโค้ดส่วนนั้นและวิธีการทำงาน แต่ฉันขอแนะนำให้คุณปรับโครงสร้างใหม่

ปรับปรุง

ในการอธิบายอย่างละเอียดเกี่ยวกับthisการมีความสำคัญเหนือกว่าprototypeฉันสามารถแสดงตัวอย่างและบอกคุณว่ามันสามารถอธิบายได้อย่างไร แต่ฉันไม่มีทรัพยากรภายนอกที่จะสำรอง

ตัวอย่างง่ายมาก:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

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


นี่เป็นคำตอบที่ยอดเยี่ยมบางส่วน! คุณสามารถแก้ไขและเข้าไปดูรายละเอียดเพิ่มเติมเปรียบเทียบและตัดกันทั้งสองวิธีได้หรือไม่? สองย่อหน้าแรกของคุณทำให้ฉันสับสนซึ่งวิธีการออกแบบที่คุณอ้างถึง การออกกำลังกายของคุณยอดเยี่ยม! ฉันไม่เคยคิดมากกับพลังของการทำต้นแบบเช่นนั้น คุณสามารถให้ตัวอย่างการใช้รายละเอียดกึ่งกรณีเมื่อใช้แต่ละวิธีได้หรือไม่? ขอบคุณอีกครั้งนี่เยี่ยมมาก
JDillon522

@ JDillon522 ดีใจที่ได้ยินเช่นนั้น ฉันจะพยายามอัปเดตในอีกไม่กี่ชั่วโมงข้างหน้า!
53777A

@ JDillon522 เพิ่งทำการอัพเดทอย่างรวดเร็ว หวังว่ามันจะชัดเจนขึ้นในเวลานี้
53777A

@ JDillon522 ข้อมูลตัวอย่างของคุณเพิ่มเติมเล็กน้อย ...
53777A

ตัวอย่างของซิงเกิลที่ดี ดังนั้นฉันใช้thisในตัวอย่างต้นแบบเซ่อเพราะthisอ้างถึงคุณสมบัติของตัวเองรวมถึงวิธีการ ฉันไม่ได้เรียนรู้ที่ดีที่สุดจากการอ่านเกี่ยวกับโค้ด แต่เพิ่มเติมจากการดูโค้ด ( บิต MDN ของมัน , วัตถุสนามเด็กเล่น (ที่น่าตื่นตาตื่นใจ)และอื่น ๆ ไม่กี่) คุณสามารถชี้ไปที่สิ่งที่อธิบายความหมายของคำว่า "ให้thisความสำคัญมากกว่าprototype" ได้หรือไม่? ฉันอยากจะดูมันมากกว่านี้
JDillon522
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.