ฉันจะประกาศเนมสเปซใน JavaScript ได้อย่างไร


990

ฉันจะสร้างเนมสเปซใน JavaScript เพื่อให้วัตถุและฟังก์ชั่นของฉันไม่ได้ถูกเขียนทับโดยวัตถุและฟังก์ชั่นที่มีชื่อเดียวกันอื่น ๆ ได้อย่างไร ฉันใช้สิ่งต่อไปนี้:

if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}

มีวิธีที่สง่างามหรือกระชับกว่านี้หรือไม่?


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

18
ใช้ "namespace" ระดับบนสุด (คุณสมบัติหน้าต่าง) เป็นเจ้าของมัน. ควรตรวจสอบความขัดแย้งก่อนในการทดสอบ อย่ากังวลที่จะเพิ่มการตรวจสอบ "เกิดอะไรขึ้น" เหล่านี้ทั้งหมด เป็นปัญหาที่ร้ายแรงสำหรับ "namespaces" ที่ซ้ำกันและควรได้รับการปฏิบัติเช่นนี้ คุณสามารถทำตามวิธีการเช่น jQuery เพื่ออนุญาตการใช้งาน "namespace" แบบกำหนดเอง แต่นี่ยังเป็นปัญหาของเวลาออกแบบ

กรุณาเปลี่ยนคำตอบที่ได้รับการยอมรับของคุณเพื่อstackoverflow.com/questions/881515/...ซึ่งเป็นวิธีการแก้ปัญหาอื่น ๆ อีกมากมายที่สง่างามและมีการปรับปรุง
hlfcoding

@pst YUI ทำอะไรได้บ้าง ฉันเชื่อว่าพวกเขาทำสิ่งนี้เพื่อเพิ่มเนมสเปซของพวกเขา เทคนิคเช่นนี้จำเป็นสำหรับการทำงานในสภาพแวดล้อม HTTP อย่างแน่นอนหรือไม่
Simon_Weaver

ดูstackoverflow.com/questions/2102591/...สำหรับปัญหาประสิทธิภาพการทำงาน
ทิมอาเบล

คำตอบ:


764

ฉันชอบสิ่งนี้:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();

62
จุดสำคัญคือการนับถือศาสนาเกี่ยวกับการขยายตัวไม่เกินตัวแปรรากเดียว ทุกอย่างต้องไหลจากนี้
annakata

22
สิ่งนี้ไม่ได้สร้างการปิดรหัสของคุณ - มันทำให้การเรียกฟังก์ชั่นอื่น ๆ ของคุณน่าเบื่อเพราะพวกเขาจะต้องมีลักษณะเช่น: yourNamespace.bar (); ฉันทำโครงการที่มาเปิดเพียงเพื่อแก้ไขปัญหาการออกแบบนี้: github.com/mckoss/namespace
mckoss

24
annakata: "จุดสำคัญคือการนับถือศาสนาเกี่ยวกับการขยายตัวไม่เกินตัวแปรรากเดียว" - ทำไมจึงเป็นเช่นนี้?
user406905

11
@alex - ทำไมต้องมีโครงสร้างวัตถุตื้น
Ryan

25
@Ryan ฉันหมายถึงทุกอย่างที่ควรอยู่ภายใต้MyAppเช่นMyApp.Views.Profile = {}มากกว่าและMyApp.users = {} MyViews.Profile = {}ไม่จำเป็นว่าควรมีความลึกสองระดับเท่านั้น
alex

1042

ฉันใช้วิธีการที่พบในไซต์ Enterprise jQuery :

นี่คือตัวอย่างของพวกเขาที่แสดงวิธีประกาศคุณสมบัติและฟังก์ชั่นส่วนตัว & สาธารณะ ทุกสิ่งทุกอย่างเสร็จสิ้นเป็นฟังก์ชั่นที่ไม่เปิดเผยตัว

(function( skillet, $, undefined ) {
    //Private Property
    var isHot = true;

    //Public Property
    skillet.ingredient = "Bacon Strips";

    //Public Method
    skillet.fry = function() {
        var oliveOil;

        addItem( "\t\n Butter \n\t" );
        addItem( oliveOil );
        console.log( "Frying " + skillet.ingredient );
    };

    //Private Method
    function addItem( item ) {
        if ( item !== undefined ) {
            console.log( "Adding " + $.trim(item) );
        }
    }
}( window.skillet = window.skillet || {}, jQuery ));

ดังนั้นหากคุณต้องการให้เป็นหนึ่งในการเข้าถึงของสมาชิกที่สาธารณะคุณก็จะไปหรือskillet.fry()skillet.ingredients

สิ่งที่เจ๋งจริงๆคือตอนนี้คุณสามารถขยายเนมสเปซได้โดยใช้ไวยากรณ์เดียวกัน

//Adding new Functionality to the skillet
(function( skillet, $, undefined ) {
    //Private Property
    var amountOfGrease = "1 Cup";

    //Public Method
    skillet.toString = function() {
        console.log( skillet.quantity + " " +
                     skillet.ingredient + " & " +
                     amountOfGrease + " of Grease" );
        console.log( isHot ? "Hot" : "Cold" );
    };
}( window.skillet = window.skillet || {}, jQuery ));

undefinedอาร์กิวเมนต์ที่สาม

