Namespace در جاوا اسکریپت - بررسی مفاهیم پایه
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 8 دقیقه

Namespace در جاوا اسکریپت - بررسی مفاهیم پایه

هنگامی که شروع به ساختن برنامه‌های پیچیده می‌کنید، عوامل مختلفی وجود دارد که باید آنها را در نظر بگیرد. یکی از این عوامل سازماندهی کد است. اگرچه ممکن است ارزش سازماندهی کد را هنگامی که برنامه‌های شما کوچک هستند درک نکنید اما وقتی برنامه‌هایتان پیچیده می‌شوند، اهمیت کد سازمان یافته را می‌دانید. یکی از تکنیک‌های دستیابی به سازماندهی کد namespacing نام دارد. Namespace به شما کمک می‌کند تا از برخورد با اشیا یا متغیرهای دیگر در فضای نام گلوبال جلوگیری کنید. این یک مشکل معمول هنگام کار با چندین توسعه دهنده و کتابخانه است.

فضای نام در جاوا اسکریپت

فضای نام در یک برنامه در سطح سازمانی ضروری است؛ زیرا شما چندین اسکریپت شخص ثالث را ادغام خواهید کرد که ممکن است در پایان از نام متغیر یا متد مشابه شما استفاده کنند. این امر منجر به شکستن کد شما می‌شود، به این دلیل که متغیرها و متدهای شما رونویسی می‌شوند.

لازم به ذکر است که بر خلاف چندین زبان برنامه نویسی دیگر مانند سی پلاس پلاس، جاوا اسکریپت از فضای نام به صورت out-of-the-box پشتیبانی نمی‌کند. اما به دلیل اهمیت این ویژگی، توسعه دهندگان از الگوهای namespacing برای دستیابی به فضای نام در جاوا اسکریپت با کمک اشیا و کلوزرها استفاده می‌کنند.

در این مقاله فقط به الگوهای اساسی فضای نام در جاوا اسکریپت پرداخته شده است. برای الگوهای متوسط ​​و پیشرفته‌تر توصیه می‌کنم کتاب Addy Osmani تحت عنوان یادگیری الگوهای طراحی جاوا اسکریپت را مطالعه کنید.

بیایید نگاهی به این الگوها بیندازیم.

متغیرهای واحد گلوبال

این یکی از اساسی‌ترین و معمول‌ترین رویکردها است. این روش از یک متغیر گلوبال به عنوان نقطه مرجع شما استفاده می‌کند. در نتیجه به متدها و متغیرهای خود به عنوان خصوصیات این شی دسترسی خواهید داشت.

var sampleApplication = (() => {
  var value = 0;

  function add() {
    value++;
    console.log(value);
  }

  function minus() {
    value--;
    console.log(value);

  }

  function getValue() {
    return value;
  }

  return {
    add: add,
    minus: minus,
    getValue: getValue
  }
})();

console.log(sampleApplication);

sampleApplication.add();//1
sampleApplication.add();//2
sampleApplication.minus();//1
console.log(sampleApplication.getValue());//1

قطعه کد فوق یک شی را با ارجاع به توابع از IIFE برمی‌گرداند.

یکی از مشکلات رایج الگوی فوق این است که مطمئن شوید هیچ کس دیگری از همان متغیر گلوبال ما استفاده نمی‌کند. اگر شخص دیگری نیز از همان متغیر گلوبال در متن خود استفاده کند، متغیر گلوبال ما به راحتی رونویسی می‌شود.

الگوی بعدی راه حلی برای این چالش ارائه می‌دهد.

الگوی متغیر واحد گلوبال نیز می‌تواند با استفاده نادرست از این کلمه کلیدی مشکلاتی را ایجاد کند.

var myApp = {};

myApp.message = 'hello';

myApp.sayHello = function() {
  alert(this.message);
};

myApp.sayHello() // works because "this" refers to myApp object.

var importedfn = myApp.sayHello;

importedfn(); // error because "this" refers to global object.

همانطور که در زیر نشان داده شده است می‌توانید از تابع call برای فراخوانی تابع sayHello با مقادیر مناسب برای این کار استفاده کنید.

var myApp = {};

myApp.message = 'hello';

myApp.sayHello = function() {
  alert(this.message);
};

myApp.sayHello() // works because "this" refers to myApp object.

