รูปแบบโมดูล JavaScript พร้อมตัวอย่าง [ปิด]


136

ฉันไม่พบตัวอย่างใด ๆ ที่สามารถเข้าถึงได้ซึ่งแสดงว่าโมดูลที่แตกต่างกันสองโมดูล (หรือมากกว่า) เชื่อมต่อเพื่อทำงานร่วมกันได้อย่างไร

ดังนั้นฉันอยากถามว่าใครมีเวลาเขียนตัวอย่างอธิบายว่าโมดูลทำงานร่วมกันได้หรือไม่


นี้มีการเปลี่ยนแปลงทั้งหมดในช่วงสี่ปี แต่ขอบคุณที่กระตือรือร้นมากกว่าปริมาณที่พอเหมาะนี้ข้อมูลออกจากวันที่จะไปไหนมาไหนตลอดไป นี่คือหน้าของ MDNในโมดูล ES6
bbsimonbb

คำตอบ:


256

เพื่อที่จะเข้าใกล้รูปแบบการออกแบบ Modular คุณต้องเข้าใจแนวคิดเหล่านี้ก่อน:

ฟังก์ชั่นการแสดงออกทันที (IIFE):

(function() {
      // Your code goes here 
}());

คุณสามารถใช้ฟังก์ชันได้สองวิธี 1. การประกาศฟังก์ชั่น 2. การแสดงออกฟังก์ชั่น

นี่คือการใช้ฟังก์ชั่นการแสดงออก

เนมสเปซคืออะไร ตอนนี้ถ้าเราเพิ่มเนมสเปซไปที่ส่วนบนของรหัสแล้ว

var anoyn = (function() {
}());

การปิดบัญชีใน JS คืออะไร

มันหมายความว่าถ้าเราประกาศฟังก์ชั่นใด ๆ ที่มีขอบเขตตัวแปร / ภายในฟังก์ชั่นอื่น (ใน JS เราสามารถประกาศฟังก์ชั่นภายในฟังก์ชั่นอื่น!) จากนั้นมันจะนับขอบเขตของฟังก์ชั่นนั้นเสมอ ซึ่งหมายความว่าตัวแปรใด ๆ ในฟังก์ชั่นด้านนอกจะถูกอ่านเสมอ มันจะไม่อ่านตัวแปรทั่วโลก (ถ้ามี) ที่มีชื่อเดียวกัน นี่เป็นหนึ่งในวัตถุประสงค์ของการใช้รูปแบบการออกแบบแบบแยกส่วนเพื่อหลีกเลี่ยงความขัดแย้งในการตั้งชื่อ

var scope = "I am global";
function whatismyscope() {
    var scope = "I am just a local";
    function func() {return scope;}
    return func;
}
whatismyscope()()

ตอนนี้เราจะใช้แนวคิดทั้งสามที่ฉันกล่าวถึงข้างต้นเพื่อกำหนดรูปแบบการออกแบบโมดูลาร์แรกของเรา:

var modularpattern = (function() {
    // your module code goes here
    var sum = 0 ;

    return {
        add:function() {
            sum = sum + 1;
            return sum;
        },
        reset:function() {
            return sum = 0;    
        }  
    }   
}());
alert(modularpattern.add());    // alerts: 1
alert(modularpattern.add());    // alerts: 2
alert(modularpattern.reset());  // alerts: 0

jsfiddle สำหรับโค้ดด้านบน

มีวัตถุประสงค์เพื่อซ่อนการเข้าถึงตัวแปรจากโลกภายนอก

หวังว่านี่จะช่วยได้ โชคดี.


มันจะดีกว่าไหมถ้าตั้งชื่อ iife สำหรับวัตถุประสงค์ทางความหมายและการติดตามสแต็กที่ดีขึ้น? มันจะเปลี่ยนแปลงอะไรในรหัสหรือไม่
Jeroen

2
ตัวอย่างแรกของคุณ(function() { /* Your code goes here */}());คือ IIFE (เรียกใช้ฟังก์ชั่นการแสดงออกทันที) ตกลงเพราะไม่ระบุชื่อเพราะไม่มีชื่อดังนั้นคุณอาจต้องการเรียกว่า IIAFE (เรียกใช้ฟังก์ชั่นนิรนามที่ไม่ระบุชื่อทันที) ดูเพิ่มเติมเกี่ยวกับ IIFE ในstackoverflow.com/questions/ 2421911 / …
Adrien เป็น

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

ตัวอย่างที่สองของคุณดูเหมือนว่าวัตถุหรือฉันไม่ถูกต้อง?
เหตุผลที่

4
นี่ไม่ได้ตอบคำถามของ OP มันเป็นคำอธิบายของรูปแบบของโมดูลไม่ใช่ตัวอย่างของวิธีที่หลายโมดูลสามารถทำงานร่วมกันได้ตามที่ต้องการ
Erik Trautman

39

ฉันอยากจะแนะนำให้ทุกคนที่เข้ามาในหัวข้อนี้เพื่ออ่านหนังสือฟรีของ Addy Osmani:

"การเรียนรู้รูปแบบการออกแบบจาวาสคริปต์"

http://addyosmani.com/resources/essentialjsdesignpatterns/book/

หนังสือเล่มนี้ช่วยฉันได้อย่างมากเมื่อฉันเริ่มเขียน JavaScript ที่บำรุงรักษาได้ดีกว่าและฉันก็ยังใช้เป็นข้อมูลอ้างอิง ดูการใช้งานรูปแบบโมดูลที่แตกต่างกันของเขาเขาอธิบายได้ดีจริงๆ


ฉันขอแนะนำให้อ่านบทความของฉันเกี่ยวกับ "Definitive Module Pattern" ซึ่งไม่ครอบคลุมในหนังสือของ Addy Osmani: github.com/tfmontague/definitive-module-pattern
tfmontague

1
สิ่งนี้เปรียบเทียบกับ "รูปแบบ JavaScript" โดย Stoyan Stefanov
JohnMerlino

4
หนังสือของ Stoyan นั้นครอบคลุมมากขึ้น มันครอบคลุมมากกว่ารูปแบบระดับสูง แต่ยังพูดถึงเชิงลึกเพิ่มเติมเกี่ยวกับวิธีปฏิบัติที่ดีที่สุดของ JS อื่น ๆ
รหัสใหม่เริ่ม

1
ความคิดเห็นเกี่ยวกับ "รูปแบบการออกแบบ JavaScript การเรียนรู้" amazon.com/product-reviews/1449331815
Adrien เป็น

3
ความคิดเห็นของ "รูปแบบ JavaScript" โดย Stoyan Stefanov amazon.com/product-reviews/0596806752 หมายเหตุ: ซึ่งดูเหมือนจะดีกว่าหนึ่งใน "รูปแบบการออกแบบ JavaScript การเรียนรู้"
Adrien Be

19

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

ฉันมาจากพื้นหลัง ac # ดังนั้นจึงได้เพิ่มคำศัพท์บางอย่างที่ฉันพบว่ามีประโยชน์จากที่นั่น

html

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

คุณต้องเพิ่มไฟล์ในโครงการด้วยแท็กสคริปต์เช่นนี้:

        <script type="text/javascript" src="app/native/MasterFile.js" /></script>
        <script type="text/javascript" src="app/native/SomeComponent.js" /></script>

ดูเหมือนการยุบแท็กทำให้สิ่งต่าง ๆ ล้มเหลว - ในขณะที่ดูเหมือนว่า xml เป็นสิ่งที่มีกฎ crazier จริงๆ!

ไฟล์เนมสเปซ

MasterFile.js

myAppNamespace = {};

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

Module (s)

SomeComponent.js

myAppNamespace.messageCounter= (function(){

    var privateState = 0;

    var incrementCount = function () {
        privateState += 1;
    };

    return function (message) {
        incrementCount();
        //TODO something with the message! 
    }
})();

สิ่งที่เราทำที่นี่คือการกำหนดฟังก์ชั่นการนับข้อความให้กับตัวแปรในแอปพลิเคชันของเรา มันเป็นฟังก์ชั่นฟังก์ชั่นซึ่งผลตอบแทนที่เราได้ทันทีที่ดำเนินการ

แนวคิด

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

ฉันเพิ่งทำตามขั้นตอนเล็กน้อยในขณะนี้ (ฉันกำลัง refactoring จาวาสคริปต์ปกติจากแอพ extjs เพื่อให้ฉันสามารถทดสอบได้) แต่ดูเหมือนดีมากที่คุณสามารถกำหนดหน่วยการทำงานเล็กน้อยในขณะที่หลีกเลี่ยงการหละหลวมของ'นี้ '

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


6