ที่สามอาร์กิวเมนต์เป็นแหล่งที่มาของตัวแปรของค่าundefined undefinedฉันไม่แน่ใจว่ามันยังคงมีความเกี่ยวข้องอยู่หรือไม่ แต่ในขณะที่ทำงานกับเบราว์เซอร์เก่า / มาตรฐาน JavaScript (ecmascript 5, javascript <1.8.5 ~ firefox 4) ตัวแปรขอบเขตทั่วโลกundefinedสามารถเขียนได้ดังนั้นทุกคนสามารถเขียนค่าใหม่ได้ อาร์กิวเมนต์ที่สาม (เมื่อไม่ผ่านค่า) จะสร้างตัวแปรundefinedที่กำหนดขอบเขตไว้ที่เนมสเปซ / ฟังก์ชัน undefinedเพราะไม่มีค่าก็ผ่านไปได้เมื่อคุณสร้างพื้นที่ชื่อเป็นค่าเริ่มต้นค่า


9
+1 สำหรับตัวอย่างที่ยอดเยี่ยมนี้ สำหรับผู้ที่สนใจตัวอย่างนี้เป็นส่วนหนึ่งของการนำเสนอที่ยอดเยี่ยมของ Elijah Manor ที่ Mix 2011 (ไม่สนใจชื่อ) live.visitmix.com/MIX11/Sessions/Speaker/Elijah-Manor
Darren Lewis

11
จากบทความของ Elijah นี่คือข้อดีข้อเสียของวิธีการนี้ถอดความ จุดเด่น: 1. คุณสมบัติและวิธีการของสาธารณะและส่วนตัว, 2. ไม่ใช้ OLN ที่ยุ่งยาก, 3. ป้องกันไม่ได้กำหนด 4. ตรวจสอบให้แน่ใจว่า $ อ้างถึง jQuery, 5. Namespace สามารถขยายไฟล์ได้, จุดด้อย: ยากที่จะเข้าใจมากกว่า OLN
Jared Beck

4
สิ่งนี้เรียกว่าวันนี้IIFE ( เรียกใช้ฟังก์ชั่นการแสดงออกทันที ) ขอบคุณสำหรับคำตอบของคุณ +1!
Gustavo Gondim

20
@CpILL: ไม่แน่ใจว่ายังมีความเกี่ยวข้อง แต่ที่สามอาร์กิวเมนต์เป็นแหล่งที่มาของตัวแปรของค่าundefined undefinedขณะทำงานกับเบราว์เซอร์ / มาตรฐานจาวาสคริปต์ที่เก่ากว่า (ecmascript 5, javascript <1.8.5 ~ firefox 4) ตัวแปรขอบเขตทั่วโลกundefinedสามารถเขียนได้ดังนั้นทุกคนสามารถเขียนค่าใหม่ได้ การเพิ่มอาร์กิวเมนต์ที่สามที่เพิ่มเติมที่คุณไม่ผ่านทำให้มันเป็นค่าundefinedดังนั้นคุณจึงสร้างเนมสเปซ - ขอบเขตundefinedซึ่งจะไม่ถูกเขียนใหม่โดยแหล่งภายนอก
mrówa

4
@SapphireSun ประโยชน์ของwindow.skillet = window.skillet || {}มันคืออนุญาตให้สคริปต์หลาย ๆ ตัวสามารถเพิ่มในเนมสเปซเดียวกันได้อย่างปลอดภัยเมื่อพวกเขาไม่ทราบล่วงหน้าในสิ่งที่พวกเขาจะดำเนินการ สิ่งนี้มีประโยชน์หากคุณต้องการจัดลำดับใหม่ของสคริปต์โดยไม่ทำให้รหัสของคุณเสียหายหรือถ้าคุณต้องการโหลดสคริปต์แบบอะซิงโครนัสกับแอตทริบิวต์ asyncดังนั้นจึงไม่มีการรับประกันเกี่ยวกับลำดับการดำเนินการ ดูstackoverflow.com/questions/6439579/…
ทำเครื่องหมาย Amery

338

อีกวิธีที่จะทำซึ่งฉันคิดว่ามันเป็นข้อ จำกัด น้อยกว่ารูปแบบตัวอักษรของวัตถุคือ:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

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


16
1. มีความแตกต่างระหว่าง OLN และรูปแบบโมดูล 2. ฉันไม่ได้ / เสมอ / ชอบ OLN เพราะคุณต้องจำไว้ว่าอย่าใส่เครื่องหมายจุลภาคต่อท้ายสุดท้ายและแอตทริบิวต์ทั้งหมดของคุณจะต้องเริ่มต้นด้วยค่า (เช่น null หรือไม่ได้กำหนด) นอกจากนี้หากคุณต้องการปิดสำหรับฟังก์ชั่นสมาชิกคุณจะต้องใช้ฟังก์ชั่นโรงงานขนาดเล็กสำหรับแต่ละวิธี อีกสิ่งหนึ่งคือคุณต้องใส่โครงสร้างการควบคุมทั้งหมดของคุณไว้ในฟังก์ชั่นในขณะที่รูปแบบข้างต้นไม่ได้กำหนดไว้ ไม่ได้หมายความว่าฉันไม่ได้ใช้ OLN แต่บางครั้งฉันก็ไม่ชอบมัน
Ionuț G. Stan

8
ฉันชอบวิธีการนี้เพราะจะช่วยให้ฟังก์ชั่นส่วนตัวตัวแปรและค่าคงที่หลอก (เช่น var API_KEY = 12345;)
Lawrence Barsanti

12
ฉันชอบสิ่งนี้ดีกว่าคอนเทนเนอร์วัตถุที่คั่นด้วยเครื่องหมายจุลภาคที่ได้คะแนนสูงกว่า ฉันไม่เห็นข้อบกพร่องใด ๆ ในการเปรียบเทียบเช่นกัน ฉันพลาดอะไรไปรึเปล่า?
Lucent