var importedfn = myApp.sayHello;

importedfn.call(myApp); // works because "this" refers to myApp object.

فضای نام پیشوند

به عنوان راه حلی برای مسئله فوق، پیتر مایكو مفهومی به نام Prefix Namespacing را معرفی كرد. این یک مفهوم کاملا ساده است که نسخه گستردهای از الگوی متغیر واحد گلوبال می‌باشد. در الگوی فضای نام پیشوند مانند قبل از متغیر منحصر به فرد گلوبال استفاده می‌کنیم، اما با یک زیرخط (underline) بعد از متد یا نام خصوصیت. این در پایان با یک متغیر گلوبال چند متغیر مطابق مثال قبلی به عنوان SampleApplication_value ،sampleApplication_add() ، ()sampleApplication_minus نام گذاری می‌شود.

فضای نام پیشوند تقریبا در C نیز مورد استفاده قرار می‌گیرد. همچنین این را می‌توان در جاوا اسکریپت در توابع MM_ Macromedia یافت.

یکی از مواردی که در مورد این الگو وجود دارد این است که وقتی برنامه شما بزرگتر شود با چندین متغیر گلوبال مواجه خواهید شد که ممکن است در نسخه‌های قبلی برخی از مرورگرها مشکل ایجاد کند، زیرا سازگاری آنها با تعداد زیادی از متغیرهای گلوبال ضعیف است.

علامت گذاری متنی شی

این مفهوم را می‌توان به عنوان یک شی ساده در نظر گرفت که شامل مجموعه‌ای از جفت‌های key-value است. این جفت‌های key-value می‌توانند خود حاوی فضاهای نام جدید باشند. با این کار می‌توانید بدون آلودگی محیط گلوبال، کد خود را به صورت منطقی سازماندهی کنید. سینتکس آنها به راحتی قابل درک است و زمینه را برای گسترش فضاهای نام با سهولت فراهم می‌کند.

var sampleApplication = {
  properties: {

  },
  //can also populate nested namespaces
  utils: {
    methods: {

    }
  },
  services: {

  }
};

علاوه بر این می‌توانید با دسترسی مستقیم به شی sampleApplication، مستقیما این جفت‌های key-value را اختصاص دهید.

var sampleApplication = {

};

sampleApplication.properties = {

};

sampleApplication.utils = {
	methods:{
    	
    }
};

همچنین باید مطمئن شوید که متغیر گلوبال در جای دیگری تعریف نشده است. اگر تعریف شده باشد، حتما از آن متغیر استفاده کنید. در غیر این صورت آن را در یک شی خالی مقداردهی اولیه کنید.

بیشتر توسعه دهندگان از هر یک از روش‌های زیر برای بررسی وجود متغیر در دامنه گلوبال استفاده می‌کنند.

//Method 1
var sampleApplication = sampleApplication || {};

//Method 2
if(!sampleApplication){
	sampleApplication = {};
}

یک عیب این روش آن است که سینتکس شی وقتی طولانی‌تر می‌شود که برنامه شما بزرگتر باشد.

فضای نام تو در تو

الگوی Nested Namespacing نسخه گسترده‌ای از الگوی Notebook Literal Object است. این می‌تواند به فضاهای نام شما کمک کند تا چندین فضای نامی درون خود جای دهند و در نتیجه کد شما به طور منطقی سازمان یافته باشد.

همانطور که در الگوهای قبلی نیز مشاهده شد، باید قبل از دسترسی به متغیرهای خود مقداردهی اولیه شوند. همچنین لازم به ذکر است که یک فضای نامی سطح 2 باید تعریف شود تا فضای نام سطح 3 تعریف یا مقداردهی اولیه شود. در غیر این صورت یک خطای نوع دریافت خواهید کرد که نمی‌تواند ویژگی undefined را تنظیم کند.

همچنین می‌توانید مقادیر را با استفاده از علامت براکت تعریف کنید. این علامت گذاری به شما امکان می‌دهد از متغیرها برای دسترسی به خصوصیات شی استفاده کنید.

var sampleApplication = sampleApplication || {};

sampleApplication["properties"] = sampleApplication["properties"] || {};

sampleApplication["utils"] = sampleApplication["utils"] || {};

sampleApplication["utils"]["methods"] = sampleApplication["utils"]["methods"] || {};

sampleApplication["services"] = sampleApplication["services"] || {};

ممکن است از خود بپرسید که آیا دسترسی به اشیا کاملا تو در تو می‌تواند بر عملکرد برنامه تأثیر بگذارد. به عنوان مثال دسترسی به یک تابع متعلق به یک فضای نامی که چندین سطح زیر آن قرار دارد، نسبت به دسترسی به یک تابع در سطح 1 زمان بیشتری می‌برد. اما به گفته Addy توسعه دهندگانی قبلا تست کرده‌اند و دریافته‌اند که این تفاوت قابل چشم پوشی است. 

عبارات فراخوانی بلافاصله تابع (IIFE)

عبارت بلافاصله فراخوانی شده یک تابع جاوا اسکریپت است که به محض تعریف اجرا می‌شود. IIFEها کاربردهای مختلفی دارند از جمله ویژگی‌ها و متدهای خصوصی، نام مستعار و موارد دیگر.

می‌توانید برای کسب اطلاعات بیشتر درباره IIFEها این مقاله را بخوانید.

استفاده مهم دیگر از IIFEها این است که فضای نام را نیز فراهم می‌کنند. ما می‌توانیم شی namespace را به عنوان یک پارامتر به IIFE منتقل کنیم و خصوصیات عمومی را نیز مانند شکل زیر به این شی اختصاص دهیم. همچنین می‌توانید این مثال را گسترش دهید تا شامل خصوصیات عمومی / خصوصی فضای نام باشد.

((namespace) => {

  namespace.properties = namespace.properties || {};
  
  namespace.utils = namespace.utils || {};
  
  namespace["utils"]["methods"] = namespace["utils"]["methods"] || {};
  
})(sampleApplication);

console.log(sampleApplication);

علاوه بر این با دنبال کردن این الگو نیز می‌توانید به راحتی خصوصیات / توابع اضافی را به فضای نام خود اضافه کنید. تمام کاری که شما باید انجام دهید این است که یک فضای نام موجود را به عنوان پارامتر به IIFE منتقل کنید و خصوصیات عمومی را به آن اضافه کنید.

تزریق فضای نام

این الگو توسعه یافته الگوی IIFE است. در این الگو ما متدها و خصوصیات یک فضای نام خاص را از داخل یک تابع با استفاده از this به عنوان پروکسی فضای نام "تزریق" می‌کنیم.

این الگو اِعمال رفتار عملکردی در چندین فضای نام و حتی اِعمال متدهای پایه مانند getterها، setterها و toString را که بعدا قابل ساخت است، آسان می‌کند.

اما برای دستیابی به همان هدف گسترش عمیق فضای نام، رویکردهای راحت‌تر و بهینه‌تری وجود دارد که قبلا در مورد آن بحث کردیم.

var sampleApplication = {};

(function ()  {

  this.properties = this.properties || {};
  
  this.utils = this.utils || {};
  
  this.services = this.services || {};
  
}).apply(sampleApplication);

(function ()  {

  this.tools = this.tools || {};
  
}).apply(sampleApplication.utils);

فضای نام یکی از ویژگی‌های مورد انتظار جاوا اسکریپت بوده که هنوز به صورت out-of-the-box پشتیبانی نشده است. اما با در دسترس بودن آبجکت‌ها و کلوزرها در جاوا اسکریپت، توانستیم به هدف فضاهای نام دست پیدا کنیم. اگرچه ماژول‌های ES6 فضای نام را تقریبا منسوخ کرده‌اند، اما برای کار با برنامه‌های قدیمی و مرورگرهای پشتیبانی نشده هنوز باید آنها را بشناسید.

این مقاله فقط مقدمه‌ای برای فضاهای نامی جاوا اسکریپت است، زیرا من فقط در مورد الگوهای اساسی فضای نام‌ها طبق کتاب Addy بحث کرده‌ام. در نهایت به شما توصیه می‌کنم برای درک کلی فضاهای نام در جاوا اسکریپت منابع زیر را نیز بررسی کنید.

Essential JS Design Patterns

JS Tutorials

GeeksforGeeks

منبع

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
3 از 2 رای

/@erfanheshmati
عرفان حشمتی
Full-Stack Web Developer

کارشناس معماری سیستم های کامپیوتری، طراح و توسعه دهنده وب سایت، تولیدکننده محتوا

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید