اگه از کتاب خوشتون اومد به گیتهابمون مراجعه کنین و بهمون ⭐️ بدین. اگر هم قصد مشارکت داشتید همونجا میتونین شروع کنین و ما هم خیلی خوشحال میشیم 😃
لینک گیتهاب ما برای مشارکت برای تولید کتابها: https://github.com/mariotek
میتونین خیلی راحت نسخه آنلاین کتاب استفاده کنین یا اگه به فایل کتاب میخوایین دسترسی داشته باشین، از بخش ریلیزهای گیتهاب به فرمتهای مختلف آخرین نسخه کتاب رو میتونین دریافت کنین.
در ابتدا، ممنونم از شما که با خرید این کتاب بهمون کمک کردین که بتونیم قدمی در راه کمک به افراد نیازمند برداریم و با درآمد حاصل از فروش این کتاب
کمکی هر چند کوچیک در راه مسئولیت اجتماعیمون برداریم، به همدیگه کمک کنیم، با هم مهربونتر باشیم و در کنار هم پیشرفت کنیم.
تشکر گرم من رو، دورادور پذیرا باشین و امیدوارم این کتاب به جهت افزایش دانشتون و کمک به پیشرفت شغلیتون کمکی کرده باشه.
کتابی که پیشروی شماست، حاصل تلاش نه فقط من، بلکه چندین نفر از بهترین و حرفهایترین دوستان بنده هم هست که در اینجا به ترتیب میزان زحمتی که متقبل شدن اسمشونو قید میکنم و کمال تشکر رو ازشون دارم:
جعفررضائی
مهسا مصباح
من جعفررضائی، پلتفرم ماریوتک رو با هدف آموزش اصولی و رایگان، تاسیس کردم و این کتاب هم از مجموعه ماریوتک منتشر میشه. ما ماریوتک رو متعلق به همه میدونیم، پس اگه بعضی تایمهای بیکاری داری که فکر میکنی میتونی باهامون توی این مسیر همراه باشی حتما بهم ایمیل بزن. ایدههای ماریوتک برای افزایش آگاهی و دانش تا حد امکان رایگان خواهد بود و تا به اینجا هم، تنها هزینههای چاپ برداشته شده و مابقی به موسسات خیریه داده شدن.
مطالب این کتاب میتونن تا حد بسیار خوبی دانش شما رو توی مسائل کلیدی مربوط به React.js و کتابخونههای پیرامون اون افزایش بدن. سوالات چالشی و کلیدی مطرح شده توی کتاب اکثرا سوالاتی هستند که توی مصاحبههای استخدامی پرسیده میشن و مسلط بودن به اونا میتونه شانس موفقیت شما برای موقعیتهای شغلی که مدنظر دارین افزایش بده. مطالب این کتاب به دلیل ترجمه بودن تا حد زیادی قابل دستکاری نبودن و سعی شده تا حد امکان حق گردآورنده محفوظ باشه و با نسخه اصلی سورس که توسط Sudheer Jonna جمعآوری شده تفاوت معنایی نداشته باشه. بخشی از مطالب کتاب اصلی به خاطر قدیمی بودن منقضی شده بودن و به عنوان مترجم بخشهای زیادی از نمونه کدها و مطالب قدیمی تصحیح شدند. در آخر، امیدوارم همیشه شاد و خندان و خوشحال باشین. مخلصیم
سازنده آبجکت: سادهترین راه برای ایجاد یه آبجکت خالی استفاده از کلاس Objectـه. در حال حاضر این روش توصیه نمیشه.
const object = new Object();
متد استاتیک create روی Object: متد استاتیک create روی Object با انتقال prototype آبجکت به عنوان پارامتر، یه آبجکت جدید ایجاد میکنه.
const object = Object.create(null);
استفاده از syntax آبجکت: با مقداردهی یه متغیر توسط یه آبجکت ساده داخل syntax آبجکت.
const object = { name: "Ali Karimi", age: 30, };
constructor تابع: هر تابعی که بخوایم رو ایجاد میکنیم و از طریق عملگر new یه نمونه آبجکت جدید میسازیم.
function Person(name) { const object = {}; object.name = name; object.age = 30; return object; } const object = new Person("Ali Karimi");
constructor تابع به همراه prototype شبیه سازنده تابع هستش اما از prototype برای متدها و خصوصیاتشون استفاده میکنه.
function Person() {} Person.prototype.name = "Ali Karimi"; const object = new Person();
این معادل نمونهای هستش که با متد ایجاد آبجکت با prototype تابع ایجاد شده و تابع رو با یه نمونه و پارامترهاش به عنوان آرگومان فراخوانی میکنه.
function func {}; new func(x, y, z);
(یا)
// Create a new instance using function prototype. const newInstance = Object.create(func.prototype) // Call the function const result = func.call(newInstance, x, y, z), // If the result is a non-null object then use it otherwise just use the new instance. console.log(result && typeof result === 'object' ? result : newInstance);
استفاده از کلاسهای ES6: توی ES6 کلمه کلیدی class رو برای ایجاد آبجکتها معرفی کردن.
class Person { constructor(name) { this.name = name; } } const object = new Person("Ali Karimi");
الگو یا پترن Singleton: آبجکتایـه که فقط یه بار قابل نمونهگیری هستش و فراخوانیهای بعدی روی سازندهش همون نمونه اولی رو برمیگردونه و اینطوری میشه مطمئن شد که به طور تصادفی نمونههای مختلف ایجاد نمیشه.
const object = new (function () { this.name = "Ali Karimi"; })();
زنجیره prototype برای ساخت انواع جدیدی از آبجکتها براساس موارد موجود استفاده میشه. این کار شبیه ارث بری توی یه زبان مبتنی بر کلاس هستش. prototype روی نمونه آبجکت از طریق ویژگی Object.getPrototypeOf(object) یا **proto** در دسترسه در حالی که prototype توی عملکرد سازندهها از طریق object.prototype در دسترسه.
متد call: متد call یه تابع با یه مقدار this
و آرگومانهای ارائه شده رو دونه دونه فراخوانی میکنه.
const employee1 = { firstName: "John", lastName: "Rodson", }; const employee2 = { firstName: "Jimmy", lastName: "Baily", }; function invite(greeting1, greeting2) { console.log( greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2 ); } invite.call(employee1, "Hello", "How are you?"); // Hello John Rodson, How are you? invite.call(employee2, "Hello", "How are you?"); // Hello Jimmy Baily, How are you?
متد apply: تابع رو فراخوانی میکنه و بهمون اجازه میده تا آرگومانها رو به عنوان یه آرایه منتقل کنیم.
const employee1 = { firstName: "John", lastName: "Rodson" }; const employee2 = { firstName: "Jimmy", lastName: "Baily" }; function invite(greeting1, greeting2) { console.log( greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2 ); } invite.apply(employee1, ["Hello", "How are you?"]); // Hello John Rodson, How are you? invite.apply(employee2, ["Hello", "How are you?"]); // Hello Jimmy Baily, How are you?
متد bind: یه تابع جدید برمیگردونه، در حالی که بهمون اجازه میده هر تعداد آرگومانی که می خوایم رو توی یه آرایه منتقل کنیم.
const employee1 = { firstName: "John", lastName: "Rodson" }; const employee2 = { firstName: "Jimmy", lastName: "Baily" }; function invite(greeting1, greeting2) { console.log( greeting1 + " " + this.firstName + " " + this.lastName + ", " + greeting2 ); } const inviteEmployee1 = invite.bind(employee1); const inviteEmployee2 = invite.bind(employee2); inviteEmployee1("Hello", "How are you?"); // Hello John Rodson, How are you? inviteEmployee2("Hello", "How are you?"); // Hello Jimmy Baily, How are you?
متدهای call
و apply
تقریباً قابل تعویض هستن. هر دو بلافاصله تابع فعلی رو اجرا میکنن. شما باید تصمیم بگیرین که ارسال آرایه در آرایه آسونتره یا فهرستی از آرگومانهای جدا شده با کاما. باید یادمون باشه که متد call برای کاما (فهرست جدا شده) و apply برای حالت آرایهایـه. در حالی که bind یه تابع جدید ایجاد میکنه و میتونه با دریافت «this» روی اولین پارامتر ارسال شده کانتکست آبجکت جدید ساخته رو تنظیم کنه.
JSON یه قالب داده مبتنی برمتنـه که از syntax آبجکت جاواسکریپت (Javascript objext syntax) پیروی میکنه و توسط Douglas Crockford
رایج شد. کاربردش زمانیـه که بخواییم دادهها رو از طریق شبکه انتقال بدیم و اساسا یه فایل متنی با پسوند .json و نوع MIME از application/json داشته باشیم. اکثرا دو عملیات زیر روی JSON انجام میشه:
تجزیه (Parsing): تبدیل یه رشته به یه آبجکت جاواسکریپت (native Object).
JSON.parse(text);
رشتهسازی (stringify کردن): تبدیل یه آبجکت جاواسکریپت به یه رشته تا بتونه از طریق شبکه منتقل بشه یا یه جایی ذخیره بشه.
JSON.stringify(object);
متد slice عناصر انتخاب شده توی یه آرایه رو به عنوان یه آرایه جدید برمیگردونه. این عناصر رو از اولین آرگومان داده شده انتخاب میکنه و با آرگومان پایانی و اختیاری داده شده بدون در نظر گرفتن آخرین عنصر به پایان میرسونه. اگه آرگومان دوم رو حذف کنیم تا آخر آرایه همه عناصر رو انتخاب میکنه. چند تا مثال در مورد نحوه کارکردش ببینیم:
const arrayIntegers = [1, 2, 3, 4, 5]; const arrayIntegers1 = arrayIntegers.slice(0, 2); // returns [1,2] const arrayIntegers2 = arrayIntegers.slice(2, 3); // returns [3] const arrayIntegers3 = arrayIntegers.slice(4); //returns [5]
نکته: متد slice آرایه اصلی رو تغییر نمیده ولی یه زیرمجموعه به عنوان یه آرایه جدید برمیگردونه.
متد splice برای اضافه کردن یه عنصر به آرایه یا حذف از اون استفاده میشه و مورد یا موارد حذف شده رو برمیگردونه. آرگومان اول موقعیت آرایه رو برای درج یا حذف مشخص میکنه در حالی که آرگومان اختیاری دوم تعداد عناصر برای حذف رو مشخص میکنه و مابقی هر آرگومان اضافهای که به این متد ارسال بشه، به آرایه اضافه میشه. چند تا مثال در مورد نحوه کارکردش ببینیم:
const arrayIntegersOriginal1 = [1, 2, 3, 4, 5]; const arrayIntegersOriginal2 = [1, 2, 3, 4, 5]; const arrayIntegersOriginal3 = [1, 2, 3, 4, 5]; const arrayIntegers1 = arrayIntegersOriginal1.splice(0, 2); // returns [1, 2]; original array: [3, 4, 5] const arrayIntegers2 = arrayIntegersOriginal2.splice(3); // returns [4, 5]; original array: [1, 2, 3] const arrayIntegers3 = arrayIntegersOriginal3.splice(3, 1, "a", "b", "c"); //returns [4]; original array: [1, 2, 3, "a", "b", "c", 5]
نکته: متد splice آرایه اصلی رو اصلاح میکنه یعنی متغیر اصلی رو تحت تاثیر قرار میده و آرایه حذف شده رو برمیگردونه.
slice | splice |
---|---|
آرایه اصلی رو تغییر نمیده (immutable یا تغییرناپذیر) | آرایه اصلی رو تغییر میده (mutable یا تغییرپذیر) |
زیر مجموعه آرایه اصلی رو برمیگردونه | عناصر حذف شده رو به عنوان آرایه برمیگردونه |
برای انتخاب عناصر از آرایه استفاده میشه | برای درج عناصر به آرایه یا حذف از اون استفاده میشه |
آبجکتها شبیه به Mapها هستن(البته خود Map هم آبجکته و اینجا منظور شاعر خود شخص Object رو میگه) از این جهت که هردو بهمون این امکان رو میدن که مقادیر رو روی کلیدهای مشخصی تعریف کنیم، مقادیر رو بازیابی کنیم، کلیدها رو حذف کنیم و ببینیم چیزی توی یه کلید ذخیره شده یا نه. به همین دلیل در طول تاریخ از آبجکتها به عنوان Map و HashMap استفادههای زیادی شده. اما تفاوتهای مهمی وجود داره که استفاده از Map رو توی موارد خاص ارجعیت میده.
کلیدهای یه آبجکت رشتهها و Symbolها هستن، در حالی که برای Map مقادیر مختلفی میتونه وجود داشته باشه که شامل توابع، آبجکتها و هر نوع اولیه دیگهای میشه.
کلیدهای Map مرتب میشن در حالی که کلیدهای اضافه شده به آبجکت اینطوری نیستن. بنابراین موقع تکرار روی اون، آبجکت map کلیدها رو به ترتیب اضافه شدنشون برمیگردونه.
اندازه Map رو میتونیم به راحتی با ویژگی سایز بدست بیاریم، در حالی که تعداد خصوصیات یه آبجکت باید به صورت دستی و با ساخت یه آرایه از روی کلیدها و یا مقادیرش حساب بشه.
Map قابل تکراره و میتونه مستقیما تکرار بشه، در حالی که تکرار روی یه آبجکت مستلزم بدست آوردن کلیدهای اون به روشی خاص و تکرار روی اونهاست.
آبجکت یه prototype داره، بنابراین کلیدهای پیشفرض توی Object وجود داره که که اگه دقت نکنیم ممکنه با کلیدهامون برخورد کنه. از زمان ES5 میتونیم با استفاده از Map = Object.create(null)، این قضیه رو دور بزنیم ولی بهندرت این کار انجام میشه.
Map ممکنه توی سناریوهای شامل جمع و حذف مکرر جفت کلیدها عملکرد بهتری داشته باشه.
جاواسکریپت مقایسه برابری سخت ( === ، !== ) و تبدیل نوع ( == ، != ) رو فراهم میکنه. عملگرهای سختگیرانه نوع متغیر رو در نظر میگیرند، در حالی که عملگرهای غیر دقیق، اصلاح/تبدیل نوع رو بر اساس مقادیر متغیرها انجام میدن. اپراتورهای سختگیر از شرایط زیر برای انواع مختلف پیروی میکنن.
دو رشته زمانی کاملاً برابر هستن که توالی کاراکترهای یکسان، طول یکسان و کاراکترهای مشابه در موقعیتهای متناظر داشته باشن.
دو عدد زمانی که از نظر عددی مساوی باشن کاملاً برابر هستن. یعنی داشتن مقدار عددی یکسان.
دو مورد خاص در این مورد وجود داره:
NaN با هیچ چیز از جمله NaN برابر نیست.
صفرهای مثبت و منفی با هم برابرند.
اگه هر دو درست یا نادرست باشن، دو عملوند بولین کاملاً برابر هستن.
اگه دو شیء به یه شیء اشاره کنن کاملاً برابر هستن.
یه چندتا مثال که موارد بالا رو پوشش میدن:
0 == false // true 0 === false // false 1 == "1" // true 1 === "1" // false null == undefined // true null === undefined // false '0' == false // true '0' === false // false []==[] or []===[] //false, refer different objects in memory {}=={} or {}==={} //false, refer different objects in memory
arrow function ها به صورت سادهتر و کوتاهتر تعریف میشن و شئ this ، متغیر جادویی argumants ، متد super یا new.target ندارن. این توابع بدون متد هستن و به عنوان سازنده یا constructor استفاده نمیشن.
توی جاواسکریپت، توابع آبجکتهای کلاس اول یا first class هستن. توابع کلاس اول توی هر زبان برنامهنویسی، زمانی معنی میدن که توابع توی اون زبان باهاشون مثل بقیه متغیرها رفتار بشه.
برای مثال، توی جاواسکریپت، یه تابع میتونه به عنوان آرگومان به یه تابع دیگه پاس داده بشه، میتونه به عنوان مقدار نهایی یه تابع دیگه برگشت داده بشه و میتونه به یه متغیر دیگه به عنوان مقدار اختصاص داده بشه. برای مثال توی کد زیر، تابع handler به عنوان callback به یه تابع listener پاس داده شده.
const handler = () => console.log("This is a click handler function"); /** * Usage of `handler` method */ document.addEventListener("click", handler);
تابع مرتبه اول یا first-order تابعیه که هیچ تابع دیگهای رو به عنوان آرگومان قبول نمیکنه و هیچ تابعی رو هم به عنوان مقدار برگشتی یا return value برنمیگردونه. مثل:
const firstOrder = () => console.log("I am a first order function!");
توابع مرتبه بالا توابعی هستن که یه تابع رو به عنوان پارامتر ورودی دریافت و یا به عنوان خروجی ارسال میکنن. مثل:
const firstOrderFunc = () => console.log("Hello I am a First order function"); const higherOrder = (ReturnFirstOrderFunc) => ReturnFirstOrderFunc(); higherOrder(firstOrderFunc);
تابع unary تابعیه که فقط یه آرگومان ورودی دریافت میکنه. مثل:
// Add 10 to the given argument and display the value const unaryFunction = (a) => { console.log(a + 10); };
به فرایندی که در اون یه تابع با چندین آرگومان رو به مجموعهای از توابع که فقط یه آرگومان دریافت میکنن، تبدیل کنیم currying میگیم. Currying از نام یه ریاضیدان به اسم Haskell Curry گرفته شده. با استفاده از Currying در واقع یه تابع رو به یه تابع unary تبدیل میکنیم. بیاین یه مثال از یه تابع با چندین آرگومان و تبدیلش به تابع currying بزنیم.
const multiArgFunction = (a, b, c) => a + b + c; const curryUnaryFunction = (a) => (b) => (c) => a + b + c; curryUnaryFunction(1); // returns a function: b => c => 1 + b + c curryUnaryFunction(1)(2); // returns a function: c => 3 + c curryUnaryFunction(1)(2)(3); // returns the number 6
توابع Curried برای بهبود قابلیت استفاده مجدد کد و ترکیب عملکردی عالی هستن.
تابع pure تابعیه که مقدار برگشتیش فقط توسط آرگومانهاش تعیین میشه بدون هیج side effect یا عوارض جانبی. برای مثال اگه ما یه تابع رو n بار در n جای مختلف برنامه فراخوانی کنیم همیشه یه مقدار مشخص برگشت داده میشه. بیاین یه مثال از تفاوت بین توابع pure و توابع غیرpure بزنیم.
//Impure let numberArray = []; const impureAddNumber = (number) => numberArray.push(number); //Pure const pureAddNumber = (number) => (argNumberArray) => argNumberArray.concat([number]); //Display the results console.log(impureAddNumber(6)); // returns 1 console.log(numberArray); // returns [6] console.log(pureAddNumber(7)(numberArray)); // returns [6, 7] console.log(numberArray); // returns [6]
بر اساس تکه کدهای بالا، تابع push با تغییر روی آرایه و برگردوندن شماره ایندکس push که مستقل از مقدار پارامتر هستش، یه تابع ناخالص یا Impure به حساب میاد. در حالی که از یه طرف متد concat آرایه رو میگیره و اونو با یه آرایه دیگه ترکیب میکنه و یه آرایه کاملا جدید و بدون هیچ side-effect تولید میکنه. همچنین مقدار برگشتی با آرایه قبلی ترکیب شده هستش.
یادتون باشه که توابع خالص یا pure مهمان چون اونا unite-test رو بدون هیچ side-effect و بدون نیاز به dependency-injection ساده میکنن. اونا همچنین از اتصال محکم بین بخشهای مختلف برنامه جلوگیری میکنن و با نداشتن side-effect، احتمال بروز خطا تو برنامه رو کمکتر میکنن. این اصول کنار هم جمع میشن و کنار Immutability و باعث میشن که از const به جای let استفاده بشه.
نکته: دقت کنیم که چاپ یه مقدار روی کنسول و یا درخواست api-call هم side-effect محسوب میشه.
دستور let
یه متغیر محلی block scope تعریف میکنه. از این رو متغیرهایی که با کلمه کلیدی let تعریف میشن محدود به همون اسکوپی که توش تعریف شدن، میشن و فقط دستورها و عبارتهای توی همون اسکوپ بهش دسترسی دارن. درحالی که متغیرهای تعریف شده با کلمه کلیدی var برای تعریف یه متغیر توی سطح global و یا به شکل محلی و برای استفاده در کل تابع بدون در نظر گرفتن اسکوپی که توش تعریف شده، استفاده میشه. بیاین برای نشون دادن کاربردش یه مثال بزنیم.
let counter = 30; if (counter === 30) { let counter = 31; console.log(counter); // 31 } console.log(counter); // 30 (because if block variable won't exist here)
var :
دامنه تابع داره
متغیرها Hoist میشن
از ابتدای جاواسکریپت در دسترس هستش
let:
به عنوان بخشی از ES6 معرفی شده
محدود به scope یا دامنه هستش
Hoist شده ولی قابل استفاده نیست
بیاین با یه مثال تفاوتش رو بهتر ببینیم:
function userDetails(username) { if (username) { console.log(salary); // undefined(due to hoisting) console.log(age); // error: age is not defined (ReferenceError) let age = 30; var salary = 10000; } console.log(salary); //10000 (accessible to due function scope) console.log(age); //error: age is not defined(due to block scope) }
Let یه عنوان ریاضی هستش که توسط زبانهای برنامهنویسی اولیه مثل Scheme و Basic پذیرفته شده. این زبان از دهها زبان دیگه گرفته شده که از let به عنوان یه کلمه کلیدی سنتی تا حد ممکن نزدیک به var استفاده میکنه.
اگه بخوایم متغیرها رو مجددا توی یه بلوک switch
تعریف کنیم، این کار باعث خطا میشه چون در واقع فقط یه بلوک وجود داره. برای مثال توی کد زیر یه خطای نحوی ایجاد میشه:
let counter = 1; switch (x) { case 0: let name; break; case 1: let name; // SyntaxError for redeclaration. break; }
برای جلوگیری از این خطا، میتونیم یه بلوک تودرتو داخل case ایجاد کنیم و یه محیط واژگانی دارای محدوده بلوک جدید ایجاد کنیم.
let counter = 1; switch (x) { case 0: { let name; break; } case 1: { let name; // No SyntaxError for redeclaration. break; } }
Temporal Dead Zone رفتاری توی جاواسکریپتـه که موقع تعریف متغیر با کلمات کلیدی let و const رخ میده، نه با کلمه کلیدی var. توی اکماسکریپت 6، دستیابی به متغیر let و const قبل از تعریفش (توی scope خودش) باعث خطای refrence میشه. فاصله زمانی ایجاد اون، بین ایجاد اتصال متغیر و تعریف اون، منطقه Temporal Dead هستش. بیاین با یه مثال ببینیم:
function somemethod() { console.log(counter1); // undefined console.log(counter2); // ReferenceError var counter1 = 1; let counter2 = 2; }
IIFE (فراخوانی عملکرد بلافاصله) یه تابع جاواسکریپتـه که به محض تعریف اجرا میشه.
تعریف اون به این صورته:
(function () { // logic here })();
دلیل اصلی استفاده از IIFE بدست آوردن حریم خصوصی دادههاست، چون محیط خارجی به متغیرهایی که توی IIFE تعریف شده دسترسی نداره. برای مثال، اگه سعی کنیم با IIFE به متغیرها دسترسی پیدا کنیم این خطا رو میگیریم:
(function () { var message = "IIFE"; console.log(message); })(); console.log(message); //Error: message is not defined
استفاده از ماژولها مزایای زیادی داره، مثلا:
قابلیت نگهداری بالایی دارن
قابلیت استفاده مجدد دارن
نامگذاری بخشهای مختلف کد رو راحتتر میکنن
Memoization
یه روش برنامهنویسیـه که سعی میکنه با ذخیره نتایج قبلی یه تابع عملکرد(پرفورمنس performance) اون تابع رو افزایش بده. هر بار که یه تابع Memoize شده فراخوانی میشه، پارامترهای اون به همراه نتجه بدست اومده cache میشه(یعنی توی حافظه ذخیره میشه). موقع اجرای بعدی قبل از انجام محاسبه بررسی میشه که داده قبلا پردازش شده یا نه و اگه داده وجود داشته باشه، بدون اجرای کل تابع و از روی مقدار cache شده نتیجه برگشت داده میشه، در غیر این صورت تابع به شکل عادی اجرا میشه و بعدش نتیجه بدست اومده توی حافظه ذخیره میشه.
بیاین یه مثال از نوشتن یه تابع با Memoization بزنیم،
const memoizAddition = () => { let cache = {}; return (value) => { if (value in cache) { console.log("Fetching from cache"); return cache[value]; // Here, cache.value cannot be used as property name starts with the number which is not a valid JavaScript identifier. Hence, can only be accessed using the square bracket notation. } else { console.log("Calculating result"); let result = value + 20; cache[value] = result; return result; } }; }; // returned function from memoizAddition const addition = memoizAddition(); console.log(addition(20)); //output: 40 calculated console.log(addition(20)); //output: 40 cached
Hoisting یه مکانیسم جاواسکریپتـه که متغیرها و تعاریف توابع رو به بالای scope یا دامنه خودشون انتقال میده. یادمون باشه که جاواسکریپت فقط تعریف متغیرها و توابع رو Hoist میکنه، نه مقدار دهی اولیه اونا رو.
بیاین یه مثال ساده از hoist کردن متغیرها ببینیم:
console.log(message); //output : undefined var message = "The variable Has been hoisted";
ترجمه کد بالا اینطوری میشه:
var message; console.log(message); message = "The variable Has been hoisted";
در ES6، کلاسهای جاواسکریپت اصطلاحا فقط یه suger-syntax روی وراثت مبتنی بر prototype جاواسکریپت هستن.
برای مثال، وراثت مبتنی بر prototype که به شکل تابع به صورت زیر نوشته شده:
function Bike(model, color) { this.model = model; this.color = color; } Bike.prototype.getDetails = function () { return this.model + " bike has" + this.color + " color"; };
حالا همین کد با کلاسهای ES6 و به شکل سادهتری به صورت زیر قابل نوشتنـه:
class Bike { constructor(color, model) { this.color = color; this.model = model; } getDetails() { return this.model + " bike has" + this.color + " color"; } }
کلاژور ترکیبی از یه تابع و یه scope هستش که تابع توی اون تعریف شده. برای مثال این یه تابع داخلیـه که به متغیرهای تابع خارجی دسترسی داره.
کلاژور دارای سه زنجیره scope هستش:
۱. scope داخلی و جایی که متغیرهای محلی بین براکتهای اون تعریف شده باشن
۲. متغیرهای تابع بیرونی
۳. متغیرهای عمومی و general
بیاین یه مثال راجع به مفهوم کلاژور بزنیم
function welcome(name) { var greetingInfo = function (message) { console.log(message + " " + name); }; return greetingInfo; } var myFunction = welcome("John"); myFunction("Welcome "); //Output: Welcome John myFunction("Hello Mr."); //output: Hello Mr.John
مطابق کد بالا، تابع داخلی (greetingInfo) حتی بعد از بازگشت تابع خارجی به متغیرهای scope تابع خارجی (welcome) دسترسی داره.
ماژولها به واحدهای کوچیکی از کد مستقل و قابل استفاده مجدد گفته میشن و به عنوان پایه بسیاری از دیزاین پترنهای جاواسکریپت عمل میکنن. خروجی ماژولهای جاواسکریپت یه شی، یه تابع یا constructor هستش.
دلایل زیادی برای استفاده کردن از ماژولها وجود داره که یه تعداد از اونا رو این زیر میاریم:
قابلیت نگهداری
قابلیت استفاده مجدد
نامگذاری
جدا بودن بخشهای مختلف برنامه
scope یا محدوده، به نحوه دسترسی متغیرها، توابع و اشیاء توی بخشهای مختلف کدمون در زمان اجرا گفته میشه. به عبارت دیگه، دامنه قابلیت دیده شدن متغیرها و بقیه منابع رو تو قسمتهایی از کدمون تعیین میکنه.
service worker اساسا یه اسکریپت هستش که جدا از یه صفحه وب توی پسزمینه اجرا میشه و ویژگیهایی رو فراهم میکنه که نیازی به صفحه وب یا تعامل کاربر نداره. بعضی از ویژگیهای عمده service workerها عبارتند از: تجربه کار با برنامه بدون نیاز به اینترنت(آفلاین وب)، به روزرسانی دادهها به شکل متناوب در پسزمینه، push notification، رهگیری و رسیدگی به درخواستهای شبکه و مدیریت درخواستهای cache شده.
service worker مستقیما نمیتونه به DOM دسترسی پیدا کنه، اما میتونه با پاسخ به پیامهای ارسالی از طریق رابط postMessage
با صفحاتی که کنترل میکنه ارتباط برقرار کنه و این صفحات میتونن DOM رو دستکاری کنن.
مشکلی که توی service worker وجود داره اینه که در صورت عدم استفاده برای یه مدت، قطع میشه و در صورت نیاز بعدی دوباره راهاندازی میشه، به همین دلیل نمیتونیم به stateهای سراسری توی handlerهای onfetch
و onmessage
یه service worker اعتماد کنیم. تو این حالت service worker برای تداوم کار و استفاده مجدد موقع شروع مجدد، به indexedDB دسترسی خواهد داشت و میشه از اون استفاده کرد.
IndexedDB یه API سطح پایین برای ذخیره client-side یا سمت کاربر و برای مقدار زیادی از دادههای ساخت یافته(structured) شامل فایلها و bolbها هستش. این API از indexها برای فراهمسازی جستجو با کارایی بالا توی این دادهها استفاده میکنه.
web storage یه API هستش که مکانیزمی رو فراهم میکنه که مرورگرها میتونن یه مقدار رو به همراه یه کلید و بصورت محلی توی مرورگر کاربر ذخیره کنن، که روشی بسیار مدرنتر و عملیتر نسبت به کوکیها محسوب میشه. فضای ذخیرهسازی وب دو مکانیزم برای ذخیره اطلاعات روی client فراهم میکنه.
Local storage: دادهها رو برای مسیر(origin) فعلی و بدون تاریخ انقضا ذخیره میکنه.
Session storage: دادهها رو برای یه session ذخیره میکنه و با بسته شدن تب مرورگر دادهها از بین میرن.
Post message روشی هست که امکان ایجاد ارتباط متقابل بین آبجکتهای window رو فراهم میکنه (برای مثال، بین یه صفحه و یه پنجره بازشو که باعث ایجاد اون شده، یا بین یه صفحه و یه iframe قرارداده شده شده توی اون)
به طور کلی اسکریپتهای موجود در صفحات مختلف اگه که صفحاتشون از خط و مشی یکسانی تبعیت کنن مجاز به دسترسی به همدیگه هستن.(یعنی صفحات از پروتکل، شماره پورت و host یکسانی برخوردار باشن).
کوکی قطعهای از داده هستش که توی کامپیوترمون ذخیره میشه تا مرورگر به اون دسترسی داشته باشه. کوکیها به عنوان جفتهای کلید و مقدار ذخیره میشن.
برای مثال میتونیم یه کوکی با عنوان نام کاربری مثل زیر ایجاد کنیم:
document.cookie = "username=John";
از کوکیها برای به خاطر سپردن اطلاعات مربوط به مشخصات کاربر (مانند نام کاربری) استفاده میشه. در اصل شامل دو مرحله هستش:
وقتی که کاربر از یه صفحه وب بازدید میکنه، مشخصات کاربر میتونه توی یه کوکی ذخیره بشه.
دفعه بعد که کاربر از صفحه بازدید کرد، کوکی مشخصات کاربر رو به خاطر میاره.
گزینههای زیر برای کوکی موجوده:
به طور پیش فرض، کوکی موقع بسته شدن مرورگر حذف میشه اما با تنظیم تاریخ انقضا (به وقت UTC) میتونیم این رفتار رو تغییر بدیم.
document.cookie = "username=John; expires=Sat, 8 Jun 2019 12:00:00 UTC";
به طور پیش فرض، کوکی به صفحه فعلی تعلق داره. اما با استفاده از پارامتر path میتونیم به مرورگر بگیم که کوکی متعلق به چه مسیریـه.
document.cookie = "username=John; path=/services";
با تنظیم تاریخ انقضا به عنوان تاریخ گذشته میتونیم کوکی رو حذف کنیم. تو این حالت نیازی به تعیین مقدار کوکی نیست.
برای مثال، میتونیم کوکی نام کاربری رو توی صفحه فعلی به صورت زیر حذف کنیم.
document.cookie = "username=; expires=Fri, 07 Jun 2019 00:00:00 UTC; path=/;";
نکته برای اطمینان از نحوه درست پاک کردن کوکی باید گزینه مسیر کوکی رو تعیین کنیم. بعضی از مرورگرها تا زمانی که پارامتر مسیر رو تعیین نکنیم اجازه حذف کوکی رو نمیدن.
ویژگی | Cookie | Local storage | Session storage |
---|---|---|---|
قابل دسترسی از طرف client یا server | هردو server و client | فقط client | فقط client |
طول عمر | پیکربندیشده با استفاده از گزینه اکسپایر | تا وقتی که حذف بشه | تا وقتی که تب بستهنشده |
پشتیبانی از SSL | پشتیبانی میشه | پشتیبانی نمیشه | پشتیبانی نمیشه |
حداکثر اندازه داده | 4KB | 5MB | 5MB |
لوکال استوریج همون سشن استوریج هستش اما دادهها با بستن و دوباره باز کردن مرورگر همچنان حفظ میشه (تاریخ انقضا نداره) در حالی که سشن استوریج دادهها رو با بستن پنجره مرورگر پاک میکنه.
آبجکت window ویژگیهای WindowLocalStorage
و WindowSessionStorage
رو که دارای ویژگیهای localStorage
و sessionStorage
هستن رو پشتیبانی میکنه. این خصوصیات نمونه ای از شئ Storage رو ایجاد میکنه که از طریق اون میشه موارد داده رو برای یه دامنه خاص و نوع ذخیره سازی (session یا محلی) تنظیم، بازیابی و حذف کرد.
برای مثال، میتونیم روی اشیای ذخیره سازی محلی مثل زیر بخونیم و بنویسیم:
localStorage.setItem("logo", document.getElementById("logo").value); localStorage.getItem("logo");
session storage متدهایی رو برای خواندن، نوشتن و پاکسازی دادههای session ارائه میده. مثلا:
// Save data to sessionStorage sessionStorage.setItem("key", "value"); // Get saved data from sessionStorage let data = sessionStorage.getItem("key"); // Remove saved data from sessionStorage sessionStorage.removeItem("key"); // Remove all saved data from sessionStorage sessionStorage.clear();
StorageEvent رویدادی هستش که با همزمان با تغییر یه محل ذخیرهسازی تو یه context صفحه دیگهای فراخوانی میشه. این امکان بهمون قابلیت پردازش تغییرات مقادیر ذخیرهسازی شده توسط یه EventHandler رو میده. ساختار کد اون یه چیزی مث کد زیر میشه:
window.onstorage = functionRef;
برای مثال استفاده از رویداد onstorage رو ببینیم که کلید ذخیره و مقادیر اونو ثبت میکنه:
window.onstorage = function (e) { console.log( "The " + e.key + " key has been changed from " + e.oldValue + " to " + e.newValue + "." ); };
با استفاده از این قابلیت میشه گفت که فضای ذخیرهسازی وب از امنیت بیشتری برخورداره و مقدار زیادی داده میتونن به صورت محلی ذخیره بشن، بدون اینکه روی عملکرد وب سایت تأثیر بذارن. همچنین، اطلاعات هرگز به سرور منتقل نمیشن و به همین دلیل این روش نسبت به کوکیها بیشتر توصیه میشه.
قبل از استفاده از فضای ذخیرهسازی وب، میتونیم پشتیبانی مرورگر رو برای localStorage و sessionStorage بررسی کنیم. البته مرورگرهای مدرن امروزی کاملا پشتیبانی web-storage رو ارائه میدن.
if (typeof Storage !== "undefined") { // Code for localStorage/sessionStorage. } else { // Sorry! No Web Storage support.. }
میتونیم برای داشتن یه کد cross-functional قبل از استفاده از وب ورکرها، پشتیبانی مرورگر رو بررسی کنیم، انجام این کار هم ساده اس و با یه شرط ساده محقق میشه:
if (typeof Worker !== "undefined") { // code for Web worker support. } else { // Sorry! No Web Worker support.. }
یه مثال ساده برای شروع استفاده از web workerها میتونه مثال شمارنده باشه که برای اجرای اون باید مراحل زیر رو دنبال کنیم:
ساخت یه فایل Web Worker: برای افزایش مقدار شمارشی، باید یه اسکریپت بنویسیم که این کار رو انجام میده. بیاین اسمشو counter.js بذاریم
let i = 0; function timedCount() { i = i + 1; postMessage(i); setTimeout("timedCount()", 500); } timedCount();
اینجا از روش postMessage برای ارسال پیام به صفحه HTML استفاده میشه.
ایجاد شی Web Worker: با بررسی پشتیبانی مرورگر میتونیم یه شی Web Worker ایجاد کنیم. بیاین اسم این فایل رو web_worker_example.js بذاریم.
if (typeof w == "undefined") { w = new Worker("counter.js"); }
روی همین شئ ما میتونیم پیامها رو از web worker دریافت کنیم:
w.onmessage = function (event) { document.getElementById("message").innerHTML = event.data; };
پایان دادن به web Worker: میدونیم که Web Workerها تا زمان خاتمه یافتن پیامها(حتی بعد از اتمام یه اسکریپت خارجی) به گوش دادن ادامه میدن. برای قطع کردن گوش دادن به پیامها میتونیم از دستور terminate استفاده کنیم.
w.terminate();
استفاده مجدد از web worker: اگه متغیر worker رو undefined مقداردهی کنیم، میتونیم از کد نوشته شده مجددا استفاده کنیم.
w = undefined;
WebWorkerها به اشیا جاواسکریپت دسترسی ندارن چون توی یه فایل خارجی تعریف شدن. پس به این آبجکتها دسترسی نداریم:
آبجکت Window
آبجکت Document
آبجکت Parent
یه Promise آبجکتایـه که یه ممکنه یه callback برای موفق بودن یا رو با یه callback موفق نبودن(مثلاً خطای شبکه) فرآیند تولید کنه. پس کلا حالتهای ممکن برای یه Promise یکی از این سه حالت خواهد بود: انجام شده، رد شده، یا در انتظار.
برای ساختن Promiseها از سینتکس زیر استفاده میشه
const promise = new Promise(function (resolve, reject) { // promise description });
استفاده از Promiseها رو هم باهم ببینیم
const promise = new Promise( (resolve) => { setTimeout(() => { resolve("I'm a Promise!"); }, 5000); }, (reject) => { // if we want to rejest, we can call `reject()` cb method } ); /** * We can call promise and add some success callback functionality to run after resolve */ promise.then((value) => console.log(value)); // here after 5s we will have a log in our console
چرخه فرآیند یه Promise به این شکل انجام میشه:
Promiseها برای رسیدگی به عملیات ناهمزمان(async) استفاده میشن. اونا با جلوگیری از وقوع callback hell و نوشتن کد clean و تر و تمیزتر ، یه رویکرد جایگزین برای callbackها ارائه میکنن.
Promiseها سه حالت دارن:
Pending: این حالت اولیه Promise قبل از شروع عملیاته
Fulfilled: این حالت نشون میده که عملیات مشخص شده تکمیل شده.
Rejected: این حالت نشون میده که عملیات کامل نشده. تو این حالت یه مقدار خطا داده خواهد شد.
تابع callback تابعیه که به عنوان آرگومان به تابع دیگری منتقل میشه. این تابع در داخل تابع خارجی برای تکمیل یه عملیات فراخوانی میشه.
بیاین یه مثال ساده از نحوه استفاده از تابع callback ببینیم:
function callbackFunction(name) { console.log("Hello " + name); } function outerFunction(callback) { let name = prompt("Please enter your name."); callback(name); } outerFunction(callbackFunction);
چون جاواسکریپت یه زبان ایونت محوره به callbackها نیاز داریم. این به این معنیه که جاواسکریپت به جای منتظر موندن برای جواب یه عملیات فراخوانی شده، در حین گوش دادن به ایونتهای دیگه به اجرا شدن ادامه میده.
بیاین یه مثال از دو تا تابع که پشت سرهم اجرا میشن ولی یکیشون callback میزنه به یه API (شبیهسازی شده با setTimeout) و اون یکی یه لاگ کنسول ساده میندازه رو ببینیم:.
function firstFunction() { // Simulate a code delay setTimeout(function () { console.log("First function called"); }, 1000); } function secondFunction() { console.log("Second function called"); } firstFunction(); secondFunction(); // Output : // Second function called // First function called
همونطور که از خروجی میشه فهمید، جاواسکریپت منتظر جواب تابع اول نمونده و بلوک کد باقی مونده رو اجرا کرده. بنابراین از callbackها میتونیم به شکلی استفاده کنیم که مطمئن شیم یه کد تا زمانی که اجرای کد دیگه تموم نشده، اجرا نمیشه.
Callback Hell اصطلاحا یه آنتیپترنـه که با چندین callback تودرتو ایجاد میشه، همیشه هم خوندن کد و رفع خطاها رو سختتر میکنه، مخصوصا زمانهایی که با async کار میکنیم. یه جهنم callback با یه کد مثل کد پایین ایجاد میشه:
async1(function () { async2(function () { async3(function () { async4(function () { // .... }); }); }); });
eventهای ارسال شده توسط سرور (SSE) یه فناوری server pushـه که به مرورگر این امکان رو میده که بهروزرسانیهای خودکار رو از طریق درخواست HTTP و بدون استفاده از polling(درخواستهای پیوسته و منظم) دریافت کنه. این روش، یه کانال ارتباطی یه طرفهـست و eventها فقط از سرور به client ارسال میشن. این روزا از قابلیتهای SSE روی بهروزرسانیهای فیسبوک/تویتر، بهروزرسانی قیمت سهام، فیدهای خبری و غیره استفاده میشه.
کلاس EventSource برای دریافت پیامهای event ارسال شده از سرور استفاده میشه. برای مثال، میتونیم پیامهایی که میخوایین رو از سرور مثل مثال زیر بگیرین.
if (typeof EventSource !== "undefined") { var source = new EventSource("sse_generator.js"); source.onmessage = function (event) { document.getElementById("output").innerHTML += event.data + "<br>"; }; }
میتونیم قبل از استفاده از SSE مانند زیر، پشتیبانی مرورگر رو با یه شرط شبیه کد زیر بررسی کنیم:
if (typeof EventSource !== "undefined") { // Server-sent events supported. Let's have some code here! } else { // No server-sent events supported }
این پایین یه لیست از eventهای موجود برای SSE رو ذکر میکنیم:
ایونت | توضیحات |
---|---|
onopen | موقعی که اتصال به سرور باز میشه استفاده میشه |
onmessage | این event زمانی استفاده میشه که پیامی دریافت شه |
onerror | زمانی اتفاق میوفته که خطایی رخ بده |
میشه گفت اصلیترین قانونهای Promiseها ایناست:
Promise آبجکتایـه که متد «.then» رو برای منتظر پاسخ درخواست موندن ارائه میکنه.
یه Promise معلق ممکنه به حالت تحقق یافته یا رد شده تبدیل بشه.
Promise تمام شده یا رد شده حل و فصل میشه و نباید به حالت دیگری تبدیل شه.
پس از اتمام Promise مقدار اون نباید تغییر کنه.
میتونیم یه پاسخ api-call رو داخل یه api-call دیگر قرار بدین تا عملیاتها رو به شکل متوالی و یکی یکی انجام بدین. این به عنوان callback در callbacks شناخته میشه.
loadScript('/script1.js', function(script) { console.log('first script is loaded'); loadScript('/script2.js', function(script) { console.log('second script is loaded'); loadScript("/script2.js", function (script) { console.log("second script is loaded"); loadScript("/script3.js", function (script) { console.log("third script is loaded"); // after all scripts are loaded }); }); });
فرآیند اجرای دنبالهای از عملیاتهای ناهمزمان(async) به طوریکه هر کدوم بعد از تموم شدن قبلی اجرا بشن با استفاده از Promiseها به عنوان Promise chaining شناخته میشه. بیاین برای محاسبه نتیجه نهایی یه مقدار، یه مثال از زنجیره Promiseها رو ببینیم:
new Promise(function (resolve, reject) { setTimeout(() => resolve(1), 1000); }) .then(function (result) { console.log(result); // 1 return result * 2; }) .then(function (result) { console.log(result); // 2 return result * 3; }) .then(function (result) { console.log(result); // 6 return result * 4; });
توی بلوکهای کد بالا، نتیجه هر Promise به زنجیرههای then بعدی منتقل میشه، فرآیندشون به شکل زیر انجام میشه:
Promise اول توی 1 ثانیه حل میشه،
پس از اون then با چاپ مقدار 1
توی کنسول، فراخوانی میشه و یه Promise با مقدار result ضربدر 2 برمیگردونه.
پس از اون result به callback بعدی منتقل شده و با چاپ مقدار 2
و برگردوندن یه Promise با result ضربدر 3.
در نهایت مقدار به آخرین callback رسیده و با چاپ مقدار 6
توی کنسول، یه Promise با result ضربدر 4 برمیگردونه`.
Promise اول توی 1 ثانیه حل میشه،
پس از اون «.then» با ثبت نتیجه (1) فراخوانی میشه و سپس یه Promise با مقدار نتیجه * 2 برمیگردونه.
پس از اون مقدار به بعدی منتقل شد. سپس با ثبت نتیجه (2) و برگردوندن یه Promise با نتیجه *3.
در نهایت مقدار به آخرین . سپس با ثبت نتیجه (6) و یه Promise با نتیجه * 4، handler`.
Promise.all یه Promiseـه که آرایهای از Promiseها رو به عنوان ورودی میگیره(یک تکرار) و زمانی resolve میشه که همه Promiseها resolve بشن، و اگه یکی از اونها رد شه reject میشه. برای مثال، تیکه کد زیر رو ببینیم:
Promise.all([Promise1, Promise2, Promise3]) .then((result) => { console.log(result); }) .catch((error) => { console.log(`Error in promises ${error}`); });
نکته: ترتیب خروجی Promiseها طبق همون ترتیب آرایه ورودی ایجاد میشه.
متد Promise.race یه آرایه از Promiseها رو میگیره و نتیجه اولین Promiseای resolve یا reject شده رو برمیگردونه. بیاین مثالی از متد race رو در نظر بگیریم که تو اون Promise2 اول resolve میشه:
const promise1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, "one"); }); const promise2 = new Promise(function (resolve, reject) { setTimeout(resolve, 100, "two"); }); Promise.race([promise1, promise2]).then(function (value) { console.log(value); // "two" // Both promises will resolve, but promise2 is faster });
Strict Mode یکی از قابلیتهای ارائه شده توی ES5 هست که به ما این امکان رو میده که یه برنامه یا یه تابع رو تو یه حالت اجرایی "سختتر" قرار بدیم. به این ترتیب از انجام بعضی اقدامات جلوگیری میکنه و استثنا(Exception)های بیشتری رو ایجاد میکنه. عبارت تحت اللفظی "usestrict" به مرورگر دستور میده تا از کد جاواسکریپت در حالت Strict استفاده کنه.
حالت سخت گیرانه(strict mode) برای نوشتن جاواسکریپت "امن" و حصول اطمینان از اطلاع از "syntax بد" برای جلوگیری از خطاهای واقعی استفاده میشه. برای مثال، ایجاد تصادفی یه متغیر گلوبال رو با ایجاد یه Exception حذف میکنه و یا یه خطا برای انتساب به یه ویژگی غیرقابل نوشتن، یه ویژگی فقط گیرنده، یه ویژگی غیرموجود، یه متغیر غیرموجود یا یه ویژگی غیر قابل نوشتن ایجاد میکنه.
حالت سخت با اضافه کردن رشته use strict
به ابتدای scope اعلام میشه. پس میتونیم اونو به ابتدای یه اسکریپت یا یه تابع اضافه کنیم.
اگه در ابتدای یه اسکریپت اعلام شه، دامنه عمومی داره:
"use strict"; x = 3.14; // This will cause an error because x is not declared
و اگه در داخل یه تابع اعلام کنیم محدوده محلی داره:
x = 3.14; // This will not cause an error. myFunction(); function myFunction() { "use strict"; y = 3.14; // This will cause an error }
علامت نقیض دوتایی یا نفی (!!) اینه که تضمین میکنه که نوع حاصل از عملیات یه مقدار true یا falseـه و تایپش بولینـه. اگه falsy بود (برای مثال 0، null، undifiend و غیره)، false میشه و در غیر این صورت، درسته و نتیجه true خواهد بود.
برای مثال، میتونیم نسخه IE رو با استفاده از عبارت زیر آزمایش کنیم.
let isIE8 = false; isIE8 = !!navigator.userAgent.match(/MSIE 8.0/); console.log(isIE8); // returns true or false
اگه از این عبارت استفاده نکنیم مقدار اصلی رو برمیگردونه.
console.log(navigator.userAgent.match(/MSIE 8.0/)); // returns either an Array or null
نکته: !!
یه اپراتور جدید نیست و فقط دوتا اپراتور !
هست.
نکته: استفاده از !!
معادل استفاده از Boolean(var)
هست ولی !!
سریعتره.
کلمه کلیدی delete برای حذف ویژگی و همچنین مقدار اون استفاده میشه.
var user = { name: "John", age: 20 }; delete user.age; console.log(user); // {name: "John"}
برای بدست آوردن نوع متغیر جاواسکریپت میتونیم از عملگر typeof استفاده کنیم و نوع یه متغیر یا یه عبارت رو به صورت یه رشته برمیگردونه.
typeof "John Abraham"; // Returns "string" typeof (1 + 2); // Returns "number"
ویژگی undefined میگیریم که به یه متغیر مقداری اختصاص داده نشده یا اصلاً تعریف نشدهـست. هم نوع مقدار تعریف نشده هم تعریف نشده.
var user; // Value is undefined, type is undefined console.log(typeof user); //undefined
هر متغیری رو میشه با تنظیم مقدار روی undefined خالی کرد.
user = undefined;
مقدار null عدم وجود عمدی هر مقدار شی رو نشون میده. null یکی از مقادیر اولیه جاواسکریپتـه و حواسمون باید باشه که نوع مقدار null آبجکته.
با قرار دادن مقدار null هم میتونیم متغیر رو خالی کنیم.
var user = null; console.log(typeof user); //object
تفاوتهای اصلی بین null و undefined:
Null | Undefined |
---|---|
یه مقدار انتسابه که نشون میده متغیر به هیچ شیئی اشاره نمیکنه. | یه مقدار انتساب نیست که تو اون متغیری اعلام شده باشه اما هنوز مقداری به اون اختصاص داده نشده. |
تایپ null آبجکته | تایپ undefined همون تعریف نشده و undefined هستش |
مقدار null یه مقدار اولیه اس که نشون دهنده مرجع تهی، خالی یا غیر موجوده. | مقدار undefined یه مقدار اولیه اس و زمانی استفاده میشه که به یه متغیر مقداری اختصاص داده نشده باشه. |
عدم وجود مقدار برای یه متغیر رو نشون میده | عدم وجود خود متغیر رو نشون میده |
در حین انجام عملیات اولیه به صفر (0) تبدیل میشه | در حین انجام عملیات اولیه به NaN تبدیل میشه |
تابع eval کد جاواسکریپتای رو که به صورت رشته بهش پاس داده شده رو اجرا میکنه. رشته میتونه یه عبارت جاواسکریپت، متغیر، دستور یا دنباله ای از عبارات باشه.
console.log(eval("1 + 2")); // 3
Window | Document |
---|---|
عنصر ریشه در هر صفحه وبه | فرزند مستقیم شی window هستش و همچنین به عنوان مدل شیء document (DOM) |
به طور پیش فرض شی window به طور ضمنی در هر صفحه قرار داره | میتونیم از طریق window.document یا document به اون دسترسی داشته باشیم. |
دارای متدهایی مانند alert، confirm و ویژگیهایی مانند document، location | متدهایی مانند getElementById، getElementByTagName، createElement و غیره رو فراهم میکنه |
شی window.history حاوی تاریخچه مرورگره. با استفاده از متدهای back
و next
میتونیم URLهای قبلی و بعدی رو در تاریخچه بارگذاری کنیم. مثلا:
function goBack() { window.history.back(); } function goForward() { window.history.forward(); }
نکته: همچنین میتونیم بدون پیشوند window به آبجکت history دسترسی داشته باشیم.
Number
String
Boolean
Object
Undefined
تابع isNaN
(Not-a-Number) برای تعیین اینه که آیا یه مقدار یه عدد واقعیه یا نه هست یا نه استفاده میشه. یعنی اگه مقدار برابر با NaN باشه، این تابع true برمیگردونه. در غیر این صورت false برمیگرده.
isNaN("Hello"); //true isNaN("100"); //false
undeclared | undefined |
---|---|
این متغیرها تو یه برنامه وجود ندارن و تعریف نشدن | این متغیرها در برنامه هست، اما هیچ مقداری نداره |
اگه سعی کنیم مقدار یه متغیر undeclared رو بخونیم، با خطای زمان اجرا مواجه میشیم | اگه سعی کنیم مقدار یه متغیر تعریف نشده رو بخونیم، یه مقدار تعریف نشده برگردونده میشه. |
متغیرهای عمومی اونایی ان که در طول کد بدون هیچ محدوده ای در دسترسن. کلمه کلیدی var برای اعلام یه متغیر محلی استفاده میشه اما اگه اونو حذف کنیم تبدیل به متغیر عمومی میشه.
msg = "Hello"; // var is missing, it becomes global variable
مشکل متغیرهای سراسری تضاد نام متغیرها با دامنه محلی و گلوباله. دیباگ و آزمایش کدی که به متغیرهای سراسری متکیه سخته.
ویژگی NaN یه ویژگی گلوباله که مقدار "Not-a-Number" رو نشون میده. یعنی نشون میده که یه مقدار یه متغیر واقعا عددی نیست. استفاده از NaN تو برنامهها خیلی نداره، اما میشه از اون به عنوان مقدار بازگشتی یه سری توابع و برای یه سری موارد کم استفاده کرد:
Math.sqrt(-1); parseInt("Hello");
تابعisFinite
برای تعیین اینکه آیا یه عدد یه عدد محدود و قانونیه استفاده میشه. اگه مقدار +infinity، -infinity یا NaN (Not-a-Number) باشه false برمیگردونه، در غیر این صورت true رو برمیگردونه.
isFinite(Infinity); // false isFinite(NaN); // false isFinite(-Infinity); // false isFinite(100); // true
event-flow
ترتیبیه که event
در صفحه وب دریافت میشه. وقتی روی یه المنت در صفحه وب کلیک میکنیم و این المنت به شکل تودرتو داخل المنتهای مختلف استفاده شده، قبل از اینکه کلیکمون واقعاً به مقصد یا المنت هدف برسه، باید event
کلیک رو برای هر کدوم از عنصرهای والد خودش بفرسته و از بالا با شی پنجره گلوبال شروع شه.
به شکل کلی دو راه برای جریان event وجود داره:
از بالا به پایین(Event Capturing)
از پایین به بالا (Event Capturing)
از بالا به پایین(Event Capturing)
از پایین به بالا (Event Capturing)
Event-bubbling
نوعی انتشار eventـه که تو اون event ابتدا روی درونیترین عنصر هدف فراخوانی میشه و سپس بهطور متوالی روی اجداد (والد) عنصر هدف تو همون سلسله مراتب تودرتو راهاندازی میشه تا زمانی که به بیرونیترین عنصر DOM برسه.
Event-capturing نوعی انتشار eventـه که تو اونevent اول با بیرونی ترین عنصر ثبت میشه و سپس به طور متوالی بر روی children (children) عنصر هدف تو همون سلسله مراتب تودرتو راه اندازی میشه تا زمانی که به درونی ترین عنصر DOM برسه.
میتونیم با استفاده از جاواسکریپت فرم مورد نظرمون رو با استفاده از کد document.form[0].submit ارسال کنیم. تمام اطلاعات ورودی فرم با استفاده از onsubmit event handler ارسال میشه
function submit() { document.form[0].submit(); }
شی window.navigator حاوی اطلاعاتی درباره جزئیات سیستم عامل مرورگر بازدیدکنندهـست. بعضی از ویژگیهای سیستم عامل روی ویژگی پلتفرم در دسترس هستن:
console.log(navigator.platform);
رویداد DOMContentLoaded
زمانی فراخوانی میشه که سند اولیه HTML بهطور کامل بارگیری و تجزیه شده باشه، بدون اینکه منتظر بمونیم تا بارگیری assetها(استایلها، تصاویر و فریمهای فرعی) تموم شه. در حالی که رویداد load روی داکیومنت زمانی فراخوانی میشه که کل صفحه بارگیری شه، شامل همه استایلها، تصاویر و ... .
Native object
ها آبجکتهایی هستن که به عنوان بخشی از زبان جاواسکریپت تعریف شدن و به عنوان بخشی از مشخصات ECMAScript هستن. برای مثال، اشیاء اصلی رشته، ریاضی، RegExp، Object، Function و غیره که در مشخصات ECMAScript
تعریف شدن.
Host objects
آبجکتهایی هستن که توسط مرورگر یا محیط زمان اجرا (Node) ارائه میشن. برای مثال، پنجره، XmlHttpRequest
نودهای DOM و غیره به عنوان اشیاء میزبان در نظر گرفته میشن.
User objects
آبجکتهایی هستن که تو کد جاواسکریپت تعریف شدن. برای مثال، آبجکتهای ایجاد شده توسط برای اطلاعات پروفایل.
Chrome Devtools
عبارت debugger
متد console.log
مزایا:
مزایا:
از جهنم callback که قابل خواندن نیست جلوگیری میکنه.
نوشتن کدهای ناهمزمان متوالی با then آسونتره.
نوشتن کد ناهمزمان موازی با Promise.all آسونتره.
بعضی از مشکلات رایج callbackهای بازگشتی رو حل میکنه (مشکل فراخوانی بسیار دیر، خیلی زود، یا چندبار فراخوانی callback و استثناها رو مدیریتیش رو راحتتر میکنه).
معایب:
کد یه کمی پیچیده میشه.
اگه ES6 پشتیبانی نشد باید یه polyfill بارگذاری بشه.
کد کمی پیچیده می سازد
اگه ES6 پشتیبانی نمیشه، باید یه polyfill بارگذاری کنیم
Attributeها برای نشونه گذاری HTML تعریف میشن در حالی که propertyها روی DOM تعریف میشن برای مثال، عنصر HTML زیر دارای 2 ویژگی نوع و مقدار هستش
<input type="text" value="Name:">
میتونیم مقدار یه ویژگی رو به صورت زیر بدست بیاریم:
const input = document.querySelector("input"); console.log(input.getAttribute("value")); // Good morning console.log(input.value); // Good morning
و بعد از اینکه مقدار فیلد متن به "Good evening" تغییر داده شد، نتیجه مثل زیر میشه:
console.log(input.getAttribute("value")); // Good morning console.log(input.value); // Good evening
سیاست یا خط مشی same-origin
خط مشیه که از درخواست جاواسکریپت در روی کل domain جلوگیری میکنه. مبدا به عنوان ترکیبی از شمای URI، نام میزبان(hostname) و شماره پورت(port) تعریف میشه. اگه این خطمشی رو فعال کنیم، مرورگر از دسترسی یه اسکریپت مخرب تو یه صفحه به دادههای حساس توی صفحه وب دیگه با استفاده از DOM(Document Object Model) جلوگیری میکنه.
Void(0) برای جلوگیری از به روزرسانی صفحه استفاده میشه. این متد برای از بین بردن ساید افکتهای ناخواسته مفیده، چون مقدار اولیه تعریف نشده رو برمیگردونه. معمولاً برای اسناد HTML استفاده میشه که از href="JavaScript:Void(0)" روی تو یه عنصر <a>
استفاده میکنن. یعنی وقتی روی یه لینک کلیک میکنیم مرورگر یه صفحه جدید رو بارگیری میکنه یا همون صفحه رو تازهسازی(reload) میکنه. ولی با استفاده از این عبارت میتونیم از این رفتار جلوگیری کنیم.
:برای مثال، لینک زیر پیام رو بدون بارگیری مجدد صفحه مطلع میکنه
<a href="JavaScript:void(0);" onclick="alert('Well done!')">Click Me!</a>
جاواسکریپت یه زبان تفسیریـه و نه یه زبان کامپایلری. یه مفسر توی مرورگر کد جاواسکریپت رو می خونه، هر خط رو تفسیر میکنه و اونو اجرا میکنه. امروزه مرورگرهای مدرن از فناوری موسوم به کامپایل Just-In-Time(JIT) استفاده میکنن که جاواسکریپت رو موقعی که در شرف اجراست به بایت کد اجرایی کامپایل میکنه.
بله، جاواسکریپت یه زبان حساس به حروف کوچک و بزرگه. کلمات کلیدی استفاده شده توی زبان، متغیرها، توابع و اشیا، و هر شناسه دیگر باید همیشه با حروف بزرگ تایپ شن.
نه، این دو زبان برنامه نویسی کاملاً متفاوت هستن و هیچ ارتباطی با همدیگه ندارن. اما هر دوی اونا زبانهای برنامه نویسی شی گرا هستن و مثل خیلی از زبانهای دیگه، از syntax مشابهی برای ویژگیهای اساسی (if، else، for، switch، break، continue و غیره) پیروی میکنن.
رویدادها «چیزهایی» هستن که روی عناصر HTML و برای اونا اتفاق میافتن. موقعی که جاواسکریپت توی صفحات HTML استفاده میشه، میتونه به این رویدادها واکنش نشون بده و ما با استفاده از این رخدادها میتونیم رفتار خاصی رو موقع رخداد خاص تعریف کنیم. بعضی از نمونههای رویدادهای HTML عبارتند از:
بارگذاری صفحه وب تموم شه
فیلد ورودی تغییر کنه
روی یه دکمه کلیک شه
بیاین رفتار رویداد کلیک رو برای یه button ببینیم:
<!DOCTYPE html> <html> <head> <script> function greeting() { alert("Hello! Good morning"); } </script> </head> <body> <button type="button" onclick="greeting()">Click me</button> </body> </html>
جاواسکریپت توسط Brendan Eich تو سال 1995 و موقع فعالیت ایشون توی نت اسکیپ (Netscape Communication) ایجاد شد و با نام Mocha
توسعه پیدا کرد، اما بعدها زمانی که برای اولین بار در نسخههای بتا نت اسکیپ عرضه شد، این زبان به طور رسمی LiveScript
نامیده شد.
متد preventDefault
اگه رویداد قابل لغو باشه، اونو لغو میکنه، به این معنی که عمل یا رفتار پیشفرض متعلق به رویداد اتفاق نمیافته. برای مثال، جلوگیری از ارسال فرم موقع کلیک بر روی دکمه ارسال و جلوگیری از باز شدن URL
صفحه موقع کلیک کردن روی لینک از موارد رایج استفادهـشه.
document .getElementById("link") .addEventListener("click", function (event) { event.preventDefault(); });
نکته: همه رویدادها قابل لغو نیستن.
روش stopPropagation
برای جلوگیری از event bubbling
توی یه زنجیره از رویدادها استفاده میشه. برای مثال، divهای تودرتو زیر با متد stopPropagation
از انتشار پیش فرض رویداد موقع کلیک روی Div1 جلوگیری میکنه.
<p>Click DIV1 Element</p> <div onclick="secondFunc()"> DIV 2 <div onclick="firstFunc(event)">DIV 1</div> </div> <script> function firstFunc(event) { alert("DIV 1"); event.stopPropagation(); } function secondFunc() { alert("DIV 2"); } </script>
عبارت return false
تو event-handler
مراحل زیر رو انجام میده:
ابتدا عملکرد یا رفتار پیش فرض مرورگر رو متوقف میکنه.
رویداد از انتشار DOM
جلوگیری میکنه.
اجرای callback
رو متوقف میکنه و بلافاصله پس از فراخونی بر میگرده.
مدل آبجکتی مرورگر (BOM) به جاواسکریپت اجازه میده تا با مرورگر صحبت کنه. این مدل شامل navigation، history، page، location و document که فرزندان window هستن. BOM مدل استاندارد همه مرورگرها نیست و میتونه بر اساس مرورگرهای مختلف تغییر کنه.
متد setTimeout
برای فراخونی یه تابع یا ارزیابی یه عبارت پس از میزان مشخصی از زمان(میلی ثانیه) استفاده میشه. برای مثال، بیاین یه پیام رو پس از 2 ثانیه با استفاده از متد setTimeout
چاپ کنیم:
setTimeout(function () { console.log("Good morning"); }, 2000);
متد setInterval
برای فراخوانی یه تابع یا ارزیابی یه عبارت در بازههای زمانی مشخص (بر حسب میلی ثانیه) استفاده میشه. برای مثال، بیاین یه پیام رو هر 2 ثانیه با استفاده از متد setInterval
چاپ کنیم:
setInterval(function () { console.log("Good morning"); }, 2000);
چون مشخصات زبان به برنامه نویس اجازه نمیده تا کدی بنویسه که مفسر بتونه بخشهایی از اونو به صورت موازی در چندین Thread یا پردازش اجرا کنه. در حالی که زبانهایی مانند java، go، C++ میتونن برنامههای چند رشتهای و چند فرآیندی بسازن.
Event-delegation
تکنیکی برای گوش دادن به رویدادهاس که تو اون یه عنصر والد رو به عنوان شنونده برای همه رویدادهایی که در داخلش اتفاق میافتن، تفویض میکنیم.
برای مثال، اگه میخواین تغییرات فیلد رو تو یه فرم خاص تشخیص بدین، میتونیم از تکنیک Event-delegation
استفاده کنیم.
var form = document.querySelector("#registration-form"); // Listen for changes to fields inside the form form.addEventListener( "input", function (event) { // Log the field that was changed console.log(event.target); }, false );
ECMAScript
زبان برنامه نویسیه که اساس جاواسکریپت رو تشکیل میده. ECMAScript
توسط سازمان استانداره بین المللی ECMA
در مشخصات ECMA-262
و ECMA-402
استانداره شده است. اولین نسخه ECMAScript
در سال 1997 منتشر شد.
JSON (JavaScript Object Notation)
یه فرمت سبک هستش که برای تبادل دادهها استفاده میشه. اصول اولیه جیسون بر اساس زیرمجموعهای از زبان جاواسکریپتـه و مشابه آبجکت اشیاییه که توی جاواسکریپت ساخته میشن.
دادهها به صورت جفت نام/مقدار هستن
دادهها با کاما از هم جدا میشن
براکتها اجسام رو نگه میدارن
کروشهها آرایهها رو نگه میدارن
موقع ارسال دادهها به وب سرور، دادهها باید در قالب رشتهای باشن. میتونیم با استفاده از متد stringify
آبجکت JSON
رو به رشته متنی تبدیل کنیم. مثل:
var userJSON = { name: "John", age: 31 }; var userString = JSON.stringify(user); console.log(userString); //"{"name":"John","age":31}"
موقع دریافت دادهها از یه وب سرور، دادهها همیشه در قالب رشته متنی هستن. اما میتونیم این مقدار رشته رو با استفاده از متد parse
به یه آبجکت جاواسکریپت تبدیل کنیم.
var userString = '{"name":"John","age":31}'; var userJSON = JSON.parse(userString); console.log(userJSON); // {name: "John", age: 31}
موقع تبادل داده بین مرورگر و سرور، دادهها به دلیل تبادل شدن با استفاده از پروتکل Http فقط میتونن متنی باشن. از اونجایی که JSON
فقط متنیـه میشه اونو به راحتی به سرور ارسال کرد و از اون به عنوان قالب داده برای هر زبان برنامهنویسی استفاده کرد.
Progressive web applications (PWAs)
نوعی از برنامههای تلفن همراه هستن که از طریق وب ارائه میشن، و با استفاده از فناوریهای رایج وب از جمله HTML
، CSS
و جاواسکریپت ساخته میشن. PWA
ها در سرورها قرار میگیرن و از طریق آدرس صفحه وب
قابل دسترسی و نصب هستن.
تابع clearTimeout
در جاواسکریپت برای پاک کردن بازه زمانی استفاده میشه که قبل از اون توسط تابع setTimeout
تنظیم شده. یعنی مقدار بازگشتی تابع setTimeout
تو یه متغیر ذخیره میشه و برای پاک کردن تایمر به تابع clearTimeout
پاس داده میشه.
برای مثال، از تابع setTimeout
موجود توی کد پایین برای نمایش پیام بعد از 3 ثانیه استفاده میشه. این مهلت زمانی رو میشه با تابع clearTimeout
پاک کرد.
<script> var msg; function greeting() { alert("Good morning"); } function start() { msg = setTimeout(greeting, 3000); } function stop() { clearTimeout(msg); } </script>
تابع clearInterval
تو جاواسکریپت برای پاک کردن interval که توسط تابع setInterval
تنظیم شده استفاده میشه. برای مثال، مقدار بازگشتی که توسط تابع setInterval
برمی گرده تو یه متغیر ذخیره میشه و برای پاک کردن interval به تابع clearInterval
ارسال میشه.
برای مثال، از تابع setInterval
توی کد پایینی برای نمایش پیام در هر 3 ثانیه استفاده میشه. این بازه رو میشه با تابع clearInterval
پاک کرد.
<script> var msg; function greeting() { alert("Good morning"); } function start() { msg = setInterval(greeting, 3000); } function stop() { clearInterval(msg); } </script>
در vanila
جاواسکریپت(جاواسکریپت خام یا خالص هم میگن)، میتونیم با استفاده از ویژگی location
آبجکت گلوبال window
به صفحه جدیدی هدایت بشین.
function redirect() { window.location.href = "newPage.html"; }
سه روش برای بررسی اینکه یه رشته دارای یه رشته فرعیه یا نه، وجود داره.
استفاده از متد includes: ES6 روش String.prototype.includes
رو برای آزمایش یه رشته حاوی یه رشته فرعی ارائه کرد.
var mainString = "hello", subString = "hell"; mainString.includes(subString);
استفاده از متد indexOf: توی محیط ES5 یا قدیمیتر، میتونیم از String. prototype.indexOf
استفاده کنیم که index یه رشته فرعی رو برمیگردونه. اگه مقدار برابر با 1 نباشه، یعنی رشته فرعی توی رشته اصلی وجود داره.
var mainString = "hello", subString = "hell"; mainString.indexOf(subString) !== -1;
استفاده از Regex: راه حل پیشرفته از روش test
عبارت Regular ('RegExp.test')
استفاده میکنه، که امکان آزمایش در برابر عبارات منظم رو فراهم میکنه.
var mainString = "hello", regex = /hell/; regex.test(mainString);
میتونیم با استفاده از Regex
ایمیل رو توی جاواسکریپت تأیید کنیم. توصیه میشه به جای سمت کلاینت، اعتبارسنجی سمت سرور انجام شه. چون جاواسکریپت رو میشه سمت کلاینت غیرفعال کرد.
function validateEmail(email) { var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(String(email).toLowerCase()); }
Regex
بالا کاراکترهای یونیک رو می پذیرد.
میتونیم از عبارت window.location.href
برای دریافت مسیر آدرس فعلی استفاده کنیم و میتونیم از همون عبارت برای بهروزرسانی URL هم استفاده کنیم. همچنین میتونیم از document.URL
برای اهداف فقط خواندنی استفاده کنیم اما این راهحل مشکلاتی در FF داره.
console.log("location.href", window.location.href); // Returns full URL
برای دسترسی به اجزای URL صفحه میتوان از ویژگیهای شی location
زیر استفاده کرد.
href - ورودی URL
protocol - پروتکل استفاده شده URL
host -هاست و پورت URL
hostname -هاست URL
port - شماره پورت URL
pathname - مسیر URL
search - قسمت جستجو URL
hash - محل جایگیری URL
میتونیم از URLSearchParams
برای دریافت مقادیر رشته پرس و جو توی جاواسکریپت استفاده کنیم. بیاین مثالی برای دریافت مقدار کد مشتری از رشته پرس و جو URL
ببینیم:
const urlParams = new URLSearchParams(window.location.search); const clientCode = urlParams.get("clientCode");
استفاده از عملگرها: میتونیم از عملگر in استفاده کنیم که آیا کلیدی توی آبجکت وجود داره یا نه
"key" in obj;
برای بررسی وجود یا عدم وجود کلید، باید از پرانتز استفاده کنیم
!("key" in obj);
استفاده از متد hasOwnProperty: میتونیم از hasOwnProperty
برای آزمایش ویژگیهای نمونه آبجکت (و نه ویژگیهای ارثی) استفاده کنیم.
obj.hasOwnProperty("key"); // true
استفاده از مقایسه undifiend: اگه بخوایم از یه آبجکت به یه ویژگی غیر موجود دسترسی پیدا کنیم، بهمون undifiend برمیگردونه. بیاین ویژگیها را با undefined مقایسه کنیم تا وجود ویژگی را مشخص کنیم.
const user = { name: "John", }; console.log(user.name !== undefined); // true console.log(user.nickName !== undefined); // false
میتونیم از حلقه for-in
برای حلقه زدن آبجکت جاواسکریپت استفاده کنیم. همچنین میتونیم مطمئن شیم که کلیدی که دریافت میکنیم ویژگی واقعی یه آبجکته و با استفاده از روش hasOwnProperty
از prototype، نیست.
var object = { k1: "value1", k2: "value2", k3: "value3", }; for (let key in object) { if (object.hasOwnProperty(key)) { console.log(key + " -> " + object[key]); // k1 -> value1 ... } }
راه حلهای مختلفی بر اساس نسخههای ECMAScript
وجود داره
object entries
استفاده کنیم و length
اونا رو چک کنیمObject.entries(obj).length === 0 && obj.constructor === Object; // Since date object length is 0, you need to check constructor check as well
object keys
استفاده کنیم و length
اونو چک کنیمObject.keys(obj).length === 0 && obj.constructor === Object; // Since date object length is 0, you need to check constructor check as well
for-in
استفاده کنیم و هر پارامتر رو با hasOwnProperty
چک کنیمfunction isEmpty(obj) { for (var prop in obj) { if (obj.hasOwnProperty(prop)) { return false; } } return JSON.stringify(obj) === JSON.stringify({}); }
آبجکت arguments یه آبجکت آرایه ماننده که داخل توابع قابل دسترسیه و حاوی مقادیر آرگومانهای ارسال شده به اون تابعه. برای مثال، بیاین ببینیم چطوری از آبجکت arguments توی تابع sum استفاده کنیم:
function sum() { var total = 0; for (var i = 0, len = arguments.length; i < len; ++i) { total += arguments[i]; } return total; } sum(1, 2, 3); // returns 6
نکته: ما نمیتونیم از متدهای ارایه برای آبجکت arguments
استفاده کنیم اما میتونیم به ارایه تبدیلش کنیم
let argsArray = [...arguments];
میتونیم با درست کردن یه تابع و با استفاده از زنجیره ای از متدهای string مثلا charAt
و toUpperCase
و slice
یه string با حرف اول بزرگ ایجاد کنیم
function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
حلقه for
یه syntax تکرار رایجه که از مزایا و معایبش میشه به موارد زیر اشاره کرد:
توی همهی محیطها env
کار میکنه
میتونیم از break
و continue
برای کنترل جریان داده استفاده کنیم
از لحاظ نوشتاری کد بیشتری باید نوشته بشه
Imperative هست
ممکنه با خطاهای one-by-off روبرو بشیم
میتونیم از کلاس new Date
استفاده کنیم و با اجرای متد toLocaleString()
تاریخ و زمان جدا شده توسط کاما رو بدست بیاریم :
const today = new Date().toLocaleString(); console.log(today.split(",")[0]); // 5/19/2022
برای این مقایسه نباید از اپراتورها استفاده کنیم. میتونیم مثل کد زیر از متد getTime که بر روی آبجکت Date قرار داره استفاده کنیم
var d1 = new Date(); var d2 = new Date(d1); console.log(d1.getTime() === d2.getTime()); //True console.log(d1 === d2); // False
میتونیم از متد startWith که بر روی پروتوتایپ String وجود داره استفاده کنیم که یه رشته رو میگیره و چک میکنه که رشته مورد نظر با اون رشته شروع میشه یا نه، برای مثال کد زیر رو براش مینویسیم:
"Good morning".startsWith("Good"); // true "Good morning".startsWith("morning"); // false
جاواسکریپت یه متد به ما میده به اسم trim
که روی رشتهها قرار داره با استفاده از این متد همه ی فضاهای خالی بین اون رشته برداشته میشه
" Hello World ".trim(); //Hello World
برای اضافه کردن key جدید به آبجکتها دو روش وجود داره
var object = { key1: value1, key2: value2, };
استفاده از dot: این روش زمانی موثر هستش که اسم پراپرتی رو میدونیم
object.key3 = "value3";
استفاده از کروشه[]: این روش زمانی موثر هستش که اسم پراپرتی داینامیک باشه
obj["key3"] = "value3";
نه! اپراتور خاص نیست اما ترکیب دو تا اپراتور استاندار هستش یکی بعد اون یکی
اپراتور نقییض (!)
کاهش کننده(--)
اول یه شماره از مقدار متغیر به مثال کم میشه بعد تست میشه که مساوی صفر هستش یا نه، که مشخصکننده درست یا غلط بودن شرط هست
میتونیم از عملگر یا اپراتور ||
برای تعریف یه مقدار پیشفرض استفاده کرد:
var a = b || c;
مثال تعریف شده بالا مقدار متغیر a زمانی برابر مقدار متغیر c خواهد شد که b خالی false یا undifined باشه.
میتونیم از /
برای تعریف کردن رشتههای چند خطی استفاده کنیم برای مثال:
const str = "This is a \ very lengthy \ sentence!";
اما اگه یه فاصله بعد /
داشته باشیم,کد دقیقا به همون حالتی که هست نشون داده میشه اما یه ارور خطای نوشتاری کد قراره داشته باشیم
روش بعدی استفاده کردن از backtick
هست که وقتی موقع تعریف رشته به جای کوتیشن مارک ازش استفاده بشه میتونیم راحت یه رشته چند خطی تعریف کنیم. برای مثال میشه کد زیر رو براش نوشت:
const str = `This is a very lengthy sentence!`;
application shell (shell) یکی از راههای ساخت PWA هستش که به طور قابل اعتماد و فوری بر روی صفحه نمایش کاربران شما بارگیری میشه، مشابه اونیکه توی برنامههای کاربردی native به کاربر نشون داده میشه. برای رسوندن سریع HTML اولیه به صفحه بدون نیاز به شبکه مفیده.
میتونیم برای توابع پراپرتی تعیین کنیم چون توابع اصولا آبجکت هستن.
const fn = function (x) { //Function code goes here }; fn.userName = "John"; fn.profile = function (y) { //Profile code goes here };
با استفاده کردن از function.length
میتونیم به تعداد پارامترهایی که یه تابع انتظار داره بگیره دسترسی داشته باشیم.
بریم یه مثال درموردش ببینیم:
function sum(num1, num2, num3, num4) { return num1 + num2 + num3 + num4; } sum.length; // 4 is the number of parameters expected.
plyfill
یه قسمت از کد جاواسکریپتـه که با استفاده از اون ما میتونیم توابع پیشرفته رو روی مروگرهایی که به طور طبیعی پشتیبانی نمیکنن,استفاده کنیم. پلاگین Silverlight
که برای تقلید کردن توابع بر روی canvas
یا مروگر IE7
استفاده کرد
دستور break
برای "پرش به بیرون" از یه حلقه استفاده میشه. یعنی حلقه رو میشکنه و اجرای کد رو بعد از حلقه ادامه میده.
for (i = 0; i < 10; i++) { if (i === 5) { break; } text += "Number: " + i + "<br>"; }
دستور continue
برای "پرش از روی" یه تکرار در حلقه استفاده میشه. یعنی یه تکرار (در حلقه) رو میشکنه، اگه شرایط مشخصی رخ بده، و با تکرار بعدی در حلقه ادامه میده.
for (i = 0; i < 10; i++) { if (i === 5) { continue; } text += "Number: " + i + "<br>"; }
دستور label
به ما اجازه میده تا حلقهها و بلوکها رو توی جاواسکریپت نام گذاری کنیم. بعد میتونیم از این برچسبها برای مراجعه به کد استفاده کنیم. برای مثال، کد زیر با استفاده از برچسبها از چاپ اعداد وقتی که یکسان هستن، جلوگیری میکنه.
loop1: for (let i = 0; i < 3; i++) { loop2: for (let j = 0; j < 3; j++) { if (i === j) { continue loop1; } console.log("i = " + i + ", j = " + j); } } // Output is: // "i = 1, j = 0" // "i = 2, j = 0" // "i = 2, j = 1"
توصیه میشه که تمام تعریف متغیرها رو بالای هر اسکریپت یا تابع انجام بدیم. مزیت این کار:
کد ما تمیز تر میشه
یه مکان واحد برای جستجوی متغیرهای محلی فراهم میکنه
میشه راحت از استفاده متفیرهای ناخواسته جلوگیری کرد
این کار محاسبات ناخواسته رو کمتر میکنه
توضیه میشه که حتما یه مقدار اولیه برای متغیرها تعیین بشه که دلایلشو چک میکنیم
خروجیمون کد تمیز تری میشه
این کار باعث میشه یه جا برای این متغییر رزرو بشه
از برگشتن خطای undefind
جلوگیری میشه
برای ساخت یه object
با مقادیر پیشفرض میتونیم به صورت زیر عمل کنیم
استفاده از {} به جای new Object
استفاده از "" به جای new String
استفاده از 0 به جای new Number
استفاده از false به جای new Boolean
استفاده از [] به جای new Array
استفاده از /()/ به جای new RegExp
استفاده از (){} به جایnew Function
بریم چند تا مثال ببینیم:
const v1 = {}; const v2 = ""; const v3 = 0; const v4 = false; const v5 = []; const v6 = /()/; const v7 = function () {};
برای تعریف آرایههای JSON از براکت استفاده میکنیم و هر تعداد که آبجکت خواستیم داخلش تعریف میکنیم.
بیاین یه مثال در موردش ببینیم
"users":[ {"firstName":"John", "lastName":"Abrahm"}, {"firstName":"Anna", "lastName":"Smith"}, {"firstName":"Shane", "lastName":"Warn"} ]
میتونیم از متد Math.random
برای ساخت یه عدد رندوم بین 0 تا 1 و از متد Math.floor
برای رند کردن اون عدد استفاده کنیم حالا اگه حاصل عدد به دست اومده رو ضربدر ده کنیم عددی بین یک تا ده خواهیم داشت
Math.floor(Math.random() * 10) + 1; // returns a random integer from 1 to 10 Math.floor(Math.random() * 100) + 1; // returns a random integer from 1 to 100
نکته: Math.random
یه عدد تصادفی بین 0 تا 1 ایجاد میکنه، یادمون باشه که استفاده از Math.floor
قبل ضرب کردن عدد رندوم به دست اومده در ده به عنوان کمترین مقدار، باعث میشه که خروجیمون همیشه به صفر رند بشه.
بله ما میتونیم کد زیر رو برای این تابع داشته باشیم که مقادیر حداکثر و حداقل رو بگیره و برای ما عدد رندوم ایجاد کنه:
function randomInteger(min, max) { return Math.floor(Math.random() * (max - min + 1) ) + min; } randomInteger(1, 100); // returns a random integer from 1 to 100 randomInteger(1, 1000); // returns a random integer from 1 to 1000
Tree Shaking
نوعی حذف کد مرده هستش و به این معنیه که ماژولهای استفاده نشده در طول فرآیند ساخت در بسته گنجونده نمیشن و برای اون بر ساختار استاتیک ماژول ES2015 متکیه (یعنی import و export). توی باندلر ماژول ES2015 'rollup' از این عملکرد استفاده شده.
Tree Shaking
میتونه اندازه کد رو در هر برنامه ای به میزان قابل توجهی کاهش بده. یعنی هرچی کد کمتری از طریق سیم بفرستیم برنامه کاربردی تره. به عنوان مثال، اگه فقط بخواهیم یه برنامه Hello World با استفاده از چارچوبهای SPA ایجاد کنیم، حدود چند مگابایت حافظه رو اشغال میکنه، اما tree-shaking میتونه اندازه رو به چند صد کیلوبایت کاهش بده. tree-shaking تو باندلرهای Rollup
و Webpack
پیاده سازی شده.
نه، eval
اجازه اجرای کد دلخواه رو میده که باعث ایجاد مشکل امنیتی میشه. همونطور که میدونیم از تابع eval
برای اجرای متن به عنوان کد استفاده میشه. در بیشتر موارد استفاده از اون ضروری نیست.
regular expression
یا همون Regex
یه توالیه که یه ساختار جستجو ایجاد میکنه با استفاده از این ساختار ما میتونیم دیتامون رو جستجو کنیم و به قولی دیتامون رو اعتبارسنجی کنیم.
/pattern/modifiers;
برای مثال Regex حساس به حروف کوچک و بزرگ زبان انگلیسی به صورت ریر نوشته میشه:
/John/i
Regular Expressions دو تا متد برای رشتهها داره : search
و replace
. متد search
یه عبارت رو میگیره اونو جستجو میکنه و محل اون عبارت رو برمیگردونه:
var msg = "Hello John"; var n = msg.search(/John/i); // 6
متد replace برای برگردوندن رشته اصلاح شده تو جایی که الگو جایگزین میشه، استفاده میشه:
var msg = "Hello John"; var n = msg.replace(/John/i, "Buttler"); // Hello Buttler
Modifiers
ها میتونن زمانی استفاده بشن که به جستجوهای بدون حروف کوچک و بزرگ سراسری نیاز داریم بیاین یه مثال درموردشون ببینیم:
اصلاح کننده | توضیح |
---|---|
i | تظبیق حساس به حروف |
g | تطبیق کلی به جای توقف در اولین تشابه |
m | تطبیق چندخطی |
بریم یه مثال از modifier گلوبال ببینیم:
const text = "Learn JS one by one"; const pattern = /one/g; const result = text.match(pattern); // one,one
Regex یه گروهی از ساختارها برامون اماده کرده که با اونا کاراکترها رو چک کنیم اونا تو سه مدل طبفه بندی میشن.
[abc]: برای پیدا کردن هر کاراکتری بین این سه کاراکتر استفاده میشه
[0-9]: برای پیدا کردن ارقام بین این دو عدد استفاده میشه
(a|b): برای پیدا کردن هر یه از گزینههای جدا شده با | استفاده میشه
\d: برای پیدا کردن اعداد استفاده میشه
\s: برای پیدا کردن فاصلهها استفاده میشه
\b: برای پیدا کردن کاراکترهای همخوانی داشته با شروع شدن یا پایانشون استفاده میشه
n+: برای پیدا کردن رشته همخوانی داشته با حداقل یه کاراکتر
n*: برای پیدا کردن همخوانی هر رشته شامل صفر یا بیشتر
n?: برای پیدا کردن هر رشته که شامل صفر یا یه کاراکنر میشه
object
های Regex
یه عبارت معمولی با پراپرتیها و متدهای تعریف شده از قبل هس. بریم یه مثال از نحوه استفادشون ببینیم.
var regexp = new RegExp('\\w+'); console.log(regexp); // expected output: /\w+/
میتونیم از متد test عبارت منظم برای جستجوی یه رشته برای الگو استفاده کنیم که بسته به نتیجه، true یا false رو برمیگردونه.
var pattern = /you/; console.log(pattern.test("How are you?")); //true
هدف متد exec شبیه به روش تسته اما جستجوی یه تطابق تو یه رشته مشخص رو انجام میده و یه آرایه نتیجه یا null رو به جای برگردوندن true/false برمیگردونه.
var pattern = /you/; console.log(pattern.exec("How are you?")); //["you", index: 8, input: "How are you?", groups: undefined]
میتونیم سبک درون خطی یا اسم کلاس یه عنصر HTML رو با استفاده از جاواسکریپت تغییر بدین
استفاده از پراپرتی style: با استفاده از ویژگی style میتونیم استایل درون خطی رو تغییر بدین
document.getElementById("title").style.fontSize = "30px";
استفاده از پراپرتی className: تغییر کلاس عنصر با استفاده از ویژگی className آسان است
document.getElementById("title").style.className = "custom-title";
خروجی '33' میشه. از اونجایی که «1» و «2» مقادیر عددی هستن، نتیجه دو رقم اول یه مقدار عددی «3» خواهد بود. رقم بعدی یه مقدار نوع رشته اس چون افزودن مقدار عددی «3» و مقدار رشته «3» فقط یه مقدار الحاقی «33» میشه.
دستور debugger هر گونه عملکرد اشکال زدایی موجود رو فراخوانی میکنه، مانند تعیین breakpoint. اگه هیچ عملکرد اشکال زدایی در دسترس نباشه، این عبارت تاثیری نداره.
برای مثال، در تابع زیر یه دستور debugger درج شده. بنابراین اجرا تو دستور debugger مثل یه breakpoint در منبع اسکریپت متوقف میشه.
function getProfile() { // code goes here debugger; // code goes here }
پس از اجرای دستور debugger و باز شدن پنجره دیباگر، میتونیم breakpointها رو در کد جاواسکریپت تنظیم کنیم. در هر breakpoint، جاواسکریپت اجرا نمیشه و به ما اجازه میده مقادیر جاواسکریپت رو بررسی کنیم. پس از بررسی مقادیر، میتونیم با استفاده از دکمه پخش، اجرای کد رو ادامه بدیم.
نه، ما نمیتونیم از کلمات رزرو شده به عنوان متغیر، برچسب، اسم آبجکت یا تابع استفاده کنیم. بیاین یه مثال ساده رو ببینیم:
let else = "hello"; // Uncaught SyntaxError: Unexpected token else
ما میتونیم با استفاده از Regex که یه boolean به ما برمیگردونه بفهمیم که مرورگری که کاربر داره ازش استفاده میکنه موبایل هست یا نه، کد تشخیص به این صورت نوشته میشه:
window.mobilecheck = function() { var mobileCheck = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) mobileCheck = true;})(navigator.userAgent||navigator.vendor||window.opera); return mobileCheck; };
میتونیم مرورگرهای تلفن همراه رو با اجرای فهرستی از دستگاهها و بررسی اینکه آیا useragent
با چیزی مطابقت داره یا نه، شناسایی کنیم. این یه راه حل جایگزین برای استفاده از RegExp هستش
function detectmob() { if( navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) ){ return true; } else { return false; } }
میتونیم با استفاده از جاواسکریپت به صورت برنامهریزی شده تصویر رو بدست بیاریم و ابعاد (عرض و ارتفاع) رو بررسی کنیم، برای مثال syntax بررسی میتونه طبق مثال زیر انجام بشه:
const img = new Image(); img.onload = function() { console.log(this.width + 'x' + this.height); } img.src = 'http://www.google.com/intl/en_ALL/images/logo.gif';
مرورگرها یه کلاس XMLHttpRequest
ارائه میدن که میتونه برای ایجاد درخواستهای HTTP
همزمان از جاواسکریپت استفاده شه.
function httpGet(theUrl) { const xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.open( "GET", theUrl, false ); // false for synchronous request xmlHttpReq.send( null ); return xmlHttpReq.responseText; }
مرورگرها یه کلاس XMLHttpRequest
رو ارائه میدن که میتونن برای درخواستهای HTTP
ناهمزمان از جاواسکریپت با ارسال پارامتر سوم به عنوان true
استفاده کنن.
function httpGetAsync(theUrl, callback) { var xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.onreadystatechange = function() { if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) callback(xmlHttpReq.responseText); } xmlHttp.open("GET", theUrl, true); // true for asynchronous xmlHttp.send(null); }
میتونیم از متد toLocaleString
برای تبدیل تاریخها تو یه منطقه زمانی به منطقه زمانی دیگه استفاده کنیم.بریم یه مثال درموردش ببینیم.
console.log(event.toLocaleString('en-GB', { timeZone: 'UTC' })); //29/06/2019, 09:56:00
میتونیم از ویژگیهای innerWidth،
innerHeight،
clientWidth،
clientHeight
ویندوز، عنصر document و آبجکت body document برای پیدا کردن اندازه یه پنجره استفاده کنیم. بیاین از ترکیب اونا برای محاسبه اندازه یه window یا document استفاده کنیم.
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; const height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
عملگر شرطی ternary
تنها عملگر جاواسکریپت هستش که سه عملوند رو میگیره که به عنوان میانبر برای دستور if عمل میکنه.
var isAuthenticated = false; console.log(isAuthenticated ? 'Hello, welcome' : 'Sorry, you are not authenticated'); //Sorry, you are not authenticated
بله، میتونیم زنجیرهسازی رو روی عملگرهای شرطی مشابه if … else if … else if… other chain
اعمال کنیم.
function traceValue(someParam) { return condition1 ? value1 : condition2 ? value2 : condition3 ? value3 : value4; } // The above conditional operator is equivalent to: function traceValue(someParam) { if (condition1) { return value1; } else if (condition2) { return value2; } else if (condition3) { return value3; } else { return value4; } }
window.onload:
window.onload = function ...
document.onload:
document.onload = function ...
body onload:
<body onload="script();">
__proto__
آبجکت واقعیه که در زنجیره جستجو برای حل متدها و غیره استفاده میشه. در حالی که prototype
آبجکتایـه که برای ساخت __proto__
استفاده میشه زمانی که یه آبجکت با new Object()
ایجاد میکنیم.
( new Employee ).__proto__ === Employee.prototype; ( new Employee ).prototype === undefined;
توصیه میشه که بعد از هر عبارت در جاواسکریپت از سیمیکالن استفاده کنیم. برای مثال، توی مثال زیر نذاشتن سیمیکالن، خطای .. is not a function
رو در زمان اجرا ایجاد میکنه:
// define a function const fn = function () { //... } // semicolon missing at this line // then execute some code inside a closure (function () { //... })();
از مثال بالا جاواسکریپت اینطور برداشت میکنه
const fn = function () { //... }(function () { //... })();
در این حالت، تابع دوم رو به عنوان آرگومان به تابع اول ارسال میکنیم و سعی میکنیم نتیجه فراخوانی تابع اول رو به عنوان تابع فراخوانی کنیم.بخاطر همین برای تابع دوم خطای.. is not a function
رو موقع اجرا میگیریم.
متد freeze برای فریز کردن یه آبجکت استفاده میشه. ثابت کردن یه آبجکت اجازه افزودن ویژگیهای جدید به یه آبجکت رو نمیده. از حذفش جلوگیری میکنه و از تغییر قابلیت شمارش پذیری، پیکربندی یا قابلیت نوشتن ویژگیهای موجود جلوگیری میکنه. یعنی آبجکتء ارسال شده رو برمیگردونه و کپی ثابتی ایجاد نمیکنه.
const obj = { prop: 100 }; Object.freeze(obj); obj.prop = 200; // Throws an error in strict mode console.log(obj.prop); //100
نکته: یه تایپ ارور بهمون میده که ارگومان داده شده object
نیست
برای فریز کردن آبجکتها و آرایهها
برای imutable
کردن آبجکتها
در پارادایم شی گرا، یه API
موجود حاوی عناصر خاصیه که قصد توسعه، اصلاح یا استفاده مجدد رو خارج از زمینه فعلی خودشون ندارن. در زبانهای مختلف کلمه کلیدیه final
برای داشتن همچین خاصیتی استفاده میشه.
ما میتونیم از آبجکت navigator
که بر روری مرورگر وجود داره این کارو انجام بدیم
var language = navigator.languages && navigator.languages[0] || // Chrome / Firefox navigator.language || // All browsers navigator.userLanguage; // IE <= 10 console.log(language);
ما میتونیم با تابع زیر این کارو انجام بدیم:
function toTitleCase(str) { return str.replace( /\w\S*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); } ); } toTitleCase("good morning john"); // Good Morning John
برای تشخیص غیرفعال بودن یا نبودن جاواسکریپت میتونیم از تگ <noscript>
استفاده کنیم. بلوک کد داخل <noscript>
زمانی اجرا میشه که جاواسکریپت غیرفعاله و معمولاً برای نمایش محتوای جایگزین زمانی که صفحه در جاواسکریپت تولید میشه، استفاده میشه.
<script type="javascript"> // JS related code goes here </script> <noscript> <a href="next_page.html?noJS=true">JavaScript is disabled in the page. Please click Next Page</a> </noscript>
یه عملگر قادر به دستکاری (محاسبات ریاضی و منطقی) مقدار یا عملوند معینه. اپراتورهای مختلفی توسط جاواسکریپت پشتیبانی میشن این اپراتورها هستن
عملگرهای حسابی: شامل + (اضافه),– (منها), * (ضرب), / (تقسیم), % (درصد), + + (اضافه کردن) و – – (کم کردن)
عملگرهای مقایسه ای: شامل = =(برابر),!= (غیر برابر), ===(برابر و تایپ برابر), > (بزرگتر),> = (بزرگتر مساوی),< (کوچکتر),<= (کوچکتر مساوی)
عملگرهای منطقی: شامل &&("و"منطقی),||("یا"منظقی),!( منطقی"نه")
عملگرهای تعیین مقدار: شامل = (اپراتور تعیین مقدار), += (اضافه کردن و تعیین مقدار), – = (منها کردن و تعیین مقدار), *= (ضرب و تعیین مقدار), /= (تقسیم و تعیین مقدار), %= (باقی مانده و تعیین مقدار)
اپراتور سه تایی: شامل اپراتورهای شرطی سه تایی
اپراتور تایپ: از اون برای پیدا کردن تایپ متغیرها استفاده میشه به صورت typeof variable
پارامتر Rest
یه روش بهبود یافته برای مدیریت پارامترهای تابع هستش که به ما امکان میده تعداد نامحدودی از آرگومانها رو به عنوان یه آرایه دریافت کنیم:
function f(a, b, ...theArgs) { // ... }
برای مثال، بیاین یه مثال مجموع برای محاسبه تعداد پویا پارامترها در نظر بگیریم،
function total(…args){ let sum = 0; for(let i of args){ sum+=i; } return sum; } console.log(fun(1,2)); //3 console.log(fun(1,2,3)); //6 console.log(fun(1,2,3,4)); //13 console.log(fun(1,2,3,4,5)); //15
نکته: پارامترRest
در ES6 به استاندارد جاوااسکریپت اضافه شد
پارامتر Rest
چون وظیفه اش جمع آوری تمام آرگومانهای باقی مونده تو یه آرایه اس پس باید همیشه آخرین پارامتر باشه. برای مثال، اگه تابعیو مثل کد زیر تعریف کنیم معنی نداره و یه خطا ایجاد میکنه:
function someFunc(a,…b,c){ //You code goes here return; }
به صورت بیتی AND ( & )
به صورت بیتی OR ( | )
به صورت بیتی XOR ( ^ )
به صورت بیتی NOT ( ~ )
تغییر مکان به چپ ( << )
علامت در حال انتشار به سمت راست ( >> )
صفر پر کردن Shift راست ( >>> )
عملگر Spread به تکرارپذیرها (آرایهها / اشیاء / رشتهها) اجازه میده تا به آرگومانها / عناصر منفرد گسترش پیدا کنن. برای مشاهده این رفتار مثالی بزنیم:
function calculateSum(x, y, z) { return x + y + z; } const numbers = [1, 2, 3]; console.log(calculateSum(...numbers)); // 6
متد Object.isFrozen
برای تعیین اینکه آیا یه آبجکت منجمد هس یا نه استفاده میشه. اگه همه شرایط زیر درست باشه، یه آبجکت منجمد میشه.
اگه قابل توسعه نباشه.
اگه تمام خصوصیاتش غیر قابل تنظیم باشن.
اگه تمام خصوصیات داده اون غیر قابل نوشتن باشه.
const object = { property: 'Welcome JS world' }; Object.freeze(object); console.log(Object.isFrozen(object));
متد Object.is
تعیین میکنه که آیا دو مقدار یه مقدار هستن یا نه. برای مثال، استفاده با انواع مختلف مقادیر،
Object.is('hello', 'hello'); // true Object.is(window, window); // true Object.is([], []) // false
اگه یکی از موارد زیر برقرار باشه، دو مقدار یکسان در نظر گرفته میشه:
هردو undefined
هردو null
هردو true یا هر دو false
هر دو رشته با طول یکسان با کاراکترهای مشابه به ترتیب یکسان
هر دو یه آبجکت (یعنی هر دو شی رفرنس یکسان دارن)
برای مقایسه دو رشته یا عدد و یا آبجکت با همدیگه و یا پیدا کردن قطبیت دو عدد استفاده میشه:
میتونیم از متد Object.assign
استفاده کنیم که برای کپی کردن مقادیر و ویژگیها از یه یا چند آبجکت منبع به یه آبجکت هدف استفاده میشه. آبجکت مورد نظر رو که دارای خواص و مقادیر کپی شده از آبجکت اولیه اس رو برمیگردونه.
Object.assign(target, ...sources)
بیاین با یه منبع و یه شی هدف مثال بزنیم،
const target = { a: 1, b: 2 }; const source = { b: 3, c: 4 }; const returnedTarget = Object.assign(target, source); console.log(target); // { a: 1, b: 3, c: 4 } console.log(returnedTarget); // { a: 1, b: 3, c: 4 }
همونطور که در کد بالا مشاهده شد، یه ویژگی مشترک (b
) از منبع به مقصد وجود داره، بنابراین مقداش بازنویسی شده.
برای شبیه سازی یه آبجکت .
برای ادغام آبجکتها با ویژگیهای یکسان .
آبجکت Proxy برای تعریف رفتار سفارشی برای عملیاتهای اساسی مثل جستجوی ویژگی، تخصیص، شمارش، فراخوانی تابع و غیره استفاده میشه.
var p = new Proxy(target, handler);
بیاین مثالی از شیء پروکسی بزنیم،
const handler = { get: function(obj, prop) { return prop in obj ? obj[prop] : 100; } }; const p = new Proxy({}, handler); p.a = 10; p.b = null; console.log(p.a, p.b); // 10, null console.log('c' in p, p.c); // false, 100
در کد بالا، از کنترلکننده «get» استفاده میکنه که رفتار پراکسی رو موقع انجام عملیات روی اون تعریف میکنه.
روش Object.seal برای مهر و موم کردن یه آبجکت با جلوگیری از اضافه شدن ویژگیهای جدید بهش و علامت گذاری تمام ویژگیهای موجود به عنوان غیر قابل تنظیم، استفاده میشه. اما مقادیر پراپرتیهای فعلی تا زمانی که قابل نوشتن باشن , قابل تغییر هستن. بیاین مثال زیرو برای درک بیشتر در مورد روش seal ببینیم
const object = { property: 'Welcome JS world' }; Object.seal(object); object.property = 'Welcome to object world'; console.log(Object.isSealed(object)); // true delete object.property; // You cannot delete when sealed console.log(object.property); //Welcome to object world
برای آب بندی آبجکتها و آرایهها استفاده میشه.
برای غیرقابل تغییر کردن یه آبجکت استفاده میشه.
اگه یه آبجکت با استفاده از متد Object.freeze
منجمد شه، ویژگیهاش تغییرناپذیر میشن و هیچ تغییری در اونا نمیتونیم ایجاد کنیم در حالی که اگه یه آبجکت با استفاده از متد Object.seal
مهر و موم شده باشه، میشه تغییرات روی ویژگیهای موجود ایجاد کرد.
متد Object.isSealed
برای تعیین مهر و موم بودن یا نبودن یه آبجکت استفاده میشه. اگه همه شرایط زیر درست باشه یه شی مهر و موم میشه
اگه قابل توسعه نباشه.
اگه تمام خصوصیات اون غیر قابل تنظیم باشن.
const object = { property: 'Hello, Good morning' }; Object.seal(object); // Using seal() method to seal the object console.log(Object.isSealed(object)); // checking whether the object is sealed or not
متد Object.entries
برای برگردوندن آرایهای از جفتهای [key, value] دارای کلید رشتهای شمارشپذیر یه شی معین، به همون ترتیبی که توسط یه حلقه for...in ارائه میشه، استفاده میشه. بیاین عملکرد متد object.entries
رو تو یه مثال ببینیم،
const object = { a: 'Good morning', b: 100 }; for (let [key, value] of Object.entries(object)) { console.log(`${key}: ${value}`); // a: 'Good morning' // b: 100 }
نکته: ترتیب به عنوان آبجکت تعریف شده تضمین نمیشه.
رفتار متد Object.values
مشابه روش Object.entries
هست اما به جای جفت [key,value] آرایه ای از مقادیر را برمیگردونه.
const object = { a: 'Good morning', b: 100 }; for (let value of Object.values(object)) { console.log(`${value}`); // 'Good morning' 100 }
میتونیم از متد Object.keys
استفاده کنیم که برای برگردوندن آرایهای از اسم ویژگیهای یه آبجکت معین استفاده میشه، به همون ترتیبی که با یه حلقه معمولی دریافت میکنیم. برای مثال:
const user = { name: 'John', gender: 'male', age: 40 }; console.log(Object.keys(user)); //['name', 'gender', 'age']
متد Object.create
برای ایجاد یه object جدید با object prototype و ویژگیهای مشخص شده استفاده میشه. برای مثال، از یه object موجود به عنوان prototype object جدید ایجاد شده استفاده میکنه. یه object جدید رو با object prototype و ویژگیهای مشخص شده برمیگردونه.
const user = { name: 'John', printInfo: function () { console.log(`My name is ${this.name}.`); } }; const admin = Object.create(user); admin.name = "Nick"; // Remember that "name" is a property set on "admin" but not on "user" object admin.printInfo(); // My name is Nick
WeakSet برای ذخیره مجموعه ای از اشیاء ضعیف (مرجع ضعیف) استفاده میشه.
new WeakSet([iterable]);
بیاین مثال زیرو برای توضیح رفتارش ببینیم،
var ws = new WeakSet(); var user = {}; ws.add(user); ws.has(user); // true ws.delete(user); // removes user from the set ws.has(user); // false, user has been removed
تفاوت اصلی اینه که ارجاع به اشیاء تو Set قویه در حالی که ارجاع به اشیا تو WeakSet ضعیفه. برای مثال، یه شی تو WeakSet میتونه زباله جمع آوری شه اگه مرجع دیگری به اون وجود نداشته باشه.
تفاوتهای دیگر عبارتند از
مجموعهها میتونن هر مقداری رو ذخیره کنن در حالی که WeakSets میتونه تنها مجموعه ای از اشیاء رو ذخیره کنه
WeakSet برخلاف Set دارای ویژگی اندازه نیست
WeakSet متدهایی مانند پاک کردن، کلیدها، مقادیر، ورودیها، forEach رو نداره.
WeakSet قابل تکرار نیست.
در زیر لیستی از روشهای موجود در WeakSet آمده است،
add(value): یه شی جدید با مقدار داده شده به مجموعه ضعیف اضافه میشه
delete(value): مقدار رو از مجموعه WeakSet حذف میکنه.
has(value): اگه مقدار در مجموعه WeakSet وجود داشته باشه true رو برمیگردونه در غیر این صورت false رو برمیگردونه.
var weakSetObject = new WeakSet(); var firstObject = {}; var secondObject = {}; // add(value) weakSetObject.add(firstObject); weakSetObject.add(secondObject); console.log(weakSetObject.has(firstObject)); //true console.log(weakSetObject.length()); //2 weakSetObject.delete(secondObject);
آبجکت WeakMap مجموعه ای از جفتهای کلید/مقداره که تو اون کلیدها به صورت ضعیف ارجاع داده شدن. در این حالت، کلیدها باید اشیا باشن و مقادیر میتونن مقادیر دلخواه باشن.برای مثال:
new WeakMap([iterable])
بیاین مثال زیرو برای توضیح رفتار اون ببینیم،
var ws = new WeakMap(); var user = {}; ws.set(user); ws.has(user); // true ws.delete(user); // removes user from the map ws.has(user); // false, user has been removed
تفاوت اصلی اینه که ارجاعات به آبجکتها کلیدی در نقشه قوی هستن در حالی که ارجاعات به اشیاء کلیدی در WeakMap ضعیف هستن. برای مثال، یه شی کلیدی در WeakMap در صورتی که هیچ مرجع دیگری بهش وجود نداشته باشه، میتونه زباله جمع آوری شه.
تفاوتهای دیگر عبارتند از
Mapها میتونن هر نوع کلیدی رو ذخیره کنن، در حالی که WeakMaps فقط میتونه مجموعه ای از اشیاء کلیدی رو ذخیره کنه
WeakMap برخلاف Map دارای ویژگی size نیست
WeakMap متدهایی مثل clear, keys, values, entries forEach رو نداره.
WeakMap قابل تکرار نیست.
set(key, value): مقدار کلید رو در آبجکت WeakMap تنظیم میکنه. آبجکت WeakMap رو برمیگردونه.
delete(key): هر مقدار مربوط به کلید رو حذف میکنه.
has(key): یه Boolean رو برمیگردونه که نشون میده آیا مقداری به کلید در آبجکت WeakMap مرتبط شده اس یا نه.
const weakMapObject = new WeakMap(); const firstObject = {}; const secondObject = {}; // set(key, value) weakMapObject.set(firstObject, 'John'); weakMapObject.set(secondObject, 100); console.log(weakMapObject.has(firstObject)); //true console.log(weakMapObject.get(firstObject)); // John weakMapObject.delete(secondObject);
uneval
یه تابع داخلیـه که برای ایجاد نمایش رشتهای از کد منبع یه شی استفاده میشه. این یه تابع سطح بالاس و با هیچ آبجکتای مرتبط نیست. بیاین مثال زیر رو درموردش ببینیم:
var a = 1; uneval(a); // returns a String containing 1 uneval(function user() {}); // returns "(function user(){})"
تابع encodeURI
برای رمزگذاری URI کامل استفاده میشه که دارای کاراکترهای خاص به جز (, / ? : @ & = + $ #) هست.
var uri = 'https://mozilla.org/?x=шеллы'; var encoded = encodeURI(uri); console.log(encoded); // https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B
تابع decodeURI
برای رمزگشایی یه شناسه منبع یکنواخت (URI) که قبلا توسط encodeURI ایجاد شده اس، استفاده میشه.
var uri = 'https://mozilla.org/?x=шеллы'; var encoded = encodeURI(uri); console.log(encoded); // https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B try { console.log(decodeURI(encoded)); // "https://mozilla.org/?x=шеллы" } catch(e) { // catches a malformed URI console.error(e); }
آبجکت window یه متد print ارائه میکنه که برای چاپ محتویات پنجره فعلی استفاده میشه. یه کادر محاوره ای چاپ رو باز میکنه که بهمون این امکان رو میده که بین گزینههای مختلف برای چاپ انتخاب کنیم. بیاین استفاده از روش چاپ رو تو یه مثال ببینیم،
<input type="button" value="Print" onclick="window.print()" />
نکته: بیشتر مرورگرها، زمانی که کادر چاپ بازه صفحه قفل میشه.
تابع 'uneval' منبع یه شی معین رو برمیگردونه. در حالی که تابع "eval" با ارزیابی اون کد منبع تو یه ناحیه حافظه متفاوت، برعکس عمل میکنه. بیاین مثالی رو برای روشن شدن تفاوت ببینیم،
var msg = uneval(function greeting() { return 'Hello, Good morning'; }); var greeting = eval(msg); greeting(); // returns "Hello, Good morning"
تابع ناشناس یه تابع بدون اسمه! توابع ناشناس معمولاً به یه نام متغیر اختصاص داده میشن یا به عنوان یه تابع callback استفاده میشن بریم یه مثال در موردش ببینیم،
function (optionalParameters) { //do something } const myFunction = function(){ //Anonymous function assigned to a variable //do something }; [1, 2, 3].map(function(element){ //Anonymous function used as a callback function //do something });
بیاین تابع ناشناس بالا رو تو یه مثال ببینیم،
var x = function (a, b) {return a * b}; var z = x(5, 10); console.log(z); // 50
یه متغیر local بر یه متغیر global با همون اسم ارجعیت داره. بیاین این رفتار رو تو یه مثال ببینیم.
const msg = "Good morning"; function greeting() { msg = "Good Evening"; console.log(msg); } greeting();
ECMAScript 5 accessor
های آبجکت جاواسکریپت یا ویژگیهای محاسبهشده رو از طریق گیرندهها و تنظیمکندنهها معرفی کرد. Getters از کلمه کلیدی "get" استفاده میکنه در حالی که Setters از کلمه کلیدی "set" استفاده میکنه.
const user = { firstName: "John", lastName : "Abraham", language : "en", get lang() { return this.language; } set lang(lang) { this.language = lang; } }; console.log(user.lang); // getter access lang as en user.lang = 'fr'; console.log(user.lang); // setter used to set lang as fr
متد استاتیک Object.defineProperty
برای تعریف یه ویژگی جدید به طور مستقیم بر روی یه آبجکت یا تغییر ویژگی موجود روی یه آبجکت استفاده میشه و آبجکت رو برمیگردونه. بیاین مثالی رو ببینیم تا بدونیم چجوری ویژگی رو تعریف کنیم:
const newObject = {}; Object.defineProperty(newObject, 'newProperty', { value: 100, writable: false }); console.log(newObject.newProperty); // 100 newObject.newProperty = 200; // It throws an error in strict mode due to writable setting
هر دو نتایج مشابهی دارن مگه اینکه از کلاسها استفاده کنیم. اگه از «get» استفاده میکنیم ویژگی روی prototype شی تعریف میشه، در حالی که با استفاده از Object.defineProperty
، ویژگی روی نمونهای که بهش اعمال میشه، تعریف میشه.
اونا syntax ساده تری ارائه میدن
اونا برای تعریف ویژگیهای محاسبه شده یا دسترسیها در JS استفاده میشن
برای ارائه رابطه هم ارزی بین خواص و روشها مفیدن
اونا میتونن کیفیت دادههای بهتری رو ارائه بدن
برای انجام کارها در پشت صحنه با منطق محصور شده مفیدن.
بله، میتونیم از روش Object.defineProperty
برای اضافه کردن Getters و Setter استفاده کنیم. برای مثال،آبجکت شمارنده زیر از ویژگیهای افزایش، کاهش، جمع و تفریق استفاده میکنه:
const obj = {counter : 0}; // Define getters Object.defineProperty(obj, "increment", { get : function () {this.counter++;} }); Object.defineProperty(obj, "decrement", { get : function () {this.counter--;} }); // Define setters Object.defineProperty(obj, "add", { set : function (value) {this.counter += value;} }); Object.defineProperty(obj, "subtract", { set : function (value) {this.counter -= value;} }); obj.add = 10; obj.subtract = 5; console.log(obj.increment); //6 console.log(obj.decrement); //5
عبارت switch case
تو جاواسکریپت برای اهداف تصمیم گیری استفاده میشه. توی چند مورد، استفاده از دستور switch case راحتتر از if-else هست. بریم یه مثال در موردش ببینیم:
switch (expression) { case value1: statement1; break; case value2: statement2; break; . . case valueN: statementN; break; default: statementDefault; }
دستور چند حالته بالا یه راه آسون برای انجام عملیات مختلف بهمون میده که بر اساس مقدار مبنا میشه عملکردهای مختلفی رو در نظر گرفت.
عبارت میتونه از نوع عددی یا رشتهای باشه.
مقادیر تکراری برای عبارت مجاز نیستن.
بیانیه default اختیاریه. اگه عبارت ارسال شده به سوئیچ با هیچ مقدار case مطابقت نداشته باشه، دستور تو حالت پیش فرض اجرا میشه.
دستور break در داخل سوئیچ برای پایان دادن به دنباله دستور استفاده میشه.
عبارت break اختیاریه. اما اگه حذف شه، اجرا در مورد بعدی ادامه پیدا میکنه
یه نوع داده primitive
دادهایه که دارای یه مقدار اولیه اس (که هیچ ویژگی یا روشی نداره). 5 نوع نوع داده اولیه وجود داره.
string
number
boolean
null
undefined
دسترسی با نقطه: از نقطه برای دسترسی به ویژگیها استفاده میکنه
objectName.property
دسترسی با کروشه: از کروشه برای دسترسی به دیتا استفاده میکنه
objectName["property"]
objectName[expression]
تعاریف تابع انواع دادهها رو برای پارامترها مشخص نمیکنه.
بررسی نوع آرگومانهای ارسال شده رو انجام ندین.
function functionName(parameter1, parameter2, parameter3) { console.log(parameter1); // 1 } functionName(1);
error object
یه آبجکت خطای داخلیه که موقع بروز خطا، اطلاعات خطا رو ارائه میده و این دو ویژگی رو داخلش داره: name و messge. برای مثال، تابع زیر جزئیات خطا رو ثبت میکنه:
try { greeting("Welcome"); } catch(err) { console.log(err.name + "<br>" + err.message); }
اگه بخواییم کد رو با یه خطای syntax ارزیابی کنیم یه SyntaxError ارسال میشه. برای مثال، کد زیر برای پارامتر تابع یه خطای syntax ایجاد میکنه:
try { eval("greeting('welcome)"); // Missing ' will produce an error } catch(err) { console.log(err.name); }
نام خطا | توضیحات |
---|---|
EvalError | خطایی تو تابع eval رخ داده |
RangeError | خطایی با عدد "خارج از محدوده" |
خطای مرجع | خطا به دلیل ارجاع غیرقانونی |
SyntaxError | خطای ناشی از خطای syntax |
TypeError | خطای ناشی از خطای type |
خطای URIE | یه خطا به دلیل encodeURI |
try: این عبارت برای آزمایش یه بلوک کد برای خطاها استفاده میشه
catch: این عبارت برای رسیدگی به خطا استفاده میشه
throw: این عبارت برای ایجاد خطاهای سفارشی استفاده میشه.
finally: این عبارت برای اجرای کد پس از تلاش و گرفتن بدون توجه به نتیجه استفاده میشه.
حلقههای کنترل شده توسط ورودی: تو این نوع حلقه، شرایط تست قبل از ورود به بدنه حلقه آزمایش میشه. برای مثال For Loop و while Loop تو این دسته قرار میگیرن.
حلقههای کنترل شده توسط خروجی: در این نوع حلقه، شرایط تست در انتهای بدنه حلقه آزمایش یا ارزیابی میشه. یعنی بدنه حلقه حداقل یه بار بدون در نظر گرفتن شرایط تست true یا false اجرا میشه. برای مثال، حلقه do-while در این دسته قرار میگیره.
Node.js یه پلتفرم سمت سروره که بر اساس زمان اجرا جاواسکریپت کروم برای ساخت آسان برنامههای شبکه سریع و مقیاس پذیر ساخته شده. این یه زمان اجرا I/O ناهمزمان مبتنی بر رویداد، غیر مسدود کننده اس که از موتور جاواسکریپت V8 گوگل و کتابخونه libuv استفاده میکنه.
آبجکت Intl
فضای نامی برای ECMAScript Internationalization
API اس که مقایسه رشتههای حساس زبان، قالب بندی اعداد و قالب بندی تاریخ و زمان رو ارائه میده. دسترسی به چندین سازنده و توابع حساس به زبان رو فراهم میکنه.
میتونیم از کلاس Intl.DateTimeFormat
استفاده کنیم که سازنده آبجکتهاییه که قالب بندی تاریخ و زمان حساس به زبان رو فعال میکنه. بیاین این رفتار رو با یه مثال ببینیم،
var date = new Date(Date.UTC(2019, 07, 07, 3, 0, 0)); console.log(new Intl.DateTimeFormat('en-GB').format(date)); // 07/08/2019 console.log(new Intl.DateTimeFormat('en-AU').format(date)); // 07/08/2019
Iterator
آبجکتایـه که پس از خاتمه، یه توالی و یه مقدار بازگشتی رو تعریف میکنه. پروتکل Iterator رو با متد «next» پیادهسازی میکنه که یه شی رو با دو ویژگی برمیگردونه: «value» (مقدار بعدی در دنباله) و «done» (که اگه آخرین مقدار در دنباله مصرف شده باشه درسته. ).
تکرار همزمان در ES6 معرفی شد و با مجموعه ای از اجزای زیر کار میکنه:
Iterable: این یه آبجکتایـه که میتونه از طریق روشی که کلید اون Symbol.iterator هس تکرار شه.
Iterator: این یه آبجکتایـه که با فراخوانی «[Symbol.iterator]» بر روی یه تکرار برگردونده میشه. این آبجکت تکرار شونده هر عنصر تکرار شده رو تو یه آبجکت پیچیده میکنه و اونو از طریق متد «next» یکی یکی برمیگردونه.
IteratorResult: این یه آبجکتایـه که با متد «next» برگردونده میشه. آبجکت شامل دو ویژگی است. ویژگی "value" حاوی یه عنصر تکرار شده و ویژگی "done" تعیین میکنه که آیا عنصر آخرین عنصر هست یا نه.
بیاین تکرار همزمان رو با آرایه ای مانند زیر نشون بدیم،
const iterable = ['one', 'two', 'three']; const iterator = iterable[Symbol.iterator](); console.log(iterator.next()); // { value: 'one', done: false } console.log(iterator.next()); // { value: 'two', done: false } console.log(iterator.next()); // { value: 'three', done: false } console.log(iterator.next()); // { value: 'undefined, done: true }
event loop
یه صف از توابع callback موقعی که یه تابع async اجرا میشه، تابع callback در صف قرار میگیرد. موتور جاواسکریپت پردازش حلقه رویداد رو شروع نمیکنه تا زمانی که تابع async اجرای کد رو تموم کنه.
نکته: این به Node.js اجازه میده تا عملیات I/O غیر مسدود کننده رو انجام بده حتی اگه جاواسکریپت تک رشتهای باشه.
Call Stack یه ساختار داده برای مفسران جاواسکریپتـه تا فراخونیهای تابع تو برنامه رو پیگیری کنه و دو عمل عمده داره،
هر زمان که یه تابع رو برای اجرای آن فراخوانی میکنیم اونو به stack
هدایت میشه.
هر زمان که اجرا کد تموم شه، تابع از stack
خارج میشه.
بیاین یه مثال و توضیح خلاصه اون در قالب نمودار رو باهم ببینیم:
function hungry() { eatFruits(); } function eatFruits() { return "I'm eating fruits"; } // Invoke the `hungry` function hungry();
کد بالا تو یه call-stack به صورت زیر پردازش میشه.
تابع 'hungry' رو به لیست call-stack اضافه میشه و کد رو اجرا میشه.
تابع 'eatFruits' رو به لیست call-stack اضافه میشه و کد رو اجرا میشه.
تابع 'eatFruits' از لیست call-stack ما حذف میشه.
تابع 'eatFruits' از لیست call-stack ما حذف میشه.
Event-queue
مسئول ارسال توابع جدید به stack برای پردازشه. ساختارش به صورت صف داده اس تا توالی درستی رو نگه داره و همه عملیات باید برای اجرا ارسال شن.
Decorator
عبارتیه که یه تابع رو ارزیابی میکنه و هدف، نام و توصیفکننده تزئین رو به عنوان آرگومان میگیره. همچنین، به صورت اختیاری یه توصیفگر دکوراتور رو برای نصب بر روی آبجکت مورد نظر برمیگردونه. بیاین در زمان طراحی، دکوراتور ادمین رو برای کلاس کاربر تعریف کنیم:
function admin(isAdmin) { return function(target) { target.isAdmin = isAdmin; } } @admin(true) class User() { } console.log(User.isAdmin); //true @admin(false) class User() { } console.log(User.isAdmin); //false
Collator: آبجکتهایی هستن که مقایسه رشتههای حساس به زبان رو امکان پذیر میکنن.
DateTimeFormat: آبجکتهایی هستن که قالب بندی تاریخ و زمان حساس به زبان رو فعال میکنن.
ListFormat: آبجکتهایی هستن که قالب بندی لیست حساس به زبان رو فعال میکنن.
NumberFormat: آبجکتهایی که قالب بندی اعداد حساس به زبان رو فعال میکنن.
PluralRules: آبجکتهایی که قالب بندی حساس به جمع و قوانین خاص زبان رو برای جمع فعال میکنن.
RelativeTimeFormat: آبجکتهایی که قالب بندی زمان نسبی حساس به زبان رو فعال میکنن.
عملگر unary(+) برای تبدیل یه متغیر به عدد استفاده میشه. اگه متغیر قابل تبدیل نباشه، همچنان به عدد تبدیل میشه اما با مقدار NaN. بیاین این رفتار رو تو یه عمل ببینیم:
const x = "100"; const y = + x; console.log(typeof x, typeof y); // string, number const a = "Hello"; const b = + a; console.log(typeof a, typeof b, b); // string, number, NaN
متد sort
برای مرتب سازی عناصر یه آرایه در جای خود استفاده میشه و آرایه مرتب شده رو برمیگردونه. برای مثال
const months = ["Aug", "Sep", "Jan", "June"]; months.sort(); console.log(months); // ["Aug", "Jan", "June", "Sep"]
از compareFunction
برای تعریف ترتیب مرتب سازی استفاده میشه. اگه حذف شه، عناصر آرایه به رشته تبدیل میشن، سپس بر اساس مقدار نقطه کد یونیک هر کاراکتر مرتب میشن بیاین مثالی بزنیم تا کاربرد compareFunction رو ببینیم،
let numbers = [1, 2, 5, 3, 4]; numbers.sort((a, b) => b - a); console.log(numbers); // [5, 4, 3, 2, 1]
برای معکوس کردن عناصر یه آرایه میتونیم از متد reverse استفاده کنیم. این روش برای مرتب کردن یه آرایه به ترتیب نزولی مفید است. بیاین استفاده از متد reverse رو تو یه مثال ببینیم،
let numbers = [1, 2, 5, 3, 4]; numbers.sort((a, b) => b - a); console.log(numbers); // [5 ,4 ,3 ,2 ,1]
میتونیم از روشهای Math.mix
و Math.max
روی متغیرهای آرایه برای یافتن حداقل و حداکثر عناصر تو یه آرایه استفاده کنیم. بیاین دو تابع برای پیدا کردن مقدار min و max تو یه آرایه ایجاد کنیم:
const marks = [50, 20, 70, 60, 45, 30]; function findMin(arr) { return Math.min(...arr) } function findMax(arr) { return Math.max(...arr)); } console.log(findMin(marks)); console.log(findMax(marks));
ما میتونیم توابعی بنویسیم که تو یه آرایه حلقه میزنن و هر مقدار را با کمترین یا بالاترین مقدار مقایسه میکنن تا مقادیر حداقل و حداکثر رو پیدا کنن. بریم یه مثال درموردش ببینیم:
const marks = [50, 20, 70, 60, 45, 30]; function findMin(arr) { let min = arr[0]; for (let i = 0; i < arr.length; i++) { if (arr[i] < minNumber) { min = arr[i] } } return min; } function findMax(arr) { let max = arr[0]; for (let i = 0; i < arr.length; i++) { if (arr[i] > minNumber) { max = arr[i] } } return max; } console.log(findMin(marks)); console.log(findMax(marks));
سیمیکالن ;
هس که نشون میده هیچ دستوری اجرا نمیشه، حتی اگه syntax جاواسکریپت به اون نیاز داشته باشه. از اونجایی که هیچ اقدامی با دستور خالی وجود نداره، ممکنه فکر کنیم که استفاده از اون خیلی کمه اما دستور خالی موقعی مفیده که میخواین یه حلقه ایجاد کنیم که بدنهاش خالیه. برای مثال، میتونیم یه آرایه با مقادیر صفر رو مثل کد زیر مقداردهی اولیه کنیم.
// Initialize an array a for(int i=0; i < a.length; a[i++] = 0) ;
میتونیم از آبجکت import.meta
استفاده کنیم که یه ویژگی متاعه که متا دادههای متنی خاص رو تو یه ماژول جاوا اسکریپت قرار میده. این شامل اطلاعاتی در مورد ماژول فعلی، مانند URL ماژوله. در مرورگرها، ممکنه متا دادههای متفاوتی نسبت به NodeJS دریافت کنیم.
<script type="module" src="welcome-module.js"></script> <script> console.log(import.meta); // { url: "file:///home/user/welcome-module.js" } </script>
عملگر کاما برای ارزیابی هر یه از عملوندهاش از چپ به راست استفاده میشه و مقدار آخرین عملوند رو برمیگردونه. این کاملاً با استفاده از کاما در آرایهها، اشیاء و آرگومانها و پارامترهای تابع متفاوته. بریم یه مثال در موردش ببینیم.
var x = 1; x = (x++, x); console.log(x); // 2
معمولاً برای گنجوندن چن تا عبارت تو جایی که به یه عبارت واحد نیاز داره استفاده میشه. یکی از کاربردهای رایج این عملگر کاما، ارائه چندین پارامتر تو یه حلقه «for» اس. برای مثال، حلقه for زیر از چند عبارت تو یه مکان واحد با استفاده از عملگر کاما استفاده میکنه.
for (var a = 0, b =10; a <= 10; a++, b--)
همچنین میتونیم از عملگر کاما تو یه عبارت بازگشتی استفاده کنیم جایی که قبل از بازگشت پردازش میکنه.
function myFunction() { let a = 1; return (a += 10, a); // 11 }
TypeScript یه ابر مجموعه تایپ شده از جاواسکریپتـه که توسط مایکروسافت ایجاد شده که انواع اختیاری، کلاسها، async/wait و بسیاری ویژگیهای دیگر رو اضافه میکنه و به جاواسکریپت ساده کامپایل میکنه. Angular به طور کامل در TypeScript ساخته شده و به عنوان زبان اصلی استفاده میشه. میتونیم اونو به صورت گلوبال نصب کنیم:
npm install -g typescript
بیاین یه مثال ساده از استفاده از TypeScript رو ببینیم،
function greeting(name: string): string { return "Hello, " + name; } let user = "Ali Karimi"; console.log(greeting(user));
متد greeting
فقط نوع رشته رو به عنوان آرگومان مجاز میکنه.
ویژگی | typescript | javascript |
---|---|---|
پارادایم زبان | زبان برنامه نویسی شی گرا | زبان اسکریپت |
پشتیبانی از تایپ | پشتیبانی از تایپ استاتیک | دارای تایپ پویا |
ماژولها | پشتیبانی شده | پشتیبانی نمیشه |
رابط | دارای مفهوم رابط | از رابطها پشتیبانی نمیکنه |
پارامترهای اختیاری | توابع از پارامترهای اختیاری پشتیبانی میکنن | عدم پشتیبانی از پارامترهای اختیاری برای توابع |
TypeScript میتونه خطاهای زمان کامپایل رو فقط در زمان توسعه پیدا کنه و باعث میشه خطاهای زمان اجرا کمتر شه. در حالی که جاواسکریپت یه زبان تفسیر شده است.
TypeScript به شدت تایپ میشه یا از تایپ استاتیک پشتیبانی میکنه که امکان بررسی صحت نوع رو در زمان کامپایل فراهم میکنه. این در جاواسکریپت در دسترس نیست.
کامپایلر TypeScript برخلاف ویژگیهای ES6 جاواسکریپت که ممکنه در بعضی از مرورگرها پشتیبانی نشه، میتونه فایلهای .ts رو در ES3، ES4 و ES5 کامپایل کنه.
object-initializer
عبارتیه که مقدار دهی اولیه یه آبجکت رو توصیف میکنه. syntax این عبارت به صورت فهرستی با کاما از صفر یا چند جفت نام ویژگی و مقادیر مرتبط یه آبجکت، محصور در براکت ({}) نشون داده میشه. این همچنین به عنوان نماد تحت اللفظی شناخته میشه. یکی از راههای ایجاد یه آبجکته.
const initObject = {a: 'John', b: 50, c: {}}; console.log(initObject.a); // John
متد constructor
یه متد خاص برای ایجاد و مقداردهی اولیه یه آبجکت ایجاد شده تو یه کلاسه. اگه متد constructor رو مشخص نکنیم از constructor پیش فرض استفاده میشه. بریم یه مثال در موردش ببینیم:
class Employee { constructor() { this.name = "John"; } } const employeeObject = new Employee(); console.log(employeeObject.name); // John
constructor
تو یه کلاس یه متد خاصه و باید فقط یه بار تو یه کلاس تعریف شه. اگه یه متد سازنده رو بیش از یه بار تو یه کلاس بنویسیم، یه خطای SyntaxError
ایجاد میشه.
class Employee { constructor() { this.name = "John"; } constructor() { // Uncaught SyntaxError: A class may only have one constructor this.age = 30; } } const employeeObject = new Employee(); console.log(employeeObject.name);
میتونیم از کلمه کلیدی super
برای فراخوانی constructor کلاس والد استفاده کنیم. یادمون باشه که super
باید قبل از استفاده از مرجع this
فراخوانی شه. در غیر این صورت باعث خطای Reference error
میشه. بیاین از اون استفاده کنیم:
class Square extends Rectangle { constructor(length) { super(length, length); this.name = 'Square'; } get area() { return this.width * this.height; } set area(value) { this.area = value; } }
میتونیم از روش Object.getPrototypeOf
(obj) برای برگردوندن prototype
آبجکت مشخص شده استفاده کنیم. یعنی مقدار ویژگی prototype
داخلی. اگه هیچ ویژگی ارثی وجود نداشته باشه، مقدار null
برگردونده میشه.
const newPrototype = {}; const newObject = Object.create(newPrototype); console.log(Object.getPrototypeOf(newObject) === newPrototype); // true
در ES5، اگه پارامتر obj یه آبجکت نباشه، یه استثنا TypeError ایجاد میکنه. در حالی که در ES2015، پارامتر به یه آبجکت اجباری تبدیل میشه.
// ES5 Object.getPrototypeOf('James'); // TypeError: "James" is not an object // ES2015 Object.getPrototypeOf('James'); // String.prototype
میتونیم از متد Object.setPrototypeOf
استفاده کنیم که prototype (یعنی ویژگی داخلی «Prototype») یه آبجکت مشخص شده رو روی یه آبجکت دیگه یا تهی تنظیم میکنه. برای مثال، اگه بخوایم prototype آبجکت Square رو روی آبجکت Rectangle تنظیم کنیم این شکلی میشه این کارو انجام داد:
Object.setPrototypeOf(Square.prototype, Rectangle.prototype); Object.setPrototypeOf({}, null);
متد Object.isExtensible
برای تعیین اینکه یه آبجکت قابل توسعه هس یا نه ( یعنی اینکه میتونه ویژگیهای جدیدی به اون اضافه شه یا نه) استفاده میشه.
const newObject = {}; console.log(Object.isExtensible(newObject)); //true
نکته: به طور پیش فرض، همه ی آبجکتها قابل گسترش هستن. برای مثال، ویژگیهای جدید رو میتونیم اضافه یا تغییر بدیم.
متد Object.preventExtensions
برای جلوگیری از افزودن ویژگیهای جدید به یه آبجکت استفاده میشه. به عبارت دیگر، از پسوندهای بعدی به آبجکت جلوگیری میکنه. بیاین استفاده از این ویژگی رو ببینیم:
const newObject = {}; Object.preventExtensions(newObject); // NOT extendable try { Object.defineProperty(newObject, 'newProperty', { // Adding new property value: 100 }); } catch (e) { console.log(e); // TypeError: Cannot define property newProperty, object is not extensible }
میتونیم یه آبجکت غیر قابل گسترش رو به 3 روش علامت گذاری کنیم.
Object.preventExtensions
Object.seal
Object.freeze
var newObject = {}; Object.preventExtensions(newObject); // Prevent objects are non-extensible Object.isExtensible(newObject); // false var sealedObject = Object.seal({}); // Sealed objects are non-extensible Object.isExtensible(sealedObject); // false var frozenObject = Object.freeze({}); // Frozen objects are non-extensible Object.isExtensible(frozenObject); // false
متد Object.defineProperties
برای تعریف یا اصلاح ویژگیهای موجود مستقیماً روی یه آبجکت و برگردوندن آبجکت استفاده میشه. بیاین چندین ویژگی رو روی یه آبجکت خالی تعریف کنیم:
const newObject = {}; Object.defineProperties(newObject, { newProperty1: { value: 'John', writable: true }, newProperty2: {} });
دسته MEAN (MongoDB، Express، AngularJS و Node.js) محبوبترین دستهبندی فناوری نرمافزار جاواسکریپت منبع بازه که برای ساخت برنامههای وب پویا در دسترسه، جایی که میتونیم کدهای سمت سرور و سمت کلاینت پروژه وب رو کاملا با جاواسکریپت بنویسین.
Obfuscation
عمل عمدی ایجاد کد جاواسکریپت مبهم (یعنی کد منبع یا ماشین) هس که درک اون برای انسان سخته. این چیزی شبیه به رمزگذاریه، اما یه ماشین میتونه کد رو درک کنه و اونو اجرا کنه.
بیاین تابع زیر رو قبل از Obfuscation ببینیم،
function greeting() { console.log('Hello, welcome to JS world'); }
و بعد از کد Obfuscation به صورت زیر ظاهر میشه
eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('2 1(){0.3(\'4, 7 6 5 8\')}',9,9,'console|greeting|function|log|Hello|JS|to|welcome|world'.split('|'),0,{}))
اندازه کد کمتر میشه. که باعث انتقال سریع تر داده بین سرور و کلاینت میشه.
این منطق کسب و کار رو از دنیای خارج پنهان میکنه و از کد در برابر دیگران محافظت میکنه
مهندسی معکوس کردن کد رو سخت میکنه
زمان دانلود کاهش پیدا میکنه
Minification
حذف تمام کاراکترهای غیر ضروریه (فضاهای خالی حذف میشن) و متغیرها بدون تغییر در عملکر اون تغییر نام میدن همچنین برای مبهم سازی کد هم استفاده میشه.
به طور معمول توصیه میشه برای ترافیک سنگین و نیازهای فشرده منابع از Minification استفاده کنیم. اندازه فایل رو با مزایای زیر کاهش میده
زمان بارگذاری یه صفحه وب رو کاهش میده
در مصرف پهنای باند صرفه جویی میکنه
ویژگی | Obfuscation | Encryption |
---|---|---|
تعریف | تغییر فرم هر داده به هر شکل دیگر | تغییر فرم اطلاعات به فرمت ناخوانا با استفاده از کلید |
کلیدی برای رمزگشایی | میشه اونو بدون هیچ کلید رمزگشایی کرد | برای رمز گشایی کلید لازمه |
فرمت دادههای هدف | به فرم پیچیده تبدیل میشه | تبدیل به فرمت ناخوانا |
کامپایلر بسته شدن گوگل
UglifyJS2
jsmin
میشه از جاواسکریپت برای اعتبار سنجی فرم HTML استفاده کرد. برای مثال، اگه فیلد فرم خالی باشه، تابع باید اطلاع بده و false رو برگردونه تا از ارسال فرم جلوگیری شه.
بریم ورود کاربر رو در فرم html انجام بدیم:
<form name="myForm" onsubmit="return validateForm()" method="post"> User name: <input type="text" name="uname"> <input type="submit" value="Submit"> </form>
و اعتبار سنجی ورود کاربر به این شکل هست.
function validateForm() { const x = document.forms["myForm"]["uname"].value; if (x == "") { alert("The username shouldn't be empty"); return false; } }
میتونیم بدون استفاده از جاواسکریپت اعتبار سنجی فرم HTML رو به صورت خودکار انجام بدین. اعتبار سنجی با اعمال ویژگی required
برای جلوگیری از ارسال فرم زمانی که ورودی خالیه فعال میشه.
<form method="post"> <input type="text" name="uname" required> <input type="submit" value="Submit"> </form>
نکته: اعتبار سنجی فرم خودکار برای IE9 یا ورژنهای قبل از اون کار نمیکنه.
checkValidity: اگه یه عنصر ورودی حاوی دادههای معتبر باشه، مقدار true رو برمیگردونه.
function myFunction() { var userName = document.getElementById("uname"); if (!userName.checkValidity()) { document.getElementById("message").innerHTML = userName.validationMessage; } else { document.getElementById("message").innerHTML = "Entered a valid username"; } }
validity: فهرستی از ویژگیهای بولین مربوط به اعتبار یه عنصر ورودی رو ارائه میده.
validationMessage: زمانی که اعتبار نادرست باشه، پیام رو نمایش میده.
willValidate: این نشون میده که آیا یه عنصر ورودی اعتبار سنجی میشه یا نه.
ویژگی validity
یه عنصر ورودی مجموعه ای از ویژگیهای مربوط به اعتبارسنجی دادهها رو ارائه میده.
customError: اگه یه پیام اعتبار سفارشی تنظیم شده باشه، true رو برمیگردونه.
patternMismatch: اگه مقدار یه عنصر با ویژگی الگوی آن مطابقت نداشته باشه، مقدار true رو برمیگردونه.
rangeOverflow: اگه مقدار یه عنصر از ویژگی max آن بیشتر باشه، مقدار true رو برمیگردونه.
rangeUnderflow:اگه مقدار یه عنصر کمتر از ویژگی min باشه، مقدار true رو برمیگردونه.
stepMismatch:اگه مقدار عنصر مطابق با ویژگی step نامعتبر باشه، مقدار true رو برمیگردونه.
tooLong: اگه مقدار یه عنصر از ویژگی maxLength آن بیشتر شه، مقدار true رو برمیگردونه.
typeMismatch: اگه مقدار یه عنصر بر اساس ویژگی نوع نامعتبر باشه، مقدار true رو برمیگردونه.
valueMissing: اگه عنصری با ویژگی مورد نیاز ارزش نداشته باشه، مقدار true رو برمیگردونه.
valid: اگه مقدار یه عنصر معتبر باشه، مقدار true رو برمیگردونه.
اگه مقدار یه عنصر از ویژگی max اون بیشتر باشه، ویژگی rangeOverflow
مقدار true رو برمیگردونه. برای مثال، توی فرم پایین اگه مقدار ورودی بیش از 100 باشه، خطا میده.
<input id="age" type="number" max="100"> <button onclick="myOverflowFunction()">OK</button>
function myOverflowFunction() { if (document.getElementById("age").validity.rangeOverflow) { alert("The mentioned age is not allowed"); } }
نه، جاواسکریپت به صورت بومی از enum
ها پشتیبانی نمیکنه. اما انواع مختلفی از راهحلها برای شبیهسازی اونا وجود داره، اگرچه ممکنه معادلهای دقیقی ارائه نکنن. برای مثال، میتونیم از freeze
یا seal
روی آبجکت استفاده کنیم:
const DaysEnum = Object.freeze({"monday":1, "tuesday":2, "wednesday":3, ...})
enum
نوعیه که متغیرها رو به یه مقدار از مجموعه ای از ثابتهای از پیش تعریف شده محدود میکنه. جاواسکریپت هیچ enum نداره اما تایپاسکریپت از enum داخلی پشتیبانی میکنه.
enum Color { RED, GREEN, BLUE }
میتونیم از متد Object.getOwnPropertyNames
استفاده کنیم که آرایهای از تمام ویژگیهایی رو که مستقیماً تو آبجکت داده شده یافت میشه رو برمیگردونه. بیاین استفاده از اونو تو یه مثال ببینیم:
const newObject = { a: 1, b: 2, c: 3 }; console.log(Object.getOwnPropertyNames(newObject)); ["a", "b", "c"]
میتونیم از متد Object.getOwnPropertyDescriptors
استفاده کنیم که تمام توصیفگرهای ویژگی یه آبجکت معین رو برمیگردونه. بیاین استفاده از اونو توی یه مثال ببینیم:
const newObject = { a: 1, b: 2, c: 3 }; const descriptorsObject = Object.getOwnPropertyDescriptors(newObject); console.log(descriptorsObject.a.writable); //true console.log(descriptorsObject.a.configurable); //true console.log(descriptorsObject.a.enumerable); //true console.log(descriptorsObject.a.value); // 1
value: ارزش مرتبط با پراپرتی
writable:تعیین میکنه که آیا مقدار مرتبط با ویژگی قابل تغییر هس یا نه
configurable: اگه بتونیم نوع descriptor این ویژگی رو تغییر بدیم و اگه بتونیم ویژگی رو از آبجکت مربوطه حذف کنیم، مقدار true رو برمیگردونه.
enumerable: تعیین میکنه که ویژگی در موقع شمارش خصوصیات روی آبجکت مربوطه ظاهر میشه یا نه.
set: تابعی که به عنوان تنظیم کننده برای ویژگی عمل میکنه
get: تابعی که به عنوان یه گیرنده برای ملک عمل میکنه
کلمه کلیدی extends
در اعلانها/عبارات کلاس برای ایجاد کلاسی که فرزند کلاس دیگه ایه استفاده میشه. میشه از اون برای زیر کلاس بندی کلاسهای سفارشی و همچنین اشیاء داخلی استفاده کرد. بریم یه مثال در موردش ببینیم،
class ChildClass extends ParentClass { ... }
بیاین یه نمونه از زیر کلاس مربع از کلاس والد Polygon رو مثال بزنیم:
class Square extends Rectangle { constructor(length) { super(length, length); this.name = 'Square'; } get area() { return this.width * this.height; } set area(value) { this.area = value; } }
برای تغییر url میشه ازwindow.location.url
استفاده کرد اما این کار باعث بارگیری دوباره صفحه میشه. HTML5 متدهای history.pushState
و history.replaceState
رو معرفی کرد که به شما اجازه میده به ترتیب ورودیهای تاریخ رو اضافه و تغییر بدین. برای مثال، میتونیم از pushState مثل کد زیر استفاده کنیم.
window.history.pushState('page2', 'Title', '/page2.html');
متد Array.includes
برای تعیین اینکه آیا یه آرایه مقدار خاصی رو بین ورودیهای خودش داره یا نه با برگردوندن true یا false استفاده میشه. بیاین مثالی برای پیداکردن یه عنصر (عددی و رشتهای) تو یه آرایه ببینیم:
const numericArray = [1, 2, 3, 4]; console.log(numericArray.includes(3)); // true const stringArray = ['green', 'yellow', 'blue']; console.log(stringArray.includes('blue')); //true
میتونیم از length و هر روش آرایه برای مقایسه دو آرایه اسکالر (مقایسه مستقیم با استفاده از ===) استفاده کنیم. ترکیب این دو تا روش میتونه نتیجه مورد نیازمون رو به ما بده:
const arrayFirst = [1,2,3,4,5]; const arraySecond = [1,2,3,4,5]; console.log(arrayFirst.length === arraySecond.length && arrayFirst.every((value, index) => value === arraySecond[index])); // true
اگه بخوایم آرایهها رو بدون توجه به ترتیب مقایسه کنیم باید اونا رو قبل از مقایسه، مرتب کنیم.
const arrayFirst = [2,3,1,4,5]; const arraySecond = [1,2,3,4,5]; console.log(arrayFirst.length === arraySecond.length && arrayFirst.sort().every((value, index) => value === arraySecond[index])); //true
کلاس URL
رشته url رو میپذیرد و از ویژگی searchParams
این آبجکت میتونیم برای دسترسی به پارامترهای get استفاده کنیم. ممکنه برای دسترسی به URL در مرورگرهای قدیمی (از جمله IE) نیاز به استفاده از polyfill یا window.location
داشته باشیم.
let urlString = "http://www.some-domain.com/about.html?x=1&y=2&z=3"; //window.location.href let url = new URL(urlString); let parameterZ = url.searchParams.get("z"); console.log(parameterZ); // 3
میتونیم از متد Number.prototype.toLocaleString
استفاده کنیم که رشتهای رو با نمایشی حساس به زبان مثل جداکننده هزار، ارز و غیره از این عدد برمیگردونه.
function convertToThousandFormat(x){ return x.toLocaleString(); // 12,345.679 } console.log(convertToThousandFormat(12345.6789));
هر دو زبان برنامه نویسی کاملاً نامرتبط هستن و هیچ ارتباطی بین اونا وجود نداره. جاوا بصورت ایستا تایپ میشه، کامپایل میشه، روی ماشین مجازی خودش اجرا میشه. در حالی که جاواسکریپت به صورت پویا تایپ میشه، تفسیر میشه و در محیطهای مرورگر و nodejs اجرا میشه. بیاین تفاوتهای عمده رو در قالب جدولی ببینیم:
ویژگی | جاوا | جاواسکریپت |
---|---|---|
تایپ شده | این یه زبان قوی تایپ شده اس | این یه زبان تایپ شده پویاس |
پارادایم | برنامه نویسی شی گرا | برنامه نویسی مبتنی بر prototype |
محدوده | محدوده بلوک | محدوده عملکردی |
همزمانی | بر اساس موضوع | مبتنی بر رویداد |
حافظه | از حافظه بیشتر استفاده میکنه | از حافظه کمتری استفاده میکنه. از این رو برای صفحات وب استفاده خواهد شد |
جاواسکریپت به طور پیش فرض از namespace پشتیبانی نمیکنه. بنابراین اگه هر عنصری (تابع، متد، آبجکت، متغیر) ایجاد کنیم گلوبال میشه و namespace گلوبال رو آلوده میکنه. بیاین مثالی از تعریف دو تابع بدون 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
همیشه تعریف تابع دوم رو فراخوانی میکنه. در این صورت namespace مشکل برخورد نام رو حل میکنه.
حتی اگه جاواسکریپت فاقد namespace باشه، میتونیم از Objects، IIFE برای ایجاد namespace استفاده کنیم.
استفاده از Object literal: بیاین متغیرها و توابع رو درون یه Object literal بپیچیم که به عنوان namespace عمل میکنه. پس از اون میتونیم با استفاده از نماد آبجکت به اونا دسترسی داشته باشیم
const namespaceOne = { function func1() { console.log("This is a first definition"); } } const namespaceTwo = { function func1() { console.log("This is a second definition"); } } namespaceOne.func1(); // This is a first definition namespaceTwo.func1(); // This is a second definition
استفاده از IIFE (توابع بیانی بلافاصله صدازده شده ): جفت پرانتز بیرونی IIFE یه محدوده محلی برای تمام کدهای داخلش ایجاد میکنه و تابع ناشناس رو به یه عبارت تابع تبدیل میکنه. به همین دلیل، میتونیم یه تابع رو در تو دو عبارت تابع مختلف ایجاد کنیم تا به عنوان namespace عمل کنه.
(function() { function fun1(){ console.log("This is a first definition"); } fun1(); }()); (function() { function fun1(){ console.log("This is a second definition"); } fun1(); }());
استفاده کردن از بلوک و تعریفکننده let و const: در ES6، میتونیم از یه بلوک و یه اعلان let برای محدود کردن دامنه یه متغیر به یه بلوک استفاده کنیم.
{ let myFunction= function fun1(){ console.log("This is a first definition"); } myFunction(); } //myFunction(): ReferenceError: myFunction is not defined. { let myFunction= function fun1(){ console.log("This is a second definition"); } myFunction(); } //myFunction(): ReferenceError: myFunction is not defined.
در ابتدا باید iFrame
با استفاده از document.getElementBy
یا window.frames
قابل دسترسی باشه. پس از اون ویژگی contentWindow iFrame
به targetFunction
دسترسی میده
document.getElementById('targetFrame').contentWindow.targetFunction(); window.frames[0].frameElement.contentWindow.targetFunction(); // Accessing iframe this way may not work in latest versions chrome and firefox
میتونیم از روش getTimezoneOffset
کلاس Date استفاده کنیم. این روش اختلاف منطقه زمانی رو بر حسب دقیقه از محلی فعلی (تنظیمات سیستم میزبان) به UTC برمیگردونه.
const offset = new Date().getTimezoneOffset(); console.log(offset); // -480
میتونیم هر دو عنصر پیوند و اسکریپت رو توی DOM ایجاد کنیم و اونا رو به عنوان child به تگ head اضافه کنیم. بیاین یه تابع برای اضافه کردن منابع اسکریپت و سبک مثل زیر ایجاد کنیم:
function loadAssets(filename, filetype) { if (filetype == "css") { // External CSS file const fileReference = document.createElement("link") fileReference.setAttribute("rel", "stylesheet"); fileReference.setAttribute("type", "text/css"); fileReference.setAttribute("href", filename); } else if (filetype == "js") { // External JavaScript file const fileReference = document.createElement('script'); fileReference.setAttribute("type", "text/javascript"); fileReference.setAttribute("src", filename); } if (typeof fileReference != "undefined") document.getElementsByTagName("head")[0].appendChild(fileReference) }
اگه بخوایم به هر عنصری در صفحه HTML دسترسی داشته باشیم، باید با دسترسی به آبجکت document شروع کنیم. بعداً میتونیم از یکی از روشهای زیر برای پیداکردن عنصر HTML استفاده کنیم.
document.getElementById(id): یه عنصر رو با Id پیدا میکنه
document.getElementsByTagName(name): یه عنصر رو با اسم تگ پیدا میکنه
document.getElementsByClassName(name):یک عنصر رو با اسم کلاس پیدا میکنه
jQuery یه کتابخونه جاواسکریپت متقابل مرورگر محبوبه که با به حداقل رسوندن اختلاف بین مرورگرها، پیمایش مدل آبجکت document (DOM)، مدیریت رویداد، انیمیشنها و تعاملات AJAX رو فراهم میکنه. با فلسفه اش «کمتر بنویس، بیشتر انجام بده» شهرت زیادی داره. برای مثال، میتونیم پیام خوش آمدگویی رو موقع بارگذاری صفحه با استفاده از jQuery به صورت زیر نمایش بدین.
$(document).ready(function(){ // It selects the document and apply the function on page load alert('Welcome to jQuery world'); });
**نکته:**میتونیم اونو از سایت رسمی jquery دانلود کنیم یا از CDNها مثل گوگل نصب کنیم.
V8 یه موتور جاواسکریپت با کارایی بالا منبع بازه که توسط مرورگر Google Chrome استفاده میشه و به زبان C++ نوشته شده است. توی پروژه node.js استفاده میشه. ECMAScript و WebAssembly رو پیادهسازی میکنه و روی ویندوز 7 یا بالاتر، macOS 10.12+ و سیستمهای لینوکس که از پردازندههای x64، IA-32، ARM یا MIPS استفاده میکنن اجرا میشه.
نکته: میتونه به صورت مستقل اجرا شه یا میتونه در هر برنامه C++ تعبیه شه.
جاواسکریپت یه زبان ساده تایپ شده یا یه زبان پویاعه چون متغیرها در جاواسکریپت مستقیماً با هیچ نوع مقدار خاصی مرتبط نیستن و هر متغیری رو میشه با مقادیری از همه نوع تخصیص/تخصیص مجدد داد.
let age = 50; // age is a number now age = 'old'; // age is a string now age = true; // age is a boolean
عملگر void
عبارت داده شده رو ارزیابی میکنه و بعد تعریف نشده (یعنی بدون برگشتن مقدار) رو برمیگردونه. بریم یه مثال در موردش ببینیم:
void (expression) void expression
بیاین پیامی رو بدون هیچ گونه تغییر مسیر یا بارگیری مجدد نمایش بدیم
<a href="javascript:void(alert('Welcome to JS world'))">Click here to see a message</a>
نکته: این عملگر بیشتر برای بدست آوردن مقدار اولیه تعریف نشده با استفاده از "void(0)" استفاده میشه.
مکان نما رو میشه برای انتظار در جاواسکریپت با استفاده از ویژگی cursor
تنظیم کرد. بیاین این رفتار رو در بارگذاری صفحه با استفاده از تابع زیر انجام بدیم:
function myFunction() { window.document.body.style.cursor = "wait"; }
و این تابع در بارگذاری صفحه فراخوانی میشه
<body onload="myFunction()">
میتونیم حلقههای بی نهایت با استفاده از حلقههای for و while بدون استفاده از هیچ عبارتی ایجاد کنیم. ساختار یا syntax حلقه for از نظر ESLint و ابزارهای بهینه ساز کد، رویکرد بهتری برای این کار هست.
for (;;) {} while(true) { }
دستور with جاواسکریپت در نظر گرفته شده بود که مختصری برای نوشتن دسترسیهای تکرارشونده به آبجکت ارائه بده. بنابراین میتونه با کاهش نیاز به تکرار یه مرجع طولانی بدون جریمه عملکرد، به کاهش اندازه فایل کمک کنه. بیاین مثالی بزنیم که تو اون برای جلوگیری از افزونگی موقع چندین بار دسترسی به یه آبجکت استفاده میشه.
a.b.c.greeting = 'welcome'; a.b.c.age = 32;
استفاده از "with" کد رو به این شکل تبدیل میکنه:
with(a.b.c) { greeting = "welcome"; age = 32; }
اما این عبارت with
مشکلات عملکردی ایجاد میکنه، چون نمیشه پیشبینی کرد که آیا یه آرگومان به یه متغیر واقعی اشاره میکنه یا به یه ویژگی توی آرگومان with.
for (var i = 0; i < 4; i++) { // global scope setTimeout(() => console.log(i)); } for (let i = 0; i < 4; i++) { // block scope setTimeout(() => console.log(i)); }
خروجی حلقههای بالا 4 4 4 4 و 0 1 2 3 است
توضیح: با توجه به صف رویداد/حلقه جاواسکریپت، تابع 'setTimeout' بعد از اجرای حلقه فراخونی میشه. از اونجایی که متغیر i با کلمه کلیدی var
تعریف میشه، به یه متغیر گلوبال تبدیل میشه و با استفاده از تکرار زمانی که تابع time setTimeout فراخوانی میشه، مقدارش برابر با 4. بنابراین، خروجی حلقه اول '4 4 4 4' میشه. حالا توی حلقه دوم، متغیر i بهعنوان کلمه کلیدی let
تعریف میشه، به متغیری با محدوده بلوک تبدیل میشه و یه مقدار جدید (0, 1,2 3) برای هر تکرار داره. بنابراین، خروجی حلقه دوم «0 1 2 3» میشه.
پشتیبانی از ثابتها یا متغیرهای تغییرناپذیر
پشتیبانی Block-scope برای متغیرها، ثابتها و توابع
Arrow functions
پارامترهای پیش فرض
پارامترهای Rest and Spread
Template Literals
Multi-line Strings
Destructuring Assignment
Enhanced Object Literals
Promises
Classes
Modules
ES6 ششمین نسخه از زبان جاواسکریپتـه و در ژوئن 2015 منتشر شد. در ابتدا با نام ECMAScript 6 (ES6) شناخته شد و بعداً به ECMAScript 2015 تغییر نام داد. تقریباً همه مرورگرهای مدرن از ES6 پشتیبانی میکنن اما برای مرورگرهای قدیمی ترانسپایلرهای زیادی وجود داره.، مثل Babel.js و غیره
نه، ما نمیتونیم متغیرهای let و const رو مجدداً تعریف کنیم. اگه این کار رو انجام بدیم، یه خطای syntax دریافت میکنیم:
Uncaught SyntaxError: Identifier 'someVariable' has already been declared
توضیح: اعلان متغیر با کلمه کلیدی "var" به یه محدوده تابع اشاره داره و با متغیر به دلیل ویژگی hoisting به گونه ای رفتار میشه که مثلا در بالای محدوده محصور تعریف شده. پس همه اعلانهای چندگانه بدون هیچ خطایی تو ایجاد یه متغیر hoisted مشترک نقش دارن. بیاین مثالی از اعلان مجدد متغیرها تو یه محدوده برای متغیرهای var و let/const بزنیم.
var name = 'John'; function myFunc() { var name = 'Nick'; var name = 'Abraham'; // Re-assigned in the same function block alert(name); // Abraham } myFunc(); alert(name); // John
اعلان چندگانه با محدوده بلوک، خطای syntax ایجاد میکنه،
let name = 'John'; function myFunc() { let name = 'Nick'; let name = 'Abraham'; // Uncaught SyntaxError: Identifier 'name' has already been declared alert(name); } myFunc(); alert(name);
نه، متغیر const مقدار رو تغییرناپذیر نمیکنه. اما تخصیصهای بعدی رو مجاز نمیدونه (یعنی میتونیم با ایجاد متغیر اعلام کنیم اما بعداً نمیتونیم مقدار دیگه ای رو یا نوع اون متغیر رو عوض کنیم)
const userList = []; userList.push('John'); // Can mutate even though it can't re-assign console.log(userList); // ['John'] uerList = 123; //throws an error
در E5، برای مدیریت مقادیر پیشفرض پارامترهای تابع، باید به عملگرهای OR منطقی وابسته باشیم.ولی در ES6، ویژگی پارامترهای تابع پیشفرض اجازه میده تا پارامترها با مقادیر پیشفرض مقداردهی اولیه بشن، اگه مقداری یا تعریفنشده ارسال نشه. بیاین رفتار رو با یه مثال مقایسه کنیم:
//ES5 var calculateArea = function(height, width) { height = height || 50; width = width || 60; return width * height; } console.log(calculateArea()); //300
پارامترهای پیش فرض، مقداردهی اولیه رو ساده تر میکنه،
//ES6 var calculateArea = function(height = 50, width = 60) { return width * height; } console.log(calculateArea()); //300
حروف الفبای الگو یا رشتههای الگو، حروف الفبای رشتهای هستن که امکان عبارات تعبیهشده رو میدن. اینا به جای گیومههای دوتایی یا تکی با کاراکتر بک تیک (`) محصور میشن در E6، این ویژگی استفاده از عبارات پویا رو به شرح زیر امکان پذیر میکنه.
const greeting = `Welcome to JS World, Mr. ${firstName} ${lastName}.`
توی ES5 لازمه که ما کدمون رو این شکلی بنویسیم.
var greeting = 'Welcome to JS World, Mr. ' + firstName + ' ' + lastName.`
نکته: میتونیم از رشتههای چند خطی و ویژگیهای درونیابی رشتهای با الفبای الگو استفاده کنیم.
در ES5، برای بدست آوردن رشتههای چند خطی، باید از کاراکترهای فرار از خط جدید ('\n') و نمادهای الحاقی (+) استفاده کنیم.
console.log('This is string sentence 1\n' + 'This is string sentence 2');
در حالی که در ES6، نیازی به ذکر کاراکتر دنباله خط جدید نیست،
console.log(`This is string sentence 'This is string sentence 2`);
الگوی تودرتو یه ویژگیه که در نحو تحت اللفظی الگو پشتیبانی میشه تا امکان بکتیکهای درونی تو یه مکاننمای ${ } رو در قالب فراهم کنه. برای مثال، الگوی تودرتو زیر برای نمایش نمادها بر اساس مجوزهای کاربر استفاده میشه، در حالی که الگوی بیرونی نوع پلت فرم رو بررسی میکنه.
const iconStyles = `icon ${ isMobilePlatform() ? '' : `icon-${user.isAuthorized ? 'submit' : 'disabled'}` }`;
میتونیم مورد استفاده بالا رو بدون ویژگیهای الگوی تودرتو هم بنویسین. با این حال، ویژگی الگوی تودرتو فشردهتر و خواناتر است.
//Without nesting templates const iconStyles = `icon ${ isMobilePlatform() ? '' : (user.isAuthorized ? 'icon-submit' : 'icon-disabled'}`;
الگوهای برچسبگذاری شده شکل پیشرفتهای از قالبها هستن که تو اون برچسبها بهمون اجازه میدن تا کلمات قالب رو با یه تابع تجزیه کنیم. تابع تگ اولین پارامتر رو به عنوان آرایه ای از رشتهها و پارامترهای باقی مانده رو به عنوان strings میگیره. این تابع همچنین میتونه رشتههای دستکاری شده رو بر اساس پارامترها برگردونه.
بیاین نحوه استفاده از رفتار الگوی برچسب گذاری شده مجموعه مهارتهای حرفه ای فناوری اطلاعات تو یه سازمان رو ببینیم.
var user1 = 'John'; var skill1 = 'JavaScript'; var experience1 = 15; var user2 = 'Kane'; var skill2 = 'JavaScript'; var experience2 = 5; function myInfoTag(strings, userExp, experienceExp, skillExp) { var str0 = strings[0]; // "Mr/Ms. " var str1 = strings[1]; // " is a/an " var str2 = strings[2]; // "in" var expertiseStr; if (experienceExp > 10){ expertiseStr = 'expert developer'; } else if(skillExp > 5 && skillExp <= 10) { expertiseStr = 'senior developer'; } else { expertiseStr = 'junior developer'; } return ${str0}${userExp}${str1}${expertiseStr}${str2}${skillExp}; } var output1 = myInfoTag`Mr/Ms. ${ user1 } is a/an ${ experience1 } in ${skill1}`; var output2 = myInfoTag`Mr/Ms. ${ user2 } is a/an ${ experience2 } in ${skill2}`; console.log(output1);// Mr/Ms. John is a/an expert developer in JavaScript console.log(output2);// Mr/Ms. Kane is a/an junior developer in JavaScript
ES6 با استفاده از روش «String.raw» ویژگی رشتههای خام رو ارائه میکنه که برای دریافت شکل رشته خام رشتههای الگو استفاده میشه. این ویژگی به ما این امکان رو میده تا به رشتههای خام همونطور که وارد شدهاند، بدون پردازش دنبالههای فرار دسترسی داشته باشیم. بریم یه مثال در موردش ببینیم،
var calculationString = String.raw `The sum of numbers is \n${1+2+3+4}!`; console.log(calculationString); // The sum of numbers is 10
اگه از رشتههای خام استفاده نمیکنیم دنباله کاراکترهای خط جدید با نمایش خروجی در چندین خط پردازش میشه.
var calculationString = `The sum of numbers is \n${1+2+3+4}!`; console.log(calculationString); // The sum of numbers is // 10
همچنین، ویژگی خام در اولین آرگومان تابع تگ موجود است
function tag(strings) { console.log(strings.raw[0]); }
تخصیص destructuring
یه عبارت جاواسکریپتـه که امکان باز کردن مقادیر آرایهها یا خصوصیات از اشیاء به متغیرهای مجزا رو فراهم میکنه.
بیاین مقادیر ماه رو از یه آرایه با استفاده از تخصیص ساختارشکن به دست آوریم
var [one, two, three] = ['JAN', 'FEB', 'MARCH']; console.log(one); // "JAN" console.log(two); // "FEB" console.log(three); // "MARCH"
و میتونیم ویژگیهای کاربر یه آبجکت رو با استفاده از انتساب destructuring به دست بیارین،
var {name, age} = {name: 'John', age: 32}; console.log(name); // John console.log(age); // 32
زمانی که مقدار باز شده از آرایه یا شیء در طول تخصیص ساختارشکن تعریف نشده باشه، میشه به یه متغیر یه مقدار پیش فرض اختصاص داد. این کمک میکنه تا از تنظیم مقادیر پیش فرض جداگانه برای هر انتساب جلوگیری کنیم. بیاین برای هر دو آرایه و موارد استفاده از شی مثالی بزنیم،
Arrays destructuring:
var x, y, z; [x=2, y=4, z=6] = [10]; console.log(x); // 10 console.log(y); // 4 console.log(z); // 6
Objects destructuring:
var {x=2, y=4, z=6} = {x: 10}; console.log(x); // 10 console.log(y); // 4 console.log(z); // 6
اگه از destructuring-assignment استفاده نمیکنیم تعویض دو مقدار به یه متغیر موقت نیاز داره. در حالی که با استفاده از یه ویژگی ساختارشکن، دو مقدار متغیر رو میشه تو یه عبارت ساختار شکن جایگزین کرد. بیاین دو متغیر عددی رو در انتساب ساختارزدایی آرایه با هم عوض کنیم:
var x = 10, y = 20; [x, y] = [y, x]; console.log(x); // 20 console.log(y); // 10
Enhanced-object-literal ایجاد سریع اجسام با ویژگیهای درون براکت رو آسان میکنه. برای مثال، نحو کوتاهتری رو برای تعریف ویژگی شی مشترک به شرح زیر ارائه میکنه.
//ES6 var x = 10, y = 20 obj = { x, y } console.log(obj); // {x: 10, y:20} //ES5 var x = 10, y = 20 obj = { x : x, y : y} console.log(obj); // {x: 10, y:20}
واردات پویا با استفاده از نحو تابع «import» به ما اجازه میده تا ماژولها رو در صورت تقاضا با استفاده از دستورات یا دستور async/await بارگذاری کنیم. در حال حاضر این ویژگی در [پیشنهاد مرحله4] (https://github.com/tc39/proposal-dynamic-import) هستش. مزیت اصلی واردات پویا کاهش اندازه بستههای ما، پاسخ حجم/بار بار درخواستهای ما و بهبود کلی در تجربه کاربر است.
import('./Module').then(Module => Module.method());
در زیر بعضی از موارد استفاده از واردات پویا نسبت به واردات استاتیک آورده شده است.
یه ماژول رو به صورت درخواستی یا مشروط وارد کنیم. برای مثال، اگه میخواین یه polyfill رو در مرورگر قدیمی بارگذاری کنیم
if (isLegacyBrowser()) { import(···) .then(···); }
تعیین کننده ماژول رو در زمان اجرا محاسبه کنیم. برای مثال میتونیم از اون برای گلوبال سازی استفاده کنیم.
import(`messages_${getLocale()}.js`).then(···);
یه ماژول رو از داخل یه اسکریپت معمولی به جای یه ماژول وارد کنیم.
آرایههای تایپ شده آبجکتهایی آرایه مانند از ECMAScript 6 API برای مدیریت دادههای باینری هستن. جاواسکریپت 8 نوع آرایه تایپ شده رو ارائه میده،
Int8Array: آرایه ای از اعداد صحیح امضا شده 8 بیتی
Int16Array: آرایه ای از اعداد صحیح امضا شده 16 بیتی
Int32Array: آرایه ای از اعداد صحیح امضا شده 32 بیتی
Uint8Array: آرایه ای از اعداد صحیح بدون علامت 8 بیتی
Uint16Array: آرایه ای از اعداد صحیح بدون علامت 16 بیتی
Uint32Array: آرایه ای از اعداد صحیح بدون علامت 32 بیتی
Float32Array:آرایه ای از اعداد ممیز شناور 32 بیتی
Float64Array: آرایه ای از اعداد ممیز شناور 64 بیتی
برای مثال، میتونیم یه آرایه از اعداد صحیح امضا شده 8 بیتی مانند زیر ایجاد کنیم
const a = new Int8Array(); // You can pre-allocate n bytes const bytes = 1024 const a = new Int8Array(bytes)
ماژول لودر ویژگیهای زیر رو ارائه میده
Dynamic loading
State isolation
Global namespace isolation
Compilation hooks
Nested virtualization
Collation برای مرتب سازی مجموعه ی رشتهها و جستجو در مجموعه ای از رشتهها استفاده میشه. این پارامتر توسط محلی و از Unicode آگاهه. بیاین ویژگیهای مقایسه و مرتب سازی رو در نظر بگیریم،
Comparison:
const list = [ "ä", "a", "z" ]; // In German, "ä" sorts with "a" Whereas in Swedish, "ä" sorts after "z" const l10nDE = new Intl.Collator("de"); const l10nSV = new Intl.Collator("sv"); console.log(l10nDE.compare("ä", "z") === -1); // true console.log(l10nSV.compare("ä", "z") === +1); // true
Sorting:
const list = [ "ä", "a", "z" ]; // In German, "ä" sorts with "a" Whereas in Swedish, "ä" sorts after "z" const l10nDE = new Intl.Collator("de"); const l10nSV = new Intl.Collator("sv"); console.log(list.sort(l10nDE.compare)) // [ "a", "ä", "z" ] console.log(list.sort(l10nSV.compare)) // [ "a", "z", "ä" ]
دستور for...of یه حلقه تکرار بر روی اشیاء یا عناصر قابل تکرار مثل رشته داخلی، آرایه، اشیاء آرایه مانند (مثل آرگومانها یا NodeList)، TypedArray، Map، Set و تکرارهای تعریف شده توسط کاربر ایجاد میکنه.
let arrayIterable = [10, 20, 30, 40, 50]; for (let value of arrayIterable) { value ++; console.log(value); // 11 21 31 41 51 }
[...'John Resig']
خروجی آرایه ['J', 'o', 'h', 'n', ', 'R', 'e', 's', 'i', 'g'] است.
توضیح: رشته یه نوع تکرارپذیره و عملگر spread تو یه آرایه هر کاراکتر یه تکرارپذیر رو به یه عنصر نگاشت میکنه. از این رو، هر کاراکتر یه رشته به عنصری تو یه آرایه تبدیل میشه.
بله، تا زمانی که برنامهنویس/توسعهدهنده مراقب منشأ و منبع پیام دریافتی باشه، postMessages رو میشه بسیار امن در نظر گرفت. اما اگه بخواییم پیامی رو بدون تأیید منبع آن ارسال یا دریافت کنیم حملات اسکریپت بین سایتی ایجاد میشه.
آرگومان دوم متد postMessage مشخص میکنه که کدوم مبدا مجاز به دریافت پیامه. اگه از علامت "*" به عنوان آرگومان استفاده کنیم هر منبعی مجاز به دریافت پیامه. در این حالت، هیچ راهی برای پنجره فرستنده وجود نداره که بفهمه پنجره هدف در موقع ارسال پیام در مبدأ هدف قرار داره یا نه. اگه پنجره هدف به مبدأ دیگری هدایت شه، مبدا دیگر دادهها رو دریافت میکنه. از این رو، این ممکنه منجر به آسیب پذیریهای XSS شه.
targetWindow.postMessage(message, '*');
از اونجایی که شنونده به هر پیامی گوش میده، مهاجم میتونه برنامه رو با ارسال پیامی از مبدأ مهاجم فریب بده که این تصور رو ایجاد میکنه که گیرنده پیام رو از پنجره فرستنده واقعی دریافت کرده. میتونیم با اعتبارسنجی مبدا پیام در انتهای گیرنده با استفاده از ویژگی "message.origin" از این مشکل جلوگیری کنیم. برای مثال، اجازه بدین مبدا فرستنده http://www.some-sender.com در سمت گیرنده [www.some-receiver.com] (www.some) رو بررسی کنیم -receiver.com)،
//Listener on http://www.some-receiver.com/ window.addEventListener("message", function(message){ if(/^http://www\.some-sender\.com$/.test(message.origin)){ console.log('You received the data from valid sender', message.data); } });
نمیتونیم به طور کامل (یا 100٪) از postMessages استفاده نکنیم. حتی اگه برنامهمون با توجه به خطرات از postMessage استفاده نمیکنه، بسیاری از اسکریپتهای شخص ثالث از postMessage برای برقراری ارتباط با سرویس شخص ثالث استفاده میکنن. بنابراین ممکنه برنامه بدون اطلاع شما از postMessage استفاده کنه.
postMessages
در مرورگر IE8 synchronous
هستن اما در IE9 و سایر مرورگرهای مدرن دیگر (یعنی IE9+، Firefox، Chrome، Safari) asynchronous
هستن. به دلیل این رفتار asyncو زمانی که postMessage
برگردونده میشه، از مکانیزم callback
استفاده میکنیم.
جاواسکریپت یه زبان چند پارادایمه که از برنامه نویسی امری/روشی، برنامه نویسی شی گرا و برنامه نویسی تابعی پشتیبانی میکنه. جاواسکریپت از برنامه نویسی شی گرا با وراثت اولیه پشتیبانی میکنه.
جاواسکریپت داخلی: کد منبع درون تگ اسکریپته.
جاواسکریپت خارجی: کد منبع تو یه فایل خارجی (ذخیره شده با پسوند js.) ذخیره میشه و در تگ ارجاع میشه.
بله، جاواسکریپت سریعتر از اسکریپت سمت سروره. از اونجایی که جاواسکریپت یه اسکریپت سمت کلاینته برای محاسبات یا محاسبات خودش به کمک سرور وب نیازی نداره. بنابراین جاواسکریپت همیشه سریعتر از هر اسکریپت سمت سرور مانند ASP، PHP و غیره اس.
میتونیم ویژگیchecked
رو در کادر انتخاب شده در DOM اعمال کنیم. اگه مقدار "True" باشه به این معنیه که چک باکس علامت زده شده در غیر این صورت علامت اونو بردارین. برای مثال، عنصر چک باکس HTML زیر رو میشه با استفاده از جاواسکریپت به صورت زیر در دسترس قرار داد:
<input type="checkbox" name="checkboxname" value="Agree"> Agree the conditions<br>
console.log(document.getElementById(‘checkboxname’).checked); // true or false
عملگر دابل tilde(~~) به عنوان عملگر bitwise double NOT
شناخته میشه. این عملگر قراره جایگزین سریع تری برای Math.floor
.
برای تبدیل کاراکترهای رشته به اعداد اسکی میتونیم از متد String.prototype.charCodeAt
استفاده کنیم. برای مثال، بیاین کد ASCII رو برای حرف اول رشته «ABC» پیدا کنیم:
"ABC".charCodeAt(0) // returns 65
در حالی که روش String.fromCharCode
اعداد رو به کاراکترهای ASCII
برابر تبدیل میکنه.
String.fromCharCode(65,66,67); // returns 'ABC'
یه گلاس ArrayBuffer
برای نشون دادن یه بافر داده باینری خام عمومی با طول ثابت استفاده میشه. میتونیم اونو به صورت زیر ایجاد کنیم:
const buffer = new ArrayBuffer(16); // create a buffer of length 16 alert(buffer.byteLength); // 16
برای دستکاری یه ArrayBuffer،
باید از یه کلاس DataView
استفاده کنیم.
//Create a DataView referring to the buffer const view = new DataView(buffer);
console.log("Welcome to JS world"[0])
خروجی عبارت بالا "W" عه.
توضیح: نماد براکت با شاخص خاص روی یه رشته کاراکتر رو تو یه مکان خاص برمیگردونه. از این رو، کاراکتر "W" رشته رو برمیگردونه. از اونجایی که این مورد در نسخههای IE7 و پایینتر پشتیبانی نمیشه، ممکنه لازم باشه از متد charAt برای به دست آوردن نتیجه دلخواه استفاده کنیم.
کلاس Error یه آبجکت error ایجاد میکنه و نمونههایی از آبجکتهای خطا موقع رخ دادن خطاهای زمان اجرا ارسال میشن، آبجکت Error همچنین میتونه به عنوان یه آبجکت پایه برای استثناهای تعریف شده توسط کاربر استفاده شه. برای مثال
new Error([message[, fileName[, lineNumber]]])
میتونیم استثناها یا خطاهای تعریف شده توسط کاربر رو با استفاده از آبجکت Error در بلوک try...catch مثل کد زیر ارسال کنیم.
try { if(withdraw > balance) throw new Error("Oops! You don't have enough balance"); } catch (e) { console.log(e.name + ': ' + e.message); }
آبجکت EvalError
یه خطا راجع به استفاده از تابع eval
رو نشون میده. البته دیگه این استثنا توسط جاواسکریپت ایجاد نمیشه و آبجکت EvalError فقط برای سازگاری با نسخههای باقی مونده. برای مثال
new EvalError([message[, fileName[, lineNumber]]])
میتونیم EvalError رو با بلوک try...catch مثل کد زیر ارسال کنیم.
try { throw new EvalError('Eval function error', 'someFile.js', 100); } catch (e) { console.log(e.message, e.name, e.fileName); // "Eval function error", "EvalError", "someFile.js" }
وقتی use strict
رو اعمال میکنیم. syntax، بعضی از موارد زیر قبل از اجرای اسکریپت یه SyntaxError ایجاد میکنن
وقتی از دستور Octal
استفاده میکنیم
const n = 022;
استفاده از عبارت with
.
وقتی از عملگر حذف روی نام متغیر استفاده میکنیم
استفاده از eval یا آرگومانها به عنوان متغیر یا نام آرگومان تابع
موقعی که از کلمات کلیدی رزرو شده جدید استفاده میکنیم
موقعی که یه تابع رو تو یه بلوک اعلام میکنیم
if (someCondition) { function f() {} }
از این رو، خطاهای موارد بالا برای جلوگیری از خطا در محیطهای توسعه/تولید مفید هستن.
خیر. همه objectها دارای prototype هستن به جز object پایه که توسط کاربر ایجاد میشه یا آبجکتای که با استفاده از کلمه کلیدی new ایجاد میشه.
parameter
نام متغیر تعریف یه تابعه در حالی که یه argument
نشون دهنده مقدار داده شده به تابع موقع فراخونای شدنشه. بیاین این رو با یه تابع ساده توضیح بدیم
function myFunction(parameter1, parameter2, parameter3) { console.log(arguments[0]) // "argument1" console.log(arguments[1]) // "argument2" console.log(arguments[2]) // "argument3" } myFunction("argument1", "argument2", "argument3")
متد some
برای تست این که حداقل یه عنصر در آرایه، از تست پیادهسازی شده توسط تابع ارائه شده، عبور میکنه یا نه استفاده میشه. متد یه مقدار بولین برمیگردونه. بیاین مثالی بزنیم تا هر عنصر رو بر اساس داشتن عدد زوج آزمایش کنیم:
const array = [1, 2, 3, 4, 5, 6 ,7, 8, 9, 10]; const odd = element => element % 2 !== 0; console.log(array.some(odd)); // true (the odd element exists)
متد concat
برای ترکیب دو یا چند آرایه با برگردوندن یه آرایه جدید حاوی تمام عناصر استفاده میشه.مثال:
array1.concat(array2, array3, ..., arrayX)
بیاین مثالی از الحاق آرایه با آرایههای veggies و fruits رو مثال بزنیم.
const veggies = ["Tomato", "Carrot", "Cabbage"]; const fruits = ["Apple", "Orange", "Pears"]; const veggiesAndFruits = veggies.concat(fruits); console.log(veggiesAndFruits); // Tomato, Carrot, Cabbage, Apple, Orange, Pears
کپی کم عمق:
کپی کم عمق یه کپی بیتی از یه آبجکته. یه آبجکت جدید ایجاد میشه که یه کپی دقیق از مقادیر موجود در آبجکت اصلی رو داره. اگه هر یه از فیلدهای آبجکت ارجاع به آبجکتهای دیگه باشه، فقط آدرسهای مرجع کپی میشن یعنی فقط آدرس توی حافظه کپی میشه.
مثال
const empDetails = { name: "John", age: 25, expertise: "Software Developer" }
برای ایجاد یه نسخه تکراری
const empDetailsShallowCopy = empDetails //Shallow copying!
اگه مقداری از ویژگی رو تو یه تکراری به این صورت تغییر بدیم:
empDetailsShallowCopy.name = "Johnson"
دستور بالا همچنین نام empDetails
رو تغییر میده، چون ما یه کپی کم عمق داریم. یعنی ما دادههای اصلی رو هم از دست می دیم.
کپی عمیق(Deep):
یه کپی عمیق همه فیلدها رو کپی میکنه و از حافظه تخصیص یافته به صورت پویا که توسط فیلدها به آن اشاره میشه کپی میکنه. یه کپی عمیق زمانی اتفاق میوفته که یه آبجکت همراه با پراپرتیهایی که به اون اشاره داره کپی شه.
Example
const empDetails = { name: "John", age: 25, expertise: "Software Developer" }
یه کپی عمیق با استفاده از خواص از آبجکت اصلی در متغیر جدید ایجاد کنیم:
const empDetailsDeepCopy = { name: empDetails.name, age: empDetails.age, expertise: empDetails.expertise }
اگه empDetailsDeepCopy.name
رو تغییر بدین، فقط empDetailsDeepCopy
و نه empDetails
رو تحت تأثیر قرار میده.
متدrepeat
برای ساخت و برگردوندن یه رشته جدید استفاده میشه که حاوی تعداد مشخصی از کپیهای رشتهای هس که روی اون فراخوانی شده و به هم پیوسته شدن. یادتون باشه که این روش به مشخصات ECMAScript 2015 اضافه شده است.
بیاین یه مثال از رشته Hello رو برای تکرارش 4 بار در نظر بگیریم:
'Hello'.repeat(4); // 'HelloHelloHelloHello'
متد matchAll
میتواند برای برگردوندن یه تکرارکننده از تمام نتایجی که یه رشته با یه عبارت منظم مطابقت دارن، استفاده شه. مثال زیر آرایه ای از نتایج رشته منطبق رو در برابر یه عبارت منظم برمیگردونه:
let regexp = /Hello(\d?))/g; let greeting = 'Hello1Hello2Hello3'; let greetingList = [...greeting.matchAll(regexp)]; console.log(greetingList[0]); //Hello1 console.log(greetingList[1]); //Hello2 console.log(greetingList[2]); //Hello3
روش trim prototype
رشته برای برش دادن دو طرف یه رشته استفاده میشه. اما اگه بخوایم بهخصوص در ابتدا یا انتهای رشته رو برش بدیم، میتونیم از روشهای trimStart/trimLeft
و trimEnd/trimRight
استفاده کنیم. بیاین نمونه ای از این روشها رو در پیام greeting ببینیم:
const greeting = ' Hello, Goodmorning! '; console.log(greeting); // " Hello, Goodmorning! " console.log(greeting.trimStart()); // "Hello, Goodmorning! " console.log(greeting.trimLeft()); // "Hello, Goodmorning! " console.log(greeting.trimEnd()); // " Hello, Goodmorning!" console.log(greeting.trimRight()); // " Hello, Goodmorning!"
console.log(+'Hello');
خروجی دستور log کنسول بالا NaN رو برمیگردونه. از اونجا که عنصر توسط عملگر unary پیشونده و مفسر جاواسکریپت سعی میکنه اون عنصر رو به یه نوع عدد تبدیل کنه. از اونجایی که تبدیل با شکست مواجه میشه، مقدار عبارت به مقدار NaN منجر میشه.
Mixin
- یک اصطلاح برنامه نویسی شی گرا عمومیه: کلاسی که شامل متدهایی برای کلاسهای دیگه اس. برخی از زبانهای دیگر به ارث بردن چندگانه اجازه میدن. جاوا اسکریپت از وراثت چندگانه پشتیبانی نمیکنه، اما Mixin
ها رو میشه با کپی کردن متدها در نمونه اولیه پیاده سازی کرد.
thunk
فقط تابعیه که ارزیابی مقدار رو به تاخیر میندازه. هیچ آرگومانی نمیگیره، اما هر زمان که thunk
رو فراخوانی میکنیم مقدار رو میده. برای مثال، از اون استفاده میشه که الان اجرا نشه، اما زمانی در آینده اجرا میشه. بیاین یه مثال sync بگیریم:
const add = (x,y) => x + y; const thunk = () => add(2,3); thunk() // 5
Thunk
های asynchronous
برای ایجاد درخواستهای شبکه مفید هستن. بیاین نمونه ای از درخواستهای شبکه رو ببینیم:
function fetchData(fn){ fetch('https://jsonplaceholder.typicode.com/todos/1') .then(response => response.json()) .then(json => fn(json)) } const asyncThunk = function (){ return fetchData(function getData(data){ console.log(data) }) } asyncThunk()
تابع getData
فوراً فراخونی نمیشه و تنها زمانی فراخونی میشه که دادهها از نقطه پایانی API در دسترس باشن. تابع setTimeout هم برای ناهمزمان کردن کد ما استفاده میشه. بهترین مثال زمان واقعی، کتابخونه مدیریت حالت redux هس که از thunkهای ناهمزمان برای به تاخیر انداختن اعمال برای ارسال استفاده میکنه.
قسمت کد:
const circle = { radius: 20, diameter() { return this.radius * 2; }, perimeter: () => 2 * Math.PI * this.radius }; console.log(circle.diameter()); console.log(circle.perimeter());
خروجی:
خروجی 40 و NaN هس. یادتون باشه که diameter یه تابع منظمه در حالی که مقدار perimeter یه arrow function
هستش. کلمه کلیدی this
یه تابع معمولی (یعنی diameter) به محدوده اطراف که یه کلاسه (یعنی آبجکت circle) اشاره داره. در حالی که این کلمه کلیدی تابع perimeter به محدوده اطراف که یه آبجکت window هس اشاره داره. از اونجایی که هیچ ویژگی radius در آبجکتهای window وجود نداره، یه مقدار undefined برمیگردونه و ضرب مقدار، مقدار NaN رو برمیگردونه.
ساده ترین روش ٍ استفاده از regex برای شناسایی و جایگزینی خطوط جدید توی رشته اس. در این حالت از تابع replace به همراه رشته برای جایگزینی استفاده میکنیم که در این مثال یه رشته خالیه:
function remove_linebreaks( var message ) { return message.replace( /[\r\n]+/gm, "" ); }
تو عبارت بالا g و m برای flagهای سراسری و چند خطی هستن.
repaintزمانی اتفاق میافته که تغییراتی ایجاد میشه که روی دید یه عنصر تأثیر میذاره، اما روی طرح اون تأثیر نمیذاره،. نمونههایی از این موارد شامل طرح کلی، نمایان بودن یا رنگ پس زمینه اس. یه reflow شامل تغییراتیه که بر طرح بندی بخشی از صفحه (یا کل صفحه) تأثیر میزاره. تغییر اندازه پنجره مرورگر، تغییر فونت، تغییر محتوا (مانند تایپ متن توسط کاربر)، استفاده از روشهای جاواسکریپت شامل سبکهای محاسبهشده، اضافه کردن یا حذف عناصر از DOM، و تغییر کلاسهای یه عنصر چند مورد از مواردی هستن که میتونن جریان مجدد رو آغاز کنن. جریان مجدد یه عنصر باعث جریان مجدد بعدی همه عناصر فرزند و اجداد و همچنین هر عنصری که به دنبال اون توی DOM هس میشه.
نفی یه آرایه با کاراکتر «!»، آرایه رو به یه بولین تبدیل میکنه. از اونجایی که آرایهها true در نظر گرفته میشن، پس نفی اون false رو برمیگردونه.
console.log(![]); // false
اگه دو آرایه رو با هم اضافه کنیم هر دو اونا رو به رشته تبدیل میکنه و اونا رو به هم متصل میکنه. برای بریم یه مثال در موردش ببینیم:
console.log(['a'] + ['b']); // "ab" console.log([] + []); // "" console.log(![] + []); // "false", because ![] returns false.
اگه عملگر additive(+) رو روی مقادیر نادرست (null، undefined، NaN، false، "") قرار بدیم، مقدار falsy به مقدار عددی صفر تبدیل میشه. بیاین اونا رو توی کنسول مرورگر به صورت زیر نمایش بدیم:
console.log(+null); // 0 console.log(+undefined);// NaN console.log(+false); // 0 console.log(+NaN); // NaN console.log(+""); // 0
رشته self رو میشه با ترکیب کاراکترهای []()!+
تشکیل داد. برای رسیدن به این الگو باید موارد زیر رو بدونیم:
از اونجایی که آرایهها مقادیر true هستن، با نفی آرایهها false تولید میشه: ![] === false
طبق قوانین اجباری جاواسکریپت، اضافه کردن آرایهها به هم اونا رو به رشتهبندی تبدیل میکنه: [] + [] === ""
Prepend یه آرایه با عملگر + یه آرایه رو به نادرست تبدیل میکنه، انکار اونو درست میکنه و در نهایت تبدیل نتیجه مقدار '1' رو تولید میکنه: +(!(+[])) === 1
با اعمال قوانین بالا میتونیم شرایط زیر رو استخراج کنیم:
![] + [] === "false" +!+[] === 1
اکنون الگوی کاراکتر به صورت زیر ایجاد میشه:
s e l f ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ (![] + [])[3] + (![] + [])[4] + (![] + [])[2] + (![] + [])[0] ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ (![] + [])[+!+[]+!+[]+!+[]] + (![] + [])[+!+[]+!+[]+!+[]+!+[]] + (![] + [])[+!+[]+!+[]] + (![] + [])[+[]] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (![]+[])[+!+[]+!+[]+!+[]]+(![]+[])[+!+[]+!+[]+!+[]+!+[]]+(![]+[])[+!+[]+!+[]]+(![]+[])[+[]]
میتونیم با وارد کردن Boolean به عنوان پارامتر، روش فیلتر رو روی آرایه اعمال کنیم. به این ترتیب تمام مقادیر falsy (0، undifined، null، false و "") از آرایه حذف میشه.
const myArray = [false, null, 1,5, undefined] myArray.filter(Boolean); // [1, 5] // is same as myArray.filter(x => x);
میتونیم مقادیر یونیک یه آرایه رو با ترکیب دستور "Set" و rest expression/spread(...) دریافت کنیم.
console.log([...new Set([1, 2, 4, 4, 3])]); // [1, 2, 4, 3]
گاهی اوقات لازم داریم یه متغیر destructure
شده با نامی متفاوت از نام ویژگی داشته باشیم. در این صورت، از یه : newName
برای تعیین اسم برای متغیر استفاده میکنیم. این فرآیند destructuring aliase
نامیده میشه.
const obj = { x: 1 }; // Grabs obj.x as as { otherName } const { x: otherName } = obj;
میتونیم مقادیر آرایهها رو بدون استفاده از متد map
تنها با استفاده از روش from
آرایه ترسیم کنیم. بیاین نام شهرها رو از آرایه کشورها ترسیم کنیم:
const countries = [ { name: 'India', capital: 'Delhi' }, { name: 'US', capital: 'Washington' }, { name: 'Russia', capital: 'Moscow' }, { name: 'Singapore', capital: 'Singapore' }, { name: 'China', capital: 'Beijing' }, { name: 'France', capital: 'Paris' }, ]; const cityNames = Array.from(countries, ({ capital}) => capital); console.log(cityNames); // ['Delhi, 'Washington', 'Moscow', 'Singapore', 'Beijing', 'Paris']
با صفر کردن length آرایه میتونیم به سرعت یه آرایه رو خالی کنیم:
let cities = ['Singapore', 'Delhi', 'London']; cities.length = 0; // cities becomes []
میتونیم با استفاده از روش toFixed
از جاواسکریپت، اعداد رو به تعداد معینی از اعشار گرد کنیم.
let pie = 3.141592653; pie = pie.toFixed(3); // 3.142
میتونیم با استفاده از عملگر spread(...) یه آرایه رو به یه آبجکت با همون داده تبدیل کنیم.
var fruits = ["banana", "apple", "orange", "watermelon"]; var fruitsObject = {...fruits}; console.log(fruitsObject); // {0: "banana", 1: "apple", 2: "orange", 3: "watermelon"}
میتونیم با استفاده از روش fill
یه آرایه با مقداری داده یا یه آرایه با همون مقادیر ایجاد کنیم.
var newArray = new Array(5).fill("0"); console.log(newArray); // ["0", "0", "0", "0", "0"]
%o - یه آبجکت رو میگیرد،
%s - یه رشته میگیره،
const user = { "name":"John", "id": 1, "city": "Delhi"}; console.log("Hello %s, your details %o are available in the object form", "John", user); // Hello John, your details {name: "John", id: 1, city: "Delhi"} are available in object
بله، میتونیم سبکهای CSS رو برای پیامهای کنسول مشابه متن html در صفحه وب اعمال کنیم.
console.log('%c The text has blue color, with large font and red background', 'color: blue; font-size: x-large; background: red');
متن به صورت زیر نمایش داده میشه
نکته: تمام سبکهای CSS رو میشه برای پیامهای کنسول اعمال کرد.
console.dir
برای نمایش یه لیست تعاملی از ویژگیهای آبجکت جاواسکریپت مشخص شده به عنوان JSON استفاده میشه.
const user = { "name":"John", "id": 1, "city": "Delhi"}; console.dir(user);
آبجکت user نمایش داده شده توی حالت JSON
بله، دریافت و اشکال زدایی عناصر HTML توی کنسول، درست مثل بررسی عناصر، امکان پذیره.
const element = document.getElementsByTagName("body")[0]; console.log(element);
این عنصر HTML رو توی کنسول چاپ میکنه،
console.table
برای نمایش دادهها توی کنسول توی یه قالب جدولی برای تجسم آرایهها یا آبجکتهای پیچیده استفاده میشه.
const users = [{ "name":"John", "id": 1, "city": "Delhi"}, { "name":"Max", "id": 2, "city": "London"}, { "name":"Rod", "id": 3, "city": "Paris"} ]; console.table(users);
دادههایی که در قالب جدول مشاهده میشن،
نکته: یادتون باشه console.table
توی مرورگر IE پشتیبانی نمیشه 😕
ترکیبی از روشهای IsNaN و isFinite برای تأیید عدد بودن یا نبودن آرگومان استفاده میشه.
function isNumber(n){ return !isNaN(parseFloat(n)) && isFinite(n); }
ما باید محتوا (با استفاده از روش .select) عنصر ورودی رو انتخاب کنیم و دستور copy رو با execCommand اجرا کنیم (یعنی execCommand('copy')). همچنین میتونیم سایر دستورات سیستم مثل cut و paste رو اجرا کنیم.
document.querySelector("#copy-button").onclick = function() { // Select the content document.querySelector("#copy-input").select(); // Copy to the clipboard document.execCommand('copy'); };
میتونیم از Date.getTime
برای دریافت مهر زمانی فعلی استفاده کنیم. یه میانبر جایگزین برای دریافت مقدار وجود داره.
console.log(+new Date()); console.log(Date.now());
مسطح کردن آرایههای دو بعدی با عملگر Spread کاربرد نداره.
const biDimensionalArr = [11, [22, 33], [44, 55], [66, 77], 88, 99]; const flattenArr = [].concat(...biDimensionalArr); // [11, 22, 33, 44, 55, 66, 77, 88, 99]
اما ما میتونیم اونو با آرایههای چند بعدی با فراخوانیهای recursive
کال کنیم:
function flattenMultiArray(arr) { const flattened = [].concat(...arr); return flattened.some(item => Array.isArray(item)) ? flattenMultiArray(flattened) : flattened; } const multiDimensionalArr = [11, [22, 33], [44, [55, 66, [77, [88]], 99]]]; const flatArr = flattenMultiArray(multiDimensionalArr); // [11, 22, 33, 44, 55, 66, 77, 88, 99]
میتونیم از تابع indexOf
» برای مقایسه ورودی با چندین مقدار به جای بررسی هر مقدار به عنوان یه شرط استفاده کنیم.
// Verbose approach if (input === 'first' || input === 1 || input === 'second' || input === 2) { someFunction(); } // Shortcut if (['first', 1, 'second', 2].indexOf(input) !== -1) { someFunction(); }
روش window.onbeforeunload
برای ضبط رویدادهای دکمه بازگشت مرورگر استفاده میشه. این برای هشدار دادن به کاربرها در مورد از دست دادن دادههای فعلی میتونه استفاده. syntax تعریف کردنش به صورت زیر هست:
window.onbeforeunload = function() { alert("You work will be lost"); };
کلیک راست روی صفحه رو میشه با برگردوندن false از ویژگی oncontextmenu
در تگ body غیرفعال کرد.
<body oncontextmenu="return false;">
مقادیر اولیه مانند رشته، عدد و بولین پراپرتی و متدی ندارن، اما زمانی که میخوایم کارهایی رو روی اونا انجام بدیم، به طور موقت به یه آبجکت (آبجکت Wrapper) تبدیل میشن. برای مثال، اگه متد UpperCase رو روی یه مقدار رشته اولیه اعمال کنیم خطایی ایجاد نمیکنه، اما حروف بزرگ رشته رو برمیگردونه.
let name = "john"; console.log(name.toUpperCase()); // Behind the scenes treated as console.log(new String(name).toUpperCase());
یعنی هر اولیه به جز null و undefined دارای Wrapper Object هس و لیست اشیاء wrapper عبارتند از String، Number، Boolean، Symbol و BigInt.
AJAX
مخفف Asynchronous JavaScript XML
هس و گروهی از فناوریهای مرتبط (HTML، CSS، JavaScript، XMLHttpRequest API و غیره) که برای نمایش دادهها به صورت ناهمزمان استفاده میشه. یعنی ما میتونیم دادهها رو به سرور ارسال کنیم و بدون بارگیری مجدد صفحه وب، دادهها رو از سرور دریافت کنیم.
callback ها
Promiseها
Async/await
کتابخونههای شخص ثالث مانند async.js، bluebird و غیره
یکی از ضعف Promiseها اینه که native راه مستقیمی برای لغو درخواست fetch نیست. اما AbortController
جدید از مشخصات js به ما امکان میده که از یه سیگنال واسه لغو یک یا چند درخواست fetch استفاده کنیم.
جریان اصلی لغو یه درخواست fetch اینجوری میشه.
یه کلاس AbortControlle
ایجاد کنیم
ویژگی سیگنال اون آبجکت ساخته شده رو دریافت کنیم و سیگنال رو به عنوان یه option به متد fetch ارسال کنیم
const controller = new AbortController(); const { signal } = controller; fetch("http://localhost:8000", { signal }).then(response => { console.log(`Request 1 is complete!`); }).catch(e => { if(e.name === "AbortError") { // We know it's been canceled! } }); fetch("http://localhost:8000", { signal }).then(response => { console.log(`Request 2 is complete!`); }).catch(e => { if(e.name === "AbortError") { // We know it's been canceled! } }); // Wait 2 seconds to abort both requests setTimeout(() => controller.abort(), 2000);
API گفتار وب برای فعال کردن مرورگرهای مدرن برای شناسایی و ترکیب گفتار (یعنی دادههای صوتی در برنامههای وب) استفاده میشه. این API توسط انجمن W3C در سال 2012 معرفی شد و دارای دو بخش اصلیه.
window.SpeechRecognition = window.webkitSpeechRecognition || window.SpeechRecognition; // webkitSpeechRecognition for Chrome and SpeechRecognition for FF const recognition = new window.SpeechRecognition(); recognition.onresult = (event) => { // SpeechRecognitionEvent type const speechToText = event.results[0][0].transcript; console.log(speechToText); } recognition.start();
در این API، مرورگر برای استفاده از میکروفون کاربر ازش اجازه می خواد
SpeechSynthesis (Text-to-Speech): این امکان رو فراهم میکنه تا یه متن رو به صدا تبدیل کنیم و به وسیله "SpeechSynthesisAPI" قابل دسترسیه.
برای مثال، کد زیر برای دریافت صدا/گفتار از متن استفاده میشه.
if('speechSynthesis' in window){ const speech = new SpeechSynthesisUtterance('Hello World!'); speech.lang = 'en-US'; window.speechSynthesis.speak(speech); }
نمونههای بالا رو میشه روی کنسول برنامهنویس مرورگر کروم (33+) تست کرد.
توجه: این API هنوز یه پیشنویس فعاله و فقط روی مرورگرهای کروم و فایرفاکس وجود داره(البته کروم فقط مشخصات رو اجرا میکنه)
هم مرورگر و هم محیطهای جاواسکریپت NodeJS با حداقل تاخیری که بیشتر از 0 میلی ثانیه اس throttles رو انجام میدن. یعنی حتی اگه تنظیم یه تاخیر 0ms به طور آنی اتفاق نیوفته.
مرورگرها: حداقل 4 میلی ثانیه تاخیر دارن. این throttles زمانی اتفاق میوفته که تماسهای متوالی به دلیل تودرتوی Callback (عمق معین) یا پس از تعداد معینی فواصل متوالی آغاز شه.
توجه: مرورگرهای قدیمی حداقل 10 میلی ثانیه تاخیر دارن.
Nodejs: حداقل 1ms تاخیر دارن. این throttles زمانی اتفاق میوفته که تاخیر بزرگتر از 2147483647 یا کمتر از 1 باشه.
بهترین مثال برای توضیح این رفتار throttling وقفه، ترتیب قطعه کد.
function runMeFirst() { console.log('My script is initialized'); } setTimeout(runMeFirst, 0); console.log('Script loaded');
و خروجی
Script loaded
My script is initialized
اگه از «setTimeout» استفاده نمیکنیم ترتیب گزارشها این شکلی میشه.
function runMeFirst() { console.log('My script is initialized'); } runMeFirst(); console.log('Script loaded');
و خروجی
My script is initialized
Script loaded
به دلیل حداقل تاخیر بیش از 0 میلی ثانیه، نمیتونیم از setTimeout(fn, 0) برای اجرای فوری کد استفاده کنیم، اما برای دستیابی به این رفتار میتونیم از window.postMessage() استفاده کنیم.
وظیفه هر کد/برنامه جاواسکریپتیه که قراره توسط مکانیسمهای استانداره اجرا شه، مثل شروع اولیه اجرای یه برنامه، اجرای یه رویداد، callback یا یه بازه زمانی یا وقفه در حال اجرا. همه این وظایف تو یه صف کار برنامه ریزی میشن
موارد استفاده برای افزودن وظایف به صف کار اینا هستن.
موقعی که یه برنامه جاواسکریپت جدید مستقیماً از کنسول اجرا میشه یا توسط عنصر <script>
اجرا میشه، وظیفه به صف کار اضافه میشه.
موقعی که یه رویداد فراخونی میشه، callback رویداد به صف کار اضافه میشه
وقتی به یه setTimeout یا setInterval رسید، callback مربوطه به صف کار اضافه میشه
Microtask کد جاواسکریپتـه که باید بلافاصله پس از تکمیل task/Microtask در حال اجرا اجرا شه. اونا در واقع به نوعی مسدود کننده هستن. یعنی تا زمانی که صف microtask خالی نشه، رشته اصلی مسدود میشه.
منابع اصلی Microtaskها عبارتند از Promise.resolve، Promise.reject، MutationObservers، IntersectionObservers و غیره.
توجه: همه این Microtaskها توی همون چرخش event-loop پردازش میشن.
MainAppLoop - این حلقه اصلی یه برنامه اس. به طور معمول این تو پایین صفحه اصلیه. خروج معمولاً نشون دهنده تمایل به بسته شدن برنامه اس. توی هر برنامه فقط یکی از این موارد میتونه وجود داشته باشه. ThreadLoop - این حلقه ایه که معمولاً تو پایین رویه اصلی یه UI Thread یافت میشه.
صف میکروتسک به کد اجازه میده بدون تداخل با کدهای دیگه که در حالت تعلیق هستن، با اولویت بالاتری اجرا بشه.
مشخصه که همهی کتابخونهها یا چارچوبهای جاواسکریپت دارای فایلهای اعلان TypeScript نیستن. اما اگه هنوزم میخواین از کتابخونهها یا فریمورکها تو فایلهای TypeScript بدون دریافت خطاهای کامپایل استفاده کنیم تنها راهحل کلمه کلیدی declare
به همراه یه اعلان متغیره. برای مثال، بیاین تصور کنیم که یه کتابخونه به نام "customLibrary" دارید که اعلان TypeScript نداره و فضای نامی به نام customLibrary توی فضای نام گلوبال داره. میتونیم از این کتابخونه توی کد تایپاسکریپت به صورت زیر استفاده کنیم.
declare var customLibrary;
در زمان اجرا، تایپاسکریپت نوع اونو به متغیر customLibrary
به صورت any ارائه میکنه. جایگزین دیگه بدون استفاده از کلمه کلیدی declare رو تو مثال زیر ببینیم:
var customLibrary: any;
Promiseها | observableها |
---|---|
فقط یه مقدار رو تو یه زمان منتشر میکنه | چندین مقدار رو تو یه دوره زمانی منتشر میکنه (جریان مقادیری از 0 تا چندگانه) |
قراره فوراً فراخوانی شن | اونا برای فراخوانی نیاز به اشتراک دارن |
Promise همیشه ناهمزمانه حتی اگه بلافاصله حل شه | observableها میتونن همزمان یا ناهمزمان |
هیچ اپراتور ارائه نمیده | اپراتورهایی مانند map، forEach، filter، reduce، retry و retryWhen و غیره رو ارائه میده. |
قابل لغو نیست | با استفاده از روش unsubscribe لغو میشن |
Heap (یا memory heap) محلیه که تو اون آبجکتها موقع تعریف متغیرها ذخیره میشن یعنی این محلیه که تمام تخصیص حافظه و عدم تخصیص تو اون انجام میشه. هر دو heap و call-stack دو ظرف زمان اجرا JS هستن.
هر زمان که زمان اجرا با متغیرها و اعلانهای تابع در کد مواجه میشه، اونا رو توی Heap ذخیره میکنه.
Event-Table
یه ساختار دادهایـه که تمام رویدادهایی رو که به صورت ناهمزمان اجرا میشن، مثل بعد از مدتی فاصله زمانی یا پس از رفع بعضی از درخواستهای API، ذخیره و ردیابی میکنه. یعنی هر زمان که یه تابع setTimeout رو فراخوانی کنیم یا عملیات async رو فراخوانی کنیم به جدول رویداد اضافه میشه. توابع رو به تنهایی اجرا نمیکنه. هدف اصلی جدول رویدادها پیگیری رویدادها و فرستادنشون به صف رویداد همونطور که توی نمودار زیر میبینیم.
Microtask Queue
صف جدیدیه که تو اون تمام وظایف آغاز شده توسط آبجکت Promise قبل از صف برگشت پردازش میشن
صف microtask قبل از کارهای رندر و نقاشی بعدی پردازش میشه. اما اگه این ریزکارها برای مدت طولانی اجرا شن، منجر به مشکل بصری میشن.
shim کتابخونهایه که یه API جدید رو با استفاده از ابزارهای اون محیط به یه محیط قدیمی تر میاره. لزوماً محدود به یه برنامه وب نیست. برای مثال، es5-shim.js برای شبیه سازی ویژگیهای ES5 توی مرورگرهای قدیمی (عمدتا قبل از IE9) استفاده میشه.
در حالی که polyfill یه قطعه کد (یا افزونه) اس که فناوری رو ارائه میکنه که شما، توسعهدهنده، از مرورگر انتظار دارید که به صورت بومی ارائه کنه.
تو یه جمله ساده، polyfill یه shim برای APIهای مرورگره.
در جاواسکریپت، دیتای primitive
عبارتند از boolean،
string،
number،
BigInt،
null،
Symbol
و undefined
. در حالی که انواع غیر primitive شامل Objectها میشه. اما با تابع زیر میتونیم به راحتی اونا رو شناسایی کنیم
const myPrimitive = 30; const myNonPrimitive = {}; function isPrimitive(val) { return Object(val) !== val; } isPrimitive(myPrimitive); isPrimitive(myNonPrimitive);
اگه مقدار یه نوع داده اولیه باشه، سازنده Object یه آبجکت wrapper جدید برای مقدار ایجاد میکنه. اما اگه مقدار یه نوع داده non-primitive (یک آبجکت) باشه، سازنده Object همون آبجکت رو میده.
Babel یه ترانسپایلر جاواسکریپت برای تبدیل کد ECMAScript 2015+ به یه نسخه سازگار جاواسکریپت تو مرورگرها یا محیطهای فعلی و قدیمی تره. که میشه موارد زیر رو درموردش نوشت:
تبدیل syntax
ویژگیهای Polyfill که در محیط هدف شما وجود نداره (با استفاده از @babel/polyfill)
تبدیل کد منبع
Node یه رشته است، اما بعضی از توابع موجود توی کتابخونه استانداره Node.js (برای مثال، توابع ماژول fs) تک رشتهای نیستن. یعنی منطق اونا خارج از رشته Node.js اجرا میشه تا سرعت و عملکرد یه برنامه رو بهبود بخشد.
بعضی از رایجترین موارد استفاده اش، سوکتهای وب با اعلانها، تغییرات ورودی کاربر، فواصل تکراری و غیره اس.
RxJS (افزونههای واکنشگرا برای جاواسکریپت) کتابخونهای برای پیادهسازی برنامهنویسی واکنشگرا با استفاده از observables
که نوشتن کد ناهمزمان یا مبتنی بر تماس رو آسانتر میکنه. همچنین توابع کاربردی رو برای ایجاد و کار با مشاهده پذیرها فراهم میکنه.
توابعی که با Function-constructor
ایجاد میشن، برای زمینههای ایجاد خود بسته ایجاد نمیکنن، اما همیشه در محدوده جهانی ایجاد میشن یعنی تابع فقط میتونه به متغیرهای محلی خود و متغیرهای دامنه جهانی دسترسی داشته باشه. در حالی که اعلانهای تابع میتونن به متغیرهای تابع بیرونی (بسته شدن) هم دسترسی داشته باشن.
بیاین این تفاوت رو با یه مثال ببینیم،
Function Constructor:
var a = 100; function createFunction() { var a = 200; return new Function('return a;'); } console.log(createFunction()()); // 100
Function declaration:
var a = 100; function createFunction() { var a = 200; return function func() { return a; } } console.log(createFunction()()); // 200
شرایط اتصال کوتاه برای روش خلاصهشده نوشتن دستورات if ساده استفاده میشه. بیاین سناریو رو با استفاده از یه مثال نشون بدیم. اگه بخوایم وارد پورتالی با شرایط احراز هویت بشیم، کد جاوااسکریپتمون به این شکل نوشته میشه:
if (authenticate) { loginToPorta(); }
از اونجایی که عملگرهای منطقی جاواسکریپت از چپ به راست ارزیابی میشن عبارت بالا رو میشه با استفاده از عملگر منطقی && ساده کرد.
authenticate && loginToPorta();
ویژگی length یه آرایه برای تغییر اندازه یا خالی کردن سریع آرایه اس. بیاین ویژگی length رو روی آرایه اعداد اعمال کنیم تا تعداد عناصر رو از 5 به 2 تغییر بدیم:
const array = [1, 2, 3, 4, 5]; console.log(array.length); // 5 array.length = 2; console.log(array.length); // 2 console.log(array); // [1,2]
و آرایه رو هم میشه خالی کرد:
const array = [1, 2, 3, 4, 5]; array.length = 0; console.log(array.length); // 0 console.log(array); // []
Observable
اساساً تابعیه که میتونه جریانی از مقادیر رو به صورت همزمان یا ناهمزمان به یه ناظر در طول زمان برگردونه. مصرف کننده میتونه با فراخوانی متد subscribe
مقدار رو دریافت کنه.
بیاین به یه مثال ساده از یه Observable نگاه کنیم:
import { Observable } from 'rxjs'; const observable = new Observable(observer => { setTimeout(() => { observer.next('Message from a Observable!'); }, 3000); }); observable.subscribe(value => console.log(value));
توجه: Observableها هنوز بخشی از زبان جاواسکریپت نیستن اما پیشنهاد شده که به زبان اضافه بشن.
تفاوت اصلی بین اعلانهای تابع و اعلانهای کلاس hoisting
هس. اعلانهای تابع میشن hoist اما اعلانهای کلاس نه.
Classes:
const user = new User(); // ReferenceError class User {}
Constructor Function:
const user = new User(); // No error function User() { }
یه تابع async تابعیه که با کلمه کلیدی async
اعلام شده که با اجتناب از زنجیره پرامیس رفتار ناهمزمان و مبتنی بر قول به سبک تمیزتری نوشته شه. این توابع میتونن شامل صفر یا بیشتر عبارت await
باشن.
بیاین یه مثال تابع همگام زیر رو در نظر بگیریم،
async function logger() { let data = await fetch('http://someapi.com/users'); // pause until fetch returns console.log(data) } logger();
این اساساً خوبی نحوی بیش از پرامیسها و توابع جنریتور ES2015 هست.
موقع استفاده از کدهایasync و ناهمزمان، Promiseهای ES6 میتونن زندگی برنامهنویس رو بدون داشتن ترس از callbackها و مدیریت خطا در هر خط آسانتر میکنن. اما Promiseها مشکلاتی دارن و بزرگترین اونا بهطور پیشفرض مخفی کردن خطاهاس.
فرض کنیم انتظار دارین برای تمام موارد زیر یه خطا توی کنسول چاپ بشه.
Promise.resolve('promised value').then(function() { throw new Error('error'); }); Promise.reject('error value').catch(function() { throw new Error('error'); }); new Promise(function(resolve, reject) { throw new Error('error'); });
اما خیلی از محیطهای جاواسکریپت مدرن وجود دارن که هیچ خطایی رو چاپ نمیکنن. میتونیم این مشکل رو به روشهای مختلف حل کنیم.
اضافه کردن یه بلوک catch به اخر هر زنجیره: ما میتونیم یه بلوک catch
به أخر زنجیره پرامیسهامون اضافه گنیم
Promise.resolve('promised value').th (function() { throw new Error('error'); }).catch(function(error) { console.error(error.stack); });
اما تایپ کردن برای هر زنجیره پرامیسها و پرمخاطب هم خیلی سخته.
اضافه کردن متد done: میتونیم ابتدا راه حلها رو جایگزین کنیم و بعد با روش انجام شده بلوکها رو بگیریم
Promise.resolve('promised value').done(function() { throw new Error('error'); });
فرض کنیم میخواییم دادهها رو با استفاده از HTTP fetch کنیم و بعداً پردازش دادههای حاصل رو به صورت ناهمزمان انجام بدیم. میتونیم بلوک done رو به صورت زیر بنویسیم.
getDataFromHttp() .then(function(result) { return processDataAsync(result); }) .done(function(processed) { displayData(processed); });
در آینده، اگه API کتابخونه پردازش به همگام تغییر کنه، میتونیم بلوک done رو حذف کنیم.
getDataFromHttp() .then(function(result) { return displayData(processDataAsyn(result)); })
سپس فراموش کردین که بلوک «انجام شد» رو به بلوک then اضافه کنیم که منجر به خطاهای خاموش میشه.
Extend ES6 Promises by Bluebird:
Bluebird-API میاد Promiseهای اکما اسکریپت رو گسترش میده تا در راه حل دوم مشکلی ایجاد نشه. این کتابخونه یه کنترل کننده "پیش فرض" در Rejection هس که تمام خطاها رو از Promises رد شده به stderr چاپ میکنه. پس از نصب، میتونیم ردهای کنترل نشده رو پردازش کنیم
Promise.onPossiblyUnhandledRejection(function(error){ throw error; });
یه reject رو انجام بدین فقط با یه catch خالی اونو مدیریت کنیم
Promise.reject('error value').catch(function() {});
Deno یه ران تایم(run-time) ساده، مدرن و ایمن برای جاواسکریپت و تایپاسکریپته که از موتور جاواسکریپت V8 و زبان برنامه نویسی Rust استفاده میکنه و توسط رایان دال، خالق نود جی اس استارت توسعهاش زده شده.
به طور پیش فرض، آبجکتهاargument
ساده قابل تکرار نیستن. اما میتونیم با تعریف ویژگی «Symbol.iterator» روی اون شی رو قابل تکرار کنیم.
بیاین این رو با یه مثال نشون بدیم،
const collection = { one: 1, two: 2, three: 3, [Symbol.iterator]() { const values = Object.keys(this); let i = 0; return { next: () => { return { value: this[values[i++]], done: i > values.length } } }; } }; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // → {value: 1, done: false} console.log(iterator.next()); // → {value: 2, done: false} console.log(iterator.next()); // → {value: 3, done: false} console.log(iterator.next()); // → {value: undefined, done: true}
فرآیند بالا رو میشه با استفاده از یه تابع مولد ساده کرد:
const collection = { one: 1, two: 2, three: 3, [Symbol.iterator]: function * () { for (let key in this) { yield this[key]; } } }; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // {value: 1, done: false} console.log(iterator.next()); // {value: 2, done: false} console.log(iterator.next()); // {value: 3, done: false} console.log(iterator.next()); // {value: undefined, done: true}
فراخونی دنباله یه فراخوانی فرعی یا تابعیه که به عنوان آخرین عمل یه تابع فراخوانی انجام میشه. در حالی که فراخوانی دنباله مناسب (PTC) تکنیکیه که تو اون برنامه یا کد فریمهای پشته ای(stack) اضافی برای بازگشت ایجاد نمیکنه، زمانی که فراخوانی تابع یه فراخوانی دنباله اس.
برای مثال، بازگشت کلاسیک یا سر تابع فاکتوریل پایین به پشته(stack) برای هر مرحله بستگی داره. هر مرحله باید تا "n * فاکتوریل(n - 1)" پردازش شه:
function factorial(n) { if (n === 0) { return 1 } return n * factorial(n - 1) } console.log(factorial(5)); //120
اما اگه از callbackها Tail استفاده میکنیم اونا تمام دادههای لازم رو که بهش نیاز داره رو بدون تکیه بر پشته(stack)، موقع برگشت به پایین منتقل میکنن.
function factorial(n, acc = 1) { if (n === 0) { return acc } return factorial(n - 1, n * acc) } console.log(factorial(5)); //120
الگوی بالا همون خروجی مورد اول رو برمیگردونه. اما انباشت کننده کل رو به عنوان آرگومان بدون استفاده از حافظه پشته توی callBack ردیابی میکنه.
اگه نمیدونیم یه مقدار یه Promise هس یا نه، مقدار رو به صورت Promise.resolve(value)
بپیچید که یه قول رو برمیگردونه.
function isPromise(object){ if(Promise && Promise.resolve){ return Promise.resolve(object) == object; }else{ throw "Promise not supported in your environment" } } const i = 1; const promise = new Promise(function(resolve,reject){ resolve() }); console.log(isPromise(i)); // false console.log(isPromise(p)); // true
راه دیگر اینه که نوع handler.then رو بررسی کنیم
function isPromise(value) { return Boolean(value && typeof value.then === 'function'); } const i = 1; const promise = new Promise(function(resolve,reject){ resolve() }); console.log(isPromise(i)) // false console.log(isPromise(promise)); // true
میتونیم از ویژگی شبه new.target
ß برای تشخیص اینکه آیا یه تابع به عنوان سازنده (با استفاده از عملگر جدید) فراخوانی شده یا به عنوان یه فراخوانی تابع معمولی استفاده کنیم.
اگه سازنده یا تابعی با استفاده از عملگر جدید فراخوانی شه، new.target یه مرجع به سازنده یا تابع برمیگردونه.
برای فراخوانی تابع، new.target تعریف نشده اس.
function Myfunc() { if (new.target) { console.log('called with new'); } else { console.log('not called with new'); } } new Myfunc(); // called with new Myfunc(); // not called with new Myfunc.call({}); //not called with new
آبجکت argument
آرایه ماننده اما آرایه نیست. در حالی که توی Rest پارامترها آرایه هستن.
آبجکت argument
از روشهایی مانند sort، map، forEach یا pop پشتیبانی نمیکنه. در حالی که این روشها رو میشه رو پارامترهای Rest استفاده کرد.
توی Rest پارامترها فقط اونایی هستن که نام جداگانه ای به اونا داده نشده در حالی که آبجکت argument
شامل تمام آرگومانهای ارسال شده به تابعه.
پارامتر Rest تمام عناصر باقی مانده رو تو یه آرایه جمع آوری میکنه. در حالی که عملگر Spread به تکرارپذیرها (آرایهها / اشیاء / رشتهها) اجازه میده تا به آرگومانها / عناصر منفرد گسترش پیدا کنن. یعنی پارامتر Rest مخالف عملگر spread هس.
تعریف بیانی تابع generator :
function* myGenFunc() { yield 1; yield 2; yield 3; } const genObj = myGenFunc();
تعریف عبارتی تابع generator:
const myGenFunc = function* () { yield 1; yield 2; yield 3; }; const genObj = myGenFunc();
تعریف بیانی تابع generator در آبجکت به صورت متد:
const myObj = { * myGeneratorMethod() { yield 1; yield 2; yield 3; } }; const genObj = myObj.myGeneratorMethod();
تعریف تابع generator در کلاسها:
class MyClass { * myGeneratorMethod() { yield 1; yield 2; yield 3; } } const myObject = new MyClass(); const genObj = myObject.myGeneratorMethod();
تعریف تابع generator به عنوان یک ویژگی محاسبه شده:
const SomeObj = { *[Symbol.iterator] () { yield 1; yield 2; yield 3; } } console.log(Array.from(SomeObj)); // [ 1, 2, 3 ]
آرایهها و TypedArrays
رشتهها: روی هر کاراکتر یا نقاط کد یونیکد تکرار کنیم
Map: روی جفتهای کلید-مقدار آن تکرار شه
مجموعهها: روی عناصر خود تکرار میشه
آرگومانها: یه متغیر خاص آرایه مانند در توابع
مجموعه DOM مانند NodeList
از for...in و for...of برای پیمایش بر روی داده ها با خاصیت تکرار (مثل آرایه ها)، استفاده میشه. تنها تفاوت در مورد چیزیه که اونا تکرار میکنن:
for..in روی تمام کلیدهای خصوصیت شمارش پذیر یه شی تکرار میشه
for..of iterates بیش از مقادیر یه شی قابل تکرار.
بیاین این تفاوت رو توی یه مثال ببینیم،
let arr = ['a', 'b', 'c']; arr.newProp = 'newVlue'; // key are the property keys for (let key in arr) { console.log(key); } // value are the property values for (let value of arr) { console.log(value); }
از اونجا که حلقه for..in روی کلیدهای شی تکرار میشه حلقه اول 0، 1، 2 و newProp رو در حین تکرار روی شی آرایه ثبت میکنه. حلقه for..of روی مقادیر یه ساختار داده arr تکرار میشه و a، b، c رو تو کنسول ثبت میکنه.
خصوصیات Instance باید در داخل متدهای کلاس تعریف بشن. برای مثال، مشخصات نام و سن سازنده داخلی هم مثل مثال پایین تعریف میشن.
class Person { constructor(name, age) { this.name = name; this.age = age; } }
اما خصوصیات داده Static(class) و prototype باید خارج از اعلان ClassBody تعریف بشن. بیاین مقدار سن رو برای کلاس Person به صورت زیر اختصاص بدیم.
Person.staticAge = 30; Person.prototype.prototypeAge = 40;
isNaN: تابع سراسری «isNaN» آرگومان رو به عدد تبدیل میکنه و اگه مقدار حاصل NaN باشه، true رو برمیگردونه.
Number.isNaN: این روش آرگومان رو تبدیل نمیکنه. اما زمانی که نوع یه عدد و مقدار NaN باشه مقدار true رو برمیگردونه.
بیاین تفاوت رو با یه مثال ببینیم:
isNaN(‘hello’); // true Number.isNaN('hello'); // false