7
JS Newbie ที่นี่ ... ทำไมถึงไม่ต้องพิมพ์ns().publicFunction()นั่นคือ ... ได้ns.publicFunction()ผล
จอห์นคราฟท์

14
@John Kraft มันเป็นสาเหตุของnewคำหลักที่อยู่ด้านหน้าของfunctionคำหลัก โดยทั่วไปสิ่งที่จะทำก็คือว่ามันประกาศฟังก์ชั่นที่ไม่ระบุชื่อ (และเป็นฟังก์ชั่นก็เป็นเช่นเดียวกับผู้สร้าง) newและมันแล้วทันทีเรียกว่ามันเป็นตัวสร้างโดยใช้ ดังนั้นค่าสุดท้ายที่ถูกเก็บไว้ภายในnsเป็นอินสแตนซ์ (เฉพาะ) ของตัวสร้างแบบไม่ระบุชื่อนั้น หวังว่ามันจะสมเหตุสมผล
Ionuț G. Stan

157

มีวิธีที่สง่างามหรือกระชับกว่านี้หรือไม่?

ใช่. ตัวอย่างเช่น:

var your_namespace = your_namespace || {};

จากนั้นคุณสามารถมี

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}

1
นี่ทำให้ฉันมีข้อผิดพลาดใน IE7 var your_namespace = (พิมพ์ your_namespace == "undefined" ||! your_namespace) หรือไม่ {}: your_namespace; ทำงานได้ดีขึ้น
mjallday

9
ควรเป็น var your_namespace = your_namespace = your_namespace || {} ใช้งานได้ในทุกเบราว์เซอร์)
Palo

+1 จากฉัน! Thin one ทำงานเป็นคำตอบ Jaco Pretorius โดยขยายไลบรารีหนึ่งไปยังไฟล์อื่นหรือสถานที่ต่าง ๆ ภายในไฟล์เดียวกัน ยอดเยี่ยมเพียง!
centurian

2
@Palo คุณช่วยอธิบายได้ไหมว่าทำไมมันควรเป็นเช่นนี้? var your_namespace = your_namespace = your_namespace || {}
ศรีราม

6
คุณจะมีความเป็นไปได้ที่จะขยายวัตถุ your_namespace ในไฟล์ js ที่แตกต่างกัน เมื่อใช้ your_namespace var = {} คุณไม่สามารถทำเช่นนั้นเป็นวัตถุจะถูกแทนที่โดยแต่ละไฟล์
อเล็กซ์ Pacurar

92

ปกติฉันจะสร้างมันในการปิด:

var MYNS = MYNS || {};

MYNS.subns = (function() {

    function privateMethod() {
        // Do private stuff, or build internal.
        return "Message";
    }

    return {
        someProperty: 'prop value',
        publicMethod: function() {
            return privateMethod() + " stuff";
        }
    };
})();

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

var MYNS = MYNS || {};

MYNS.subns = (function() {
    var internalState = "Message";

    var privateMethod = function() {
        // Do private stuff, or build internal.
        return internalState;
    };
    var publicMethod = function() {
        return privateMethod() + " stuff";
    };

    return {
        someProperty: 'prop value',
        publicMethod: publicMethod
    };
})();

ด้วยวิธีนี้ฉันค้นหา API สาธารณะและการใช้งานที่เข้าใจง่ายขึ้น คิดว่าข้อความสั่งคืนเป็นอินเทอร์เฟซสาธารณะสำหรับการนำไปใช้


3
คุณไม่ควรตรวจสอบMYNS.subns = MYNS.subns || {}?
Mirko

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

1
มีคำอธิบายของวิธีการนี้ในหนังสือ "การพูดจาวาสคริปต์" ที่หน้า 412 หากใครมีมันภายใต้หัวข้อ "โมดูลที่รวดเร็วและสกปรก"
Soferio

2
เคล็ดลับการเพิ่มประสิทธิภาพ: ขณะที่var foo = functionและfunction fooคล้ายกันการเป็นส่วนตัว เนื่องจากลักษณะที่มีการพิมพ์แบบไดนามิกของ JavaScript จึงทำให้การพิมพ์เร็วกว่าเล็กน้อยเนื่องจากข้ามคำแนะนำเล็กน้อยในท่อของล่ามส่วนใหญ่ ด้วยvar fooระบบประเภทจะต้องเรียกใช้เพื่อค้นหาประเภทที่ได้รับมอบหมายให้พูดว่า var ในขณะfunction fooที่ระบบประเภทจะรู้ว่ามันเป็นฟังก์ชั่นโดยอัตโนมัติดังนั้นการเรียกฟังก์ชั่นคู่จะถูกข้ามซึ่งแปลเป็นการร้องขอคำสั่ง CPU น้อยลงเช่นjmp, pushq, popqฯลฯ ซึ่งหมายถึงท่อ CPU สั้น
Braden ที่ดีที่สุด

1
@ เบร็ทอุ้ย คุณถูก. ฉันคิดถึงภาษาสคริปต์ที่แตกต่าง แม้ว่าฉันจะยังคงยืนยันว่าfunction fooไวยากรณ์สามารถอ่านได้มากขึ้น และฉันก็ยังชอบเวอร์ชั่นของฉันอยู่
Braden ดีที่สุด

56

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

หนึ่งไฟล์อาจต้องการใช้เนมสเปซnamespace.namespace1:

namespace = window.namespace || {};
namespace.namespace1 = namespace.namespace1 || {};

namespace.namespace1.doSomeThing = function(){}