ที่นี่https://toddmotto.com/mastering-the-module-patternคุณสามารถค้นหารูปแบบที่อธิบายอย่างละเอียด ฉันจะเพิ่มว่าสิ่งที่สองเกี่ยวกับ modular JavaScript คือวิธีการโครงสร้างรหัสของคุณในหลายไฟล์ หลายคนอาจแนะนำคุณที่นี่เพื่อไปกับ AMD แต่ฉันสามารถพูดได้จากประสบการณ์ที่คุณจะจบลงในบางจุดด้วยการตอบสนองหน้าช้าเพราะคำขอ HTTP จำนวนมาก ทางออกคือการรวบรวมโมดูล JavaScript ของคุณล่วงหน้า (หนึ่งไฟล์ต่อไฟล์) เป็นไฟล์เดียวตามมาตรฐาน CommonJS ดูตัวอย่างได้ที่นี่http://dsheiko.github.io/cjsc/


การใช้งานของ AMD ทั้งหมดยังมีการคอมไพล์ล่วงหน้าไว้ในไฟล์เดียว
I-Lin Kuo

1
ถูกต้อง แต่ไฟล์ที่ได้รับการปรับปรุงให้ดีที่สุดนั้นต้องใช้โหลดเดอร์ไลบรารี่ (เพียงตรวจสอบใหม่ด้วย r.js v2.1.14) ซึ่งโดยทั่วไปจะค่อนข้างหนัก ทันทีที่เรามีรหัสที่รวบรวมเราไม่จำเป็นต้องแก้ไขการพึ่งพาโหลดแบบอะซิงโครนัสเราไม่ต้องการไลบรารีนี้ เพียงแค่พิจารณา: เรารวมโมดูลเข้าไปใน AMD นั่นหมายถึง async การโหลดจากนั้นคอมไพล์ไฟล์เหล่านั้นเป็นไฟล์เดียว (ไม่ต้องโหลดแยกต่างหากอีกต่อไป) แต่ให้โหลดทั้งไลบรารีเพื่อระบุที่อยู่ (สิ่งที่ซ้ำซ้อนตอนนี้) มันไม่ได้เป็นวิธีที่ดีที่สุดสำหรับฉัน ทำไมต้อง AMD เมื่อเราไม่โหลดแบบอะซิงโครนัส?
Dmitry Sheiko

almond.js มีตัวโหลดน้ำหนักที่เล็กกว่าสำหรับรหัสการผลิตที่เสร็จสมบูรณ์กว่า RequireJS แต่เมื่อเปรียบเทียบกันแล้วประโยชน์ที่ได้จากการไม่เพียงแค่คำขอ http เดียวไกลเกินกว่าค่าใช้จ่ายในการเพิ่มรหัสโหลดลงในโมดูลดังนั้นในขณะที่มันเหมาะสมที่สุด ในระดับที่เล็กกว่ามาก คำถามในความคิดของฉันควรจะหันไป - ทำไมสันนิษฐานว่าบังเอิญเมื่อเบราว์เซอร์ไม่ได้? จริง ๆ แล้วฉันเห็นว่าทั้ง RequireJS และ CommonJS ควรมีการติดตั้งตามสัญญา
I-Lin Kuo

ทั้งสองรูปแบบเป็นพา ธ ที่ถูกต้องไปยัง CommonJS Modules / 2.0 และให้ความยืดหยุ่นที่เท่ากัน สำหรับฉัน - การจัดการกับ CJS Modules / 1.1 (นั่นคือสิ่งที่ฉันหมายถึงโดย CommonJS) นั้นง่ายกว่ามากรหัสดูสะอาดตา
Dmitry Sheiko

ฉันได้รับประโยชน์จาก AMD เช่น * สามารถโหลดได้มากกว่าไฟล์ JavaScript; นามแฝงเส้นทาง *; CommonJS Compiler แก้ปัญหาเหล่านี้ - มันโหลดการขึ้นต่อกันที่ไม่ใช่ JavaScipt / JSON เป็นข้อมูลและสามารถให้กับการกำหนดค่าการสร้าง (รวมถึงนามแฝง) ข้อเสียเดียวที่ต้องมีการสร้าง แต่ทุกวันนี้ทุกคนสร้างโครงการสำหรับตัวประมวลผลล่วงหน้า CSS อยู่แล้ว ดังนั้นมันเป็นเพียงเกี่ยวกับการเพิ่มงานพิเศษสำหรับ Grunt / อึก ...
Dmitry Sheiko

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.