ไฟล์อื่นอาจต้องการใช้เนมสเปซnamespace.namespace2:

namespace = window.namespace || {};
namespace.namespace2 = namespace.namespace2 || {};

namespace.namespace2.doSomeThing = function(){}

ไฟล์สองไฟล์นี้สามารถอยู่ด้วยกันหรือแยกกันโดยไม่เกิดการชนกัน


1
ฉันพบว่านี่เป็นวิธีที่มีประโยชน์มากสำหรับการจัดระเบียบสคริปต์ไคลเอ็นต์เป็นหลายไฟล์ในแอปพลิเคชันขนาดใหญ่ที่จำเป็นต้องใช้ฟังก์ชั่นแบบแยกส่วน
DVK

คำถามที่ถามถึงไฟล์หลายไฟล์โดยเฉพาะ: stackoverflow.com/questions/5150124/…
Ciro Santilli 冠状病毒审查审查六四事件法轮功

48

นี่คือวิธีที่ Stoyan Stefanov ทำไว้ในหนังสือรูปแบบ JavaScriptซึ่งฉันพบว่าเป็นสิ่งที่ดีมาก (มันแสดงให้เห็นว่าเขาแสดงความคิดเห็นที่อนุญาตสำหรับเอกสาร API ที่สร้างขึ้นโดยอัตโนมัติได้อย่างไรและวิธีเพิ่มวิธีลงในต้นแบบต้นแบบของวัตถุที่กำหนดเอง):

/**
* My JavaScript application
*
* @module myapp
*/

/** @namespace Namespace for MYAPP classes and functions. */
var MYAPP = MYAPP || {};

/**
* A maths utility
* @namespace MYAPP
* @class math_stuff
*/
MYAPP.math_stuff = {

    /**
    * Sums two numbers
    *
    * @method sum
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} Sum of the inputs
    */
    sum: function (a, b) {
        return a + b;
    },

    /**
    * Multiplies two numbers
    *
    * @method multi
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} The inputs multiplied
    */
    multi: function (a, b) {
        return a * b;
    }
};

/**
* Constructs Person objects
* @class Person
* @constructor
* @namespace MYAPP
* @param {String} First name
* @param {String} Last name
*/
MYAPP.Person = function (first, last) {

    /**
    * First name of the Person
    * @property first_name
    * @type String
    */
    this.first_name = first;

    /**
    * Last name of the Person
    * @property last_name
    * @type String
    */
    this.last_name = last;
};

/**
* Return Person's full name
*
* @method getName
* @return {String} First name + last name
*/
MYAPP.Person.prototype.getName = function () {
    return this.first_name + ' ' + this.last_name;
};

32

ฉันใช้วิธีนี้:

var myNamespace = {}
myNamespace._construct = function()
{
    var staticVariable = "This is available to all functions created here"

    function MyClass()
    {
       // Depending on the class, we may build all the classes here
       this.publicMethod = function()
       {
          //Do stuff
       }
    }

    // Alternatively, we may use a prototype.
    MyClass.prototype.altPublicMethod = function()
    {
        //Do stuff
    }

    function privateStuff()
    {
    }

    function publicStuff()
    {
       // Code that may call other public and private functions
    }

    // List of things to place publically
    this.publicStuff = publicStuff
    this.MyClass = MyClass
}
myNamespace._construct()

// The following may or may not be in another file
myNamespace.subName = {}
myNamespace.subName._construct = function()
{
   // Build namespace
}
myNamespace.subName._construct()

รหัสภายนอกสามารถเป็น:

var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);

รายละเอียดยอดเยี่ยม! ขอบคุณ! เพียงแค่สงสัยว่าสิ่งที่คุณใช้กับ Namespace.js ฉันไม่เคยใช้มันด้วยตัวเองดังนั้นฉันจึงสงสัยว่าคนที่มีความรู้ / ทักษะ / ประสบการณ์ของคุณจะพิจารณาใช้มันหรือไม่
จอห์น

ฉันชอบมัน! ในขณะที่ฉันได้รับข้อยกเว้นในบรรทัดแรกของรหัสภายนอกนี้พูดว่า: 'myNameSpace.MyClass' [undefined] ไม่ใช่ตัวสร้าง อาจจะขึ้นอยู่กับการติดตั้ง JS? : /
yoosiba

@yossiba: อาจเป็นไปได้ รหัสข้างต้นเป็นสิ่งที่ค่อนข้างมาตรฐาน ใน JS มาตรฐานฟังก์ชั่นใด ๆ ที่สามารถใช้เป็นตัวสร้างไม่มีอะไรที่คุณต้องทำเพื่อทำเครื่องหมายฟังก์ชั่นเป็นพิเศษสำหรับการใช้เป็นตัวสร้าง คุณใช้รสชาติที่ผิดปกติเช่น ActionScript หรืออะไรบางอย่าง?
AnthonyWJones

@Anthony ดีกว่าที่จะใช้ var MYNAMESPACE = MYNAMESPACE || {}; เพียงแค่ใช้ var myNamespace = {} ไม่ปลอดภัยและนอกจากนี้ยังเป็นการดีกว่าที่จะประกาศเนมสเปซของคุณในรูปแบบตัวพิมพ์ใหญ่
paul

9
@ พอล: "ดีกว่า" สามารถเป็นอัตวิสัยค่อนข้าง ฉันเกลียดการอ่านรหัสที่ SHOUTS ที่ฉันดังนั้นฉันจึงหลีกเลี่ยงการใช้ตัวระบุที่ใช้ตัวพิมพ์ใหญ่ทั้งหมด ในขณะที่ns = ns || {}อาจดูป้องกันมากกว่านั้นสามารถนำไปสู่ผลลัพธ์ที่ไม่คาดคิดอื่น ๆ
AnthonyWJones

32

นี่คือการติดตามลิงก์ของ user106826 ไปยัง Namespace.js ดูเหมือนว่าโครงการย้ายไปGitHub ตอนนี้มันเป็นsmith / namespacedotjs

ฉันใช้ JavaScript ตัวช่วยนี้ง่าย ๆ สำหรับโครงการเล็ก ๆ ของฉันและจนถึงตอนนี้ดูเหมือนว่าจะเบา แต่ก็อเนกประสงค์พอที่จะรองรับการกำหนดเนมสเปซและโหลดโมดูล / คลาส มันจะดีมากถ้ามันจะอนุญาตให้ฉันนำเข้าแพ็คเกจไปยัง namespace ที่ฉันเลือกไม่ใช่แค่ namespace ทั่วโลก ... ถอนหายใจ แต่นั่นเป็นประเด็น

อนุญาตให้คุณประกาศเนมสเปซจากนั้นกำหนดออบเจ็กต์ / โมดูลในเนมสเปซนั้น:

Namespace('my.awesome.package');
my.awesome.package.WildClass = {};

ตัวเลือกอื่นคือการประกาศ namespace และเนื้อหาในครั้งเดียว:

Namespace('my.awesome.package', {
    SuperDuperClass: {
        saveTheDay: function() {
            alert('You are welcome.');
        }
    }
});

สำหรับตัวอย่างการใช้งานมากขึ้นดูที่ example.js แฟ้มในแหล่งที่มา


2
ตราบใดที่คุณจำได้ว่าสิ่งนี้มีผลกระทบต่อประสิทธิภาพการทำงานบางครั้งที่คุณเข้าถึง my.awesome.package.WildClass คุณจะเข้าถึงคุณสมบัติที่ยอดเยี่ยมของฉันคุณสมบัติแพ็กเกจของ my.awesome และคุณสมบัติ WildClass ของ my.awesome บรรจุภัณฑ์
SamStephens

29

ตัวอย่าง:

var namespace = {};
namespace.module1 = (function(){

    var self = {};
    self.initialized = false;

    self.init = function(){
        setTimeout(self.onTimeout, 1000)
    };

    self.onTimeout = function(){
        alert('onTimeout')
        self.initialized = true;
    };

    self.init(); /* If it needs to auto-initialize, */
    /* You can also call 'namespace.module1.init();' from outside the module. */
    return self;
})()

คุณสามารถประกาศlocalตัวแปรsameเช่นเลือกselfและกำหนดlocal.onTimeoutถ้าคุณต้องการให้เป็นส่วนตัว


14

คุณสามารถประกาศฟังก์ชั่นที่เรียบง่ายเพื่อให้ namespaces

function namespace(namespace) {
    var object = this, tokens = namespace.split("."), token;

    while (tokens.length > 0) {
        token = tokens.shift();

        if (typeof object[token] === "undefined") {
            object[token] = {};
        }

        object = object[token];
    }

    return object;
}

// Usage example
namespace("foo.bar").baz = "I'm a value!";

13

หากคุณต้องการขอบเขตส่วนตัว:

var yourNamespace = (function() {

  //Private property
  var publicScope = {};

  //Private property
  var privateProperty = "aaa"; 

  //Public property
  publicScope.publicProperty = "bbb";

  //Public method
  publicScope.publicMethod = function() {
    this.privateMethod();
  };

  //Private method
  function privateMethod() {
    console.log(this.privateProperty);
  }

  //Return only the public parts
  return publicScope;
}());

yourNamespace.publicMethod();

อื่นถ้าคุณจะไม่ใช้ขอบเขตส่วนตัว:

var yourNamespace = {};

yourNamespace.publicMethod = function() {
    // Do something...
};

yourNamespace.publicMethod2 = function() {
    // Do something...
};

yourNamespace.publicMethod();

12

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

เมื่อทำงานกับรูปแบบโมดูลเราอาจพบว่ามีประโยชน์ในการกำหนดแม่แบบง่าย ๆ ที่เราใช้สำหรับเริ่มต้นใช้งาน นี่คือสิ่งที่ครอบคลุมการเว้นวรรคชื่อตัวแปรสาธารณะและส่วนตัว

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

var myNamespace = (function () {

  var myPrivateVar, myPrivateMethod;

  // A private counter variable
  myPrivateVar = 0;

  // A private function which logs any arguments
  myPrivateMethod = function( foo ) {
      console.log( foo );
  };

  return {

    // A public variable
    myPublicVar: "foo",

    // A public function utilizing privates
    myPublicFunction: function( bar ) {

      // Increment our private counter
      myPrivateVar++;

      // Call our private method using bar
      myPrivateMethod( bar );

    }
  };

})();

ข้อดี

ทำไมรูปแบบของโมดูลจึงเป็นตัวเลือกที่ดี? สำหรับผู้เริ่มต้นมันสะอาดกว่าสำหรับนักพัฒนาที่มาจากพื้นหลังเชิงวัตถุมากกว่าแนวคิดของการห่อหุ้มที่แท้จริงอย่างน้อยจากมุมมอง JavaScript

ประการที่สองมันรองรับข้อมูลส่วนตัวดังนั้นในรูปแบบของโมดูลส่วนสาธารณะของรหัสของเราสามารถสัมผัสกับส่วนส่วนตัวได้อย่างไรก็ตามโลกภายนอกไม่สามารถสัมผัสชิ้นส่วนส่วนตัวของชั้นเรียนได้

ข้อเสีย

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

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

รูปแบบโมดูลการเปิดเผย

ตอนนี้เรามีความคุ้นเคยกับรูปแบบของโมดูลเพิ่มขึ้นเล็กน้อยมาดูรุ่นที่ได้รับการปรับปรุงเล็กน้อย - รูปแบบของ Revealing Module ของ Christian Heilmann

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

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

ตัวอย่างของวิธีการใช้รูปแบบการเปิดเผยโมดูลสามารถพบได้ที่ด้านล่าง

var myRevealingModule = (function () {

        var privateVar = "Ben Cherry",
            publicVar = "Hey there!";

        function privateFunction() {
            console.log( "Name:" + privateVar );
        }

        function publicSetName( strName ) {
            privateVar = strName;
        }

        function publicGetName() {
            privateFunction();
        }


        // Reveal public pointers to
        // private functions and properties

        return {
            setName: publicSetName,
            greeting: publicVar,
            getName: publicGetName
        };

    })();

myRevealingModule.setName( "Paul Kinlan" );

ข้อดี

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

ข้อเสีย

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

สมาชิกออบเจกต์สาธารณะที่อ้างถึงตัวแปรส่วนบุคคลจะต้องอยู่ภายใต้กฎการแก้ไขที่ไม่มีการแก้ไขข้างต้น


9

ฉันสร้างเนมสเปซซึ่งได้รับแรงบันดาลใจจากโมดูลของ Erlang มันเป็นวิธีการทำงานที่ดีมาก แต่นั่นเป็นวิธีที่ฉันเขียนโค้ด JavaScript ของฉันในวันนี้

มันให้ปิด namespace ทั่วโลกและแสดงฟังก์ชั่นชุดที่กำหนดไว้ในการปิดที่

(function(){

  namespace("images", previous, next);
  // ^^ This creates or finds a root object, images, and binds the two functions to it.
  // It works even though those functions are not yet defined.

  function previous(){ ... }

  function next(){ ... }

  function find(){ ... } // A private function

})();

8

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

global_namespace.Define('startpad.base', function(ns) {
    var Other = ns.Import('startpad.other');
    ....
});

คำอธิบายของผลประโยชน์อยู่ที่ฉันโพสต์บล็อก คุณสามารถคว้ารหัสที่มาที่นี่

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


1
ฉันได้สร้างเวอร์ชันที่ปรับปรุงแล้ว (2.0) ของไลบรารีเนมสเปซ: code.google.com/p/pageforest/source/browse/appengine/static/src/
......

ลิงก์ทั้งหมดของคุณดูเหมือนจะตาย
snoob dogg

8

ฉันใช้ไวยากรณ์ต่อไปนี้สำหรับเนมสเปซ

var MYNamespace = MYNamespace|| {};

 MYNamespace.MyFirstClass = function (val) {
        this.value = val;
        this.getValue = function(){
                          return this.value;
                       };
    }

var myFirstInstance = new MYNamespace.MyFirstClass(46);
alert(myFirstInstance.getValue());

jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/


8

ฉันไปงานเลี้ยงมา 7 ปีแล้ว แต่ก็ทำงานประมาณ 8 ปีที่ผ่านมา:

เป็นสิ่งสำคัญที่จะสามารถสร้างเนมสเปซที่ซ้อนกันหลายรายการได้อย่างง่ายดายและมีประสิทธิภาพเพื่อให้เว็บแอปพลิเคชันที่ซับซ้อนมีการจัดการและจัดการในขณะที่เคารพเนมสเปซทั่วโลกของ JavaScript .

จากข้างบนนี่เป็นโซลูชันของฉันประมาณปี 2008:

var namespace = function(name, separator, container){
  var ns = name.split(separator || '.'),
    o = container || window,
    i,
    len;
  for(i = 0, len = ns.length; i < len; i++){
    o = o[ns[i]] = o[ns[i]] || {};
  }
  return o;
};

นี่ไม่ใช่การสร้างเนมสเปซ แต่มีฟังก์ชันสำหรับสร้างเนมสเปซ

นี่สามารถย่อให้ย่อขนาดหนึ่งซับ:

var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a;for(d=0,a=e.length;d<a;d++){g=g[e[d]]=g[e[d]]||{}}return g};

ตัวอย่างการใช้งาน:

namespace("com.example.namespace");
com.example.namespace.test = function(){
  alert("In namespaced function.");
};

หรือเป็นคำสั่งเดียว:

namespace("com.example.namespace").test = function(){
  alert("In namespaced function.");
};

จะถูกดำเนินการอย่างใดอย่างหนึ่งเป็น:

com.example.namespace.test();

หากคุณไม่ต้องการการสนับสนุนเบราว์เซอร์รุ่นเก่ารุ่นที่อัปเดตแล้ว:

const namespace = function(name, separator, container){
    var o = container || window;
    name.split(separator || '.').forEach(function(x){
        o = o[x] = o[x] || {};
    });
    return o;
};

ตอนนี้ฉันน่าจะเปิดเผยnamespaceเนมสเปซทั่วโลกด้วยตัวเอง (น่าเสียดายที่ภาษาฐานไม่ได้ให้สิ่งนี้สำหรับเรา!) ดังนั้นโดยทั่วไปฉันจะใช้ตัวเองในการปิดเช่น:

(function(){
	const namespace = function(name, separator, container){
		var o = container || window;
		name.split(separator || '.').forEach(function(x){
			o = o[x] = o[x] || {};
		});
		return o;
	};
	const ns = namespace("com.ziesemer.myApp");
	
	// Optional:
	ns.namespace = ns;
	
	// Further extend, work with ns from here...
}());

console.log("\"com\":", com);

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


2

ฉันชอบวิธีการแก้ปัญหาของ Jaco Pretorius แต่ฉันต้องการทำให้คำหลัก "นี่" มีประโยชน์มากขึ้นโดยการชี้ไปที่วัตถุโมดูล / เนมสเปซ รุ่น skillet ของฉัน:

(function ($, undefined) {

    console.log(this);

}).call(window.myNamespace = window.myNamespace || {}, jQuery);

2

รูปแบบที่ฉันโปรดปรานกลายเป็นเมื่อเร็ว ๆ นี้:

var namespace = (function() {
  
  // expose to public
  return {
    a: internalA,
    c: internalC
  }

  // all private
  
  /**
   * Full JSDoc
   */
  function internalA() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalB() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalC() {
    // ...
  }
  
  /**
   * Full JSDoc
   */
  function internalD() {
    // ...
  }
  
})();

แน่นอนว่าการกลับมาอาจเป็นไปได้ในตอนท้าย แต่ถ้ามีเพียงการประกาศฟังก์ชั่นตามมาเท่านั้นมันง่ายกว่ามากที่จะเห็นว่าเนมสเปซทั้งหมดเกี่ยวกับอะไรและ API ใดที่เปิดเผย

รูปแบบของการใช้การแสดงออกของฟังก์ชั่นในกรณีเช่นนี้ส่งผลให้ไม่สามารถรู้ว่าวิธีการใดที่ถูกเปิดเผยโดยไม่ต้องใช้รหัสทั้งหมด


สวัสดีคุณเรียกฟังก์ชั่นสาธารณะจากตัวอย่างข้อมูลได้อย่างไร ฉันลองแล้วnamespace.a();
olimart

@ Olivier ใช่นั่นคือความคิด แม้ว่าตอนนี้กับ ES6 ฉันมักจะใช้ไวยากรณ์ชวเลขของตัวอักษรวัตถุ ( ponyfoo.com/articles/es6-object-literal-features-in-depth )
Nomaed

2

ฉันคิดว่าคุณทุกคนใช้รหัสมากเกินไปสำหรับปัญหาง่ายๆ ไม่จำเป็นต้องทำธุรกรรมซื้อคืนสำหรับสิ่งนั้น นี่คือฟังก์ชั่นบรรทัดเดียว

namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);

ลองมัน :

// --- definition ---
const namespace = namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window);

// --- Use ----
let myNamespace = namespace("a.b.c");
myNamespace.MyClass = class MyClass {};

// --- see ----
console.log("a : ", a);


1

หากใช้ Makefile คุณสามารถทำได้

// prelude.hjs
billy = new (
    function moduleWrapper () {
    const exports = this;

// postlude.hjs
return exports;
})();

// someinternalfile.js
function bob () { console.log('hi'); }
exports.bob = bob;

// clientfile.js
billy.bob();

ฉันชอบที่จะใช้ Makefile ต่อไปเมื่อฉันไปถึง 1,000 บรรทัดเพราะฉันสามารถคอมเม้นต์โค้ดขนาดใหญ่ได้อย่างมีประสิทธิภาพโดยการลบบรรทัดเดียวใน makefile ทำให้ง่ายต่อการเล่นกับสิ่งของ ด้วยเทคนิคนี้เนมสเปซจะปรากฏเพียงครั้งเดียวในโหมโรงเพื่อให้ง่ายต่อการเปลี่ยนแปลงและคุณไม่จำเป็นต้องทำซ้ำในรหัสห้องสมุด

เชลล์สคริปต์สำหรับการพัฒนาสดในเบราว์เซอร์เมื่อใช้ makefile:

while (true); do make; sleep 1; done

เพิ่มสิ่งนี้เป็นงานสร้าง 'ไป' และคุณสามารถ 'ทำไป' เพื่อให้งานสร้างของคุณอัปเดตตามรหัสของคุณ


1

ค่อนข้างติดตามผลของ Ionu Ion G. คำตอบของ Stan แต่แสดงประโยชน์ของโค้ดที่กระจายตัวโดยใช้var ClassFirst = this.ClassFirst = function() {...}ซึ่งใช้ประโยชน์จากขอบเขตการปิด JavaScript ของ JavaScript สำหรับเนมสเปซที่น้อยลงสำหรับคลาสในเนมสเปซเดียวกัน

var Namespace = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 123;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

var Namespace2 = new function() {
    var ClassFirst = this.ClassFirst = function() {
        this.abc = 666;
    }

    var ClassSecond = this.ClassSecond = function() {
        console.log("Cluttered way to access another class in namespace: ", new Namespace2.ClassFirst().abc);
        console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc);
    }
}

new Namespace.ClassSecond()
new Namespace2.ClassSecond()

เอาท์พุท:

Cluttered way to access another class in namespace: 123
Nicer way to access a class in same namespace: 123
Cluttered way to access another class in namespace: 666
Nicer way to access a class in same namespace: 666

1

ฉันได้เขียนไลบรารี namespacing อื่นที่ใช้งานได้มากกว่าเช่นแพ็คเกจ / หน่วยทำในภาษาอื่น อนุญาตให้คุณสร้างแพ็คเกจของรหัส JavaScript และการอ้างอิงแพ็คเกจนั้นจากรหัสอื่น:

ไฟล์ hello.js

Package("hello", [], function() {
  function greeting() {
    alert("Hello World!");
  }
  // Expose function greeting to other packages
  Export("greeting", greeting);
});

ไฟล์ Example.js

Package("example", ["hello"], function(greeting) {
  // Greeting is available here
  greeting();  // Alerts: "Hello World!"
});

ต้องรวมเฉพาะไฟล์ที่สองในหน้า การอ้างอิง (ไฟล์hello.jsในตัวอย่างนี้) จะถูกโหลดโดยอัตโนมัติและวัตถุที่ส่งออกจากการอ้างอิงเหล่านั้นจะถูกใช้เพื่อเติมอาร์กิวเมนต์ของฟังก์ชันการเรียกกลับ

คุณสามารถค้นหาโครงการที่เกี่ยวข้องในแพคเกจ JS


1
@ peter-mortensen การแก้ไขเหล่านี้สำหรับคำตอบของฉันจาก '11 มีความจำเป็นจริงๆหรือไม่? แน่นอนว่าไม่ใช่ความป่าเถื่อนในสิ่งที่คุณกำลังทำอย่าเข้าใจฉันผิด แต่พวกเขาก็ตื้นมาก ฉันต้องการที่จะยังคงเป็นผู้สร้างโพสต์เพียงคนเดียวเว้นแต่คุณจะเพิ่มสิ่งที่ดีจริงๆ
Stijn de Witt


0

นิสัยของฉันคือการใช้ฟังก์ชั่น myName ()เป็นที่เก็บข้อมูลแล้วvar myNameเป็นตัวยึด "เมธอด" ...

ไม่ว่าจะถูกต้องตามกฎหมายเพียงพอหรือไม่เอาชนะฉัน! ฉันใช้ตรรกะ PHP ของฉันตลอดเวลาและทำงานได้ดี : D

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
 (myObj instanceof Function !== false)
 ? Object.create({

     $props: new myObj(),
     fName1: function() { /* code..  */ },
     fName2: function() { /* code ...*/ }
 })
 : console.log('Object creation failed!')
);

if (this !== that) myObj.fName1(); else myObj.fName2();

นอกจากนี้คุณยังสามารถทำได้ในทางกลับกันเพื่อตรวจสอบก่อนการสร้างวัตถุที่ดีกว่ามาก :

function myObj() {
    this.prop1 = 1;
    this.prop2 = 2;
    this.prop3 = 'string';
}

var myObj = (
    (typeof(myObj) !== "function" || myObj instanceof Function === false)
    ? new Boolean()
    : Object.create({
        $props: new myObj(),
        init: function () { return; },
        fName1: function() { /* code..  */ },
        fName2: function() { /* code ...*/ }
    })
);

if (myObj instanceof Boolean) {
    Object.freeze(myObj);
    console.log('myObj failed!');
    debugger;
}
else
    myObj.init();

อ้างอิงถึงสิ่งนี้: JavaScript: การสร้างวัตถุด้วย Object.create ()


0

ใน JavaScript ไม่มีวิธีที่กำหนดไว้ล่วงหน้าเพื่อใช้เนมสเปซ ใน JavaScript เราต้องสร้างวิธีการของเราเองเพื่อกำหนด NameSpaces นี่คือขั้นตอนที่เราปฏิบัติตามในเทคโนโลยี Oodles

การลงทะเบียน NameSpace Following ต่อไปนี้เป็นฟังก์ชั่นในการลงทะเบียนชื่อพื้นที่

//Register NameSpaces Function
function registerNS(args){
 var nameSpaceParts = args.split(".");
 var root = window;

 for(var i=0; i < nameSpaceParts.length; i++)
 {
  if(typeof root[nameSpaceParts[i]] == "undefined")
   root[nameSpaceParts[i]] = new Object();

  root = root[nameSpaceParts[i]];
 }
}

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

registerNS("oodles.HomeUtilities");
registerNS("oodles.GlobalUtilities");
var $OHU = oodles.HomeUtilities;
var $OGU = oodles.GlobalUtilities;

โดยทั่วไปมันจะสร้างโครงสร้าง NameSpaces ของคุณเหมือนด้านล่างในแบ็กเอนด์:

var oodles = {
    "HomeUtilities": {},
    "GlobalUtilities": {}
};

ในฟังก์ชั่นดังกล่าวข้างต้นที่คุณต้องลงทะเบียน namespace ที่เรียกว่าและ"oodles.HomeUtilities" "oodles.GlobalUtilities"ที่จะเรียก namespaces เหล่านี้เราจะทำให้ตัวแปร var เช่น$OHUและ $OGUvar

ตัวแปรเหล่านี้ไม่มีอะไรนอกจากนามแฝงในการทำให้เนมสเปซเป็นจำนวนมาก ตอนนี้เมื่อใดก็ตามที่คุณประกาศฟังก์ชั่นที่เป็นของHomeUtilitiesคุณจะประกาศมันดังต่อไปนี้:

$OHU.initialization = function(){
    //Your Code Here
};

ข้างต้นคือการเริ่มต้นชื่อฟังก์ชั่นและมันจะใส่ลงใน $OHUnamespace และเรียกใช้ฟังก์ชันนี้ได้ทุกที่ในไฟล์สคริปต์ เพียงใช้รหัสต่อไปนี้

$OHU.initialization();

ในทำนองเดียวกันกับ NameSpaces อื่น

หวังว่ามันจะช่วย


0

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

function func1() {
    console.log("This is a first definition");

}
function func1() {
    console.log("This is a second definition");
}
func1(); // This is a second definition

มันมักจะเรียกความหมายฟังก์ชั่นที่สอง ในกรณีนี้เนมสเปซจะแก้ปัญหาการชนกันของชื่อ

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