مخزن اصلی: airbnb/javascript
یک رویکرد عمدتاً معقول برای جاوا اسکریپت
نکته: این راهنما فرض می کند که شما در حال استفاده از Babel هستید، و مستلزم این است که از babel-preset-airbnb یا معادل آن استفاده کنید. این راهنما همچنین فرض میکند که در حال استفاده از shims/polyfills در برنامه خود هستید, به همراه airbnb-browser-shims یا معادل آن.
سایر راهنماها:
- انواع داده ها
- مراجع
- اشیاء
- آرایه ها
- استخراج(Destructuring)
- رشته ها
- توابع
- توابع پیکانی
- کلاس ها و سازندگان
- ماژول ها
- تکرار کننده ها و مولدها
- خصوصیات
- متغیرها
- بالا بردن
- اپراتورهای مقایسه و برابری
- بلوک ها
- بیانیه های کنترلی
- توضیح نویسی
- فضای سفید
- ویرگول ها
- نقطه ویرگول ها
- نوع ریختگی و اجبار
- قراردادهای نامگذاری
- دسترسی گیرنده / دهنده ها
- رویدادها
- جی کوئری
- سازگاری با ECMAScript 5
- سبک های ECMAScript 6+ (ES 2015+)
- کتابخانه استاندارد
- آزمایش کردن
- کارایی
- منابع
- موارد استفاده در دنیای واقعی
- ترجمه
- راهنمای راهنمای سبک جاوا اسکریپت
- درباره جاوا اسکریپت با ما گپ بزنید
- مشارکت کنندگان
- مجوز
- اصلاحیه ها
-
1.1 نوع اولیه ها: هنگامی که به یک نوع اولیه دسترسی دارید، مستقیماً روی مقدار آن کار کنید.
-
string -
number -
boolean -
null -
undefined -
symbol -
bigint
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9نمی توان به طرز درستی Symbols و BigInts ها را polyfill کرد، بنابراین نباید هنگام هدف قرار دادن مرورگرها/محیط هایی که به صورت بومی از آنها پشتیبانی نمی کنند استفاده شوند.
-
1.2 انواع پیچیده: هنگامی که به یک نوع پیچیده دسترسی پیدا می کنید، با یک مرجع به مقدار آن کار کنید.
-
object -
array -
function
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9-
2.1 از
constبرای همه مراجع خود استفاده کنید; از استفاده ازvarاجتناب کنید.
eslint:prefer-const,no-const-assignچرا؟ این کار تضمین می کند که نتوانید مراجع خود را مجدداً اختصاص دهید، که این کار می تواند منجر به اشکالات و درک کد دشوارتر شود.
// بد
var a = 1;
var b = 2;
// خوب
const a = 1;
const b = 2;-
2.2 اگر باید مراجع را دوباره اختصاص دهید, از
letبه جایvarاستفاده کنید. eslint:no-varچرا؟
letبه جای محدوده تابعی مانندvarدارای محدوده بلوکی است.
// بد
var count = 1;
if (true) {
count += 1;
}
// خوب،از let استفاده کنید
let count = 1;
if (true) {
count += 1;
}- 2.3 توجه داشته باشید که هر دو
letوconstدارای محدوده بلوکی هستند، در حالی کهvarدارای محدوده تابعی است.
// const و let فقط در بلوک هایی که در آنها تعریف شده اند وجود دارند.
{
let a = 1;
const b = 1;
var c = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
console.log(c); // Prints 1در کد بالا، میبینید که ارجاع
aوbیک ReferenceError ایجاد میکند، در حالی کهcحاوی عدد است. این به این دلیل است کهaوbدارای محدوده بلوکی هستند، در حالی کهcبه تابع حاوی آن محدوده است.
- 3.1 از literal syntax برای ایجاد شیء ها استفاده کنید. eslint:
no-new-object
// بد
const item = new Object();
// خوب
const item = {};-
3.2 هنگام ایجاد اشیایی با ویژگی های پویا از نام های ویژگی محاسبه شده استفاده کنید.
چرا؟ این کار به شما اجازه می دهند تمام خصوصیات یک شیء را در یک مکان تعریف کنید.
function getKey(k) {
return `a key named ${k}`;
}
// بد
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// خوب
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};- 3.3 از روش اختصار شیء استفاده کنید. eslint:
object-shorthand
// بد
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// خوب
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};-
3.4 از کوتاه نویسی استفاده کنید. eslint:
object-shorthandچرا؟ مختصرتر و توصیف کننده تر است.
const lukeSkywalker = 'Luke Skywalker';
// بد
const obj = {
lukeSkywalker: lukeSkywalker,
};
// خوب
const obj = {
lukeSkywalker,
};-
3.5 کوتاه نویسی های خود را در ابتدای اعلان شیء گروه بندی کنید.
چرا؟ تشخیص اینکه کدام خصوصیات شیء از کوتاه نویسی استفاده می کنند آسان تر است.
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// بد
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// خوب
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};-
3.6 فقط ویژگی هایی را داخل کوتیشن بگذارید که شناسه های نامعتبر هستند. eslint:
quote-propsچرا؟ به طور کلی ما خواندن آن را به صورت ذهنی ساده تر می دانیم.این کار برجسته سازی کد را بهبود می بخشد و همچنین توسط بسیاری از موتورهای جاوا اسکریپتی به راحتی بهینه می شود.
// بد
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// خوب
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};-
3.7 هیچوقت
Object.prototypeرا مستقیماً فراخوانی نکنید , مثلاhasOwnProperty,propertyIsEnumerable, وisPrototypeOf.
eslint:no-prototype-builtinsچرا؟ این متدها ممکن است با ویژگیهای شیء مورد نظر تداخل داشته باشند -
{ hasOwnProperty: false }را در نظر بگیرید - یا شی، ممکن است یک شی، تهی باشد (Object.create(null)).
// بد
console.log(object.hasOwnProperty(key));
// خوب
console.log(Object.prototype.hasOwnProperty.call(object, key));
// بهترین
const has = Object.prototype.hasOwnProperty; // جستجو را یک بار در محدوده ماژول کش کنید.
console.log(has.call(object, key));
/* یا */
import has from 'has'; // https://www.npmjs.com/package/has
console.log(has(object, key));
/* یا */
console.log(Object.hasOwn(object, key)); // https://www.npmjs.com/package/object.hasown- 3.8 برای کپی کردن اشیاء
Object.assignسینتکس گسترش شیء را ترجیح دهید. از سینتکس گسترش شیء استفاده کنید تا یک شیء جدید با ویژگی های خاصی حذف شده باشد. eslint:prefer-object-spread
// خیلی بد
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // این `اصلی` را تغییر می دهد ಠ_ಠ
delete copy.a; // همینطور این کار
// بد
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// خوب
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }- 4.1 برای ایجاد آرایه از literal syntax استفاده کنید. eslint:
no-array-constructor
// بد
const items = new Array();
// خوب
const items = [];- 4.2 به جای انتساب مستقیم برای افزودن آیتم ها به یک آرایه از
Array.pushاستفاده کنید.
const someStack = [];
// بد
someStack[someStack.length] = 'abracadabra';
// خوب
someStack.push('abracadabra');- 4.3 برای کپی کردن آرایه ها از
...گسترش آرایه استفاده کنید.
// بد
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i <br len; i += 1) {
itemsCopy[i] = items[i];
}
// خوب
const itemsCopy = [...items];- 4.4 برای تبدیل یک شیء تکرارپذیر به آرایه, از اسپرد
...به جایArray.fromاستفاده کنید.
const foo = document.querySelectorAll('.foo');
// خوب
const nodes = Array.from(foo);
// بهترین
const nodes = [...foo];- 4.5 برای تبدیل یک شیء آرایه مانند به یک آرایه از
Array.fromاستفاده کنید.
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
// بد
const arr = Array.prototype.slice.call(arrLike);
// خوب
const arr = Array.from(arrLike);- 4.6 برای نگاشت روی تکرارپذیرها از
Array.fromبه جای اسپرد...استفاده کنید، زیرا از ایجاد یک آرایه میانی جلوگیری می کند.
// بد
const baz = [...foo].map(bar);
// خوب
const baz = Array.from(foo, bar);- 4.7 از عبارات بازگشتی در فراخوانی متد آرایه ها استفاده کنید. اگر بدنه تابع از یک عبارت واحد تشکیل شده باشد که یک عبارت را بدون عوارض جانبی برمی گرداند، حذف
returnاشکالی ندارد. eslint:array-callback-return
// خوب
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// خوب
[1, 2, 3].map((x) => x + 1);
// بد - بدون مقدار بازگشتی به این معنی است که `acc` پس از اولین تکرار نامشخص می شود
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
});
// خوب
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
return flatten;
});
// بد
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// خوب
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});- 4.8 اگر یک آرایه دارای چندین خط است، پس از باز کردن و قبل از بستن پرانتزهای آرایه، از شکستن خط استفاده کنید.
// بد
const arr = [
[0, 1], [2, 3], [4, 5],
];
const objectInArray = [{
id: 1,
}, {
id: 2,
}];
const numberInArray = [
1, 2,
];
// خوب
const arr = [[0, 1], [2, 3], [4, 5]];
const objectInArray = [
{
id: 1,
},
{
id: 2,
},
];
const numberInArray = [
1,
2,
];-
5.1 هنگام دسترسی و استفاده از چندین ویژگی یک شی، از استخراج ساختار استفاده کنید. eslint:
prefer-destructuringچرا؟ Destructuring شما را از ایجاد مراجع موقت برای آن ویژگی ها و دسترسی مکرر به شیء نجات می دهد. تکرار دسترسی به شیء کدهای تکراری بیشتری ایجاد می کند، به خواندن بیشتر نیاز دارد و فرصت های بیشتری برای اشتباهات ایجاد می کند. استخراج اشیاء همچنین به جای نیاز به خواندن کل بلوک برای تعیین آنچه مورد استفاده قرار می گیرد، یک مکان واحد برای تعریف ساختار شیء که در بلوک استفاده می شود، ارائه می دهد.
// بد
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// خوب
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// بهترین
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}- 5.2 از استخراج آرایه استفاده کنید. eslint:
prefer-destructuring
const arr = [1, 2, 3, 4];
// بد
const first = arr[0];
const second = arr[1];
// خوب
const [first, second] = arr;-
5.3 از ساختارشکنی شیء برای مقادیر چندگانه بازگشتی استفاده کنید، نه برای استخراج آرایه.
چرا؟ میتوانید به مرور زمان ویژگیهای جدید اضافه کنید یا ترتیب کارها را بدون شکستن سایتهای تماس تغییر دهید.
// بد
function processInput(input) {
// سپس معجزه رخ می دهد
return [left, right, top, bottom];
}
// تماس گیرنده باید در مورد ترتیب برگشت داده ها فکر کند
const [left, __, top] = processInput(input);
// خوب
function processInput(input) {
// سپس معجزه رخ می دهد
return { left, right, top, bottom };
}
// تماس گیرنده فقط داده های مورد نیاز خود را انتخاب می کند
const { left, top } = processInput(input); // بد
const name = "Capt. Janeway";
// بد - لیترال ها باید شامل درون یابی یا خطوط جدید باشند
const name = `Capt. Janeway`;
// خوب
const name = 'Capt. Janeway';-
6.2 رشته هایی که باعث می شوند خط بیش از 100 کاراکتر باشد، نباید با استفاده از الحاق رشته ها در چندین خط نوشته شوند.
چرا؟ کار با رشته های شکسته عذاب آور است و باعث می شود که کد کمتر قابل جستجو باشد.
// بد
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';
// بد
const errorMessage = 'This is a super long error that was thrown because ' +
'of Batman. When you stop to think about how Batman had anything to do ' +
'with this, you would get nowhere fast.';
// خوب
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';-
6.3 هنگام ساختن رشته ها از طریق برنامه، از رشته های الگویی به جای الحاق استفاده کنید. eslint:
prefer-templatetemplate-curly-spacingچرا؟ رشته های الگویی به شما یک سینتکس خوانا و مختصر با خطوط جدید مناسب و ویژگی های درون یابی رشته ای می دهد.
// بد
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// بد
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// بد
function sayHi(name) {
return `How are you, ${ name }?`;
}
// خوب
function sayHi(name) {
return `How are you, ${name}?`;
}- 6.4 در یک رشته هرگز از
()evalاستفاده نکنید زیرا آسیب پذیری های زیادی را به برنامه اضافه میکند.
eslint:no-eval
-
6.5 بی جهت از کاراکتر
\در رشته ها استفاده نکنید. eslint:no-useless-escapeچرا؟
\به خوانایی کد آسیب میرسانند، بنابراین فقط در صورت لزوم باید وجود داشته باشند.
// بد
const foo = '\'this\' \i\s \"quoted\"';
// خوب
const foo = '\'this\' is "quoted"';
const foo = `my name is '${name}'`;-
7.1 به جای اعلان تابع از عبارات تابع نامگذاری شده استفاده کنید. eslint:
func-styleچرا؟ اعلانهای تابع بالا میروند، به این معنی که ارجاع به تابع قبل از تعریف در فایل خیلی آسان است. این به خوانایی و قابلیت نگهداری آسیب می رساند. اگر متوجه شدید که تعریف یک تابع به اندازه کافی بزرگ یا پیچیده است که در درک بقیه فایل اختلال ایجاد می کند، شاید وقت آن رسیده که آن را در ماژول خودش استخراج کنید! فراموش نکنید که صراحتاً عبارت را نامگذاری کنید، صرف نظر از اینکه نام از متغیر حاوی استنباط شده باشد یا نه (که اغلب در مرورگرهای مدرن یا هنگام استفاده از کامپایلرهایی مانند Babel چنین است). این هر گونه فرضی را که در مورد پشته تماس خطا وجود دارد حذف می کند. (بحث)
// بد
function foo() {
// ...
}
// بد
const foo = function () {
// ...
};
// خوب
// نام واژگانی متمایز از فراخوان ارجاع شده به متغیر
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};-
7.2 عبارات تابع فورا فراخوانی شده را در پرانتز قرار دهید. eslint:
wrap-iifeچرا؟ یک عبارت تابعی که بلافاصله فراخوانی می شود یک واحد است - بسته بندی هر دو آن، و پرانتزهای فراخوانی آن، این را به وضوح بیان می کند. توجه داشته باشید که در دنیایی که ماژولها در همه جا وجود دارد، تقریباً هرگز نیازی به IIFE ندارید.
// عبارت تابع فوری فراخوانی شده (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());- 7.3 هرگز یک تابع را در یک بلوک غیر تابعی (
if،whileو غیره) اعلام نکنید. به جای آن تابع را به یک متغیر اختصاص دهید. مرورگرها به شما اجازه انجام این کار را میدهند، اما همه آنها آن را متفاوت تفسیر میکنند، که خبر بدی است. eslint:no-loop-func
- 7.4 نکته: ECMA-262 یک
blockرا به عنوان لیستی از عبارات تعریف می کند. اعلان تابع یک عبارت نیست.
// بد
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// خوب
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}- 7.5 هرگز پارامتری را
argumentsنامگذاری نکنید. این موضوع بر شیءargumentsکه به هر محدوده تابعی داده می شود اولویت خواهد داشت.
// بد
function foo(name, options, arguments) {
// ...
}
// خوب
function foo(name, options, args) {
// ...
}-
7.6 هرگز از
argumentsاستفاده نکنید، به جای آن از دستور rest...استفاده کنید. eslint:prefer-rest-paramsچرا؟
...در مورد اینکه کدام آرگومانهایی را میخواهید بکشید، صریح است. بعلاوه، آرگومانهای rest یک آرایه واقعی هستند و فقط آرگومانهای آرایه مانند نیستند.
// بد
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// خوب
function concatenateAll(...args) {
return args.join('');
}- 7.7 به جای تغییر (mutate) در آرگومان های تابع، از نحو پارامتر پیش فرض استفاده کنید.
// بسیار بد
function handleThings(opts) {
// نه! ما نباید آرگومان های تابع را تغییر دهیم.
// مضاعف بد: اگر گزینهها نادرست باشد، روی یک شیء تنظیم میشود که ممکن است
// همان چیزی باشد که شما میخواهید اما میتواند اشکالات ظریفی را ایجاد کند.
opts = opts || {};
// ...
}
// همچنان بد
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// خوب
function handleThings(opts = {}) {
// ...
}-
7.8 با پارامترهای پیش فرض از عوارض جانبی اجتناب کنید.
چرا؟ آنها برای استدلال گیج کننده هستند.
let b = 1;
// بد
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3- 7.9 همیشه پارامترهای پیش فرض را در آخر قرار دهید. eslint:
default-param-last
// بد
function handleThings(opts = {}, name) {
// ...
}
// خوب
function handleThings(name, opts = {}) {
// ...
}-
7.10 هرگز از سازنده تابع برای ایجاد یک تابع جدید استفاده نکنید. eslint:
no-new-funcچرا؟ ایجاد یک تابع به این روش، رشته ای را مشابه
eval()ارزیابی می کند که آسیب پذیری ها را باز می کند.
// بد
const add = new Function('a', 'b', 'return a + b');
// همچنان بد
const subtract = Function('a', 'b', 'return a - b');-
7.11 فاصله گذاری در امضای تابع eslint:
space-before-function-parenspace-before-blocksچرا؟ سازگاری خوب است، و هنگام افزودن یا حذف نام، مجبور نیستید فضایی را اضافه یا حذف کنید.
// بد
const f = function(){};
const g = function (){};
const h = function() {};
// خوب
const x = function () {};
const y = function a() {};-
7.12 هرگز پارامترها را تغییر ندهید. eslint:
no-param-reassignچرا؟ دستکاری اشیاء ارسال شده به عنوان پارامتر می تواند باعث ایجاد عوارض جانبی متغیر ناخواسته در تماس گیرنده اصلی شود.
// بد
function f1(obj) {
obj.key = 1;
}
// خوب
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
}-
7.13 هرگز پارامترها را تغییر ندهید. eslint:
no-param-reassignرا؟ تخصیص مجدد پارامترها میتواند منجر به رفتار غیرمنتظره شود، بهویژه هنگام دسترسی به شیء
arguments. همچنین می تواند باعث مشکلات بهینه سازی شود، به خصوص در موتور جاوا اسکریپت V8.
// بد
function f1(a) {
a = 1;
// ...
}
function f2(a) {
if (!a) { a = 1; }
// ...
}
// خوب
function f3(a) {
const b = a || 1;
// ...
}
function f4(a = 1) {
// ...
}-
7.14 برای فراخوانی توابع متغیر، استفاده از اسپرد سینتکس
...را ترجیح دهید. eslint:prefer-spreadچرا؟ اینگونه کد تمیزتر است، شما نیازی به ارائه یک زمینه ندارید، و نمی توانید به راحتی
applyباnewبنویسید.
// بد
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);
// خوب
const x = [1, 2, 3, 4, 5];
console.log(...x);
// بد
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
// خوب
new Date(...[2016, 8, 5]);- 7.15 توابع با امضای چند خطی یا فراخوانی باید درست مانند هر فهرست چند خطی دیگر در این راهنما تورفتگی داشته باشند: با هر مورد در یک خط به تنهایی، با یک کاما انتهایی در آخرین مورد. eslint:
function-paren-newline
// بد
function foo(bar,
baz,
quux) {
// ...
}
// خوب
function foo(
bar,
baz,
quux,
) {
// ...
}
// بد
console.log(foo,
bar,
baz);
// خوب
console.log(
foo,
bar,
baz,
);-
8.1 هنگامی که باید از یک تابع ناشناس استفاده کنید (مانند هنگام ارسال یک تماس درونی)، از نماد تابع فلش استفاده کنید. eslint:
prefer-arrow-callback,arrow-spacingچرا؟ این یک نسخه از تابع را ایجاد می کند که در زمینه
thisاجرا می شود، که معمولاً همان چیزی است که شما می خواهید، و یک سینتکس مختصرتر است.چرا که نه؟ اگر یک تابع نسبتاً پیچیده دارید، ممکن است آن منطق را به عبارت تابع نامگذاری شده خودش منتقل کنید.
// بد
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// خوب
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});-
8.2 اگر بدنه تابع از یک عبارت واحد تشکیل شده است که یک عبارت را بدون عوارض جانبی برمی گرداند، بریس ها را حذف کنید و استفاده کنید. بازگشت ضمنی در غیر این صورت، بریس ها را نگه دارید و از عبارت
returnاستفاده کنید. eslint:arrow-parens,arrow-body-styleچرا؟ خوانایی بهتر. هنگامی که چندین تابع به هم متصل می شوند،کد به خوبی خوانده می شود.
// بد
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// خوب
[1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
// خوب
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
// خوب
[1, 2, 3].map((number, index) => ({
[index]: number,
}));
// بدون بازگشت ضمنی با عوارض جانبی
function foo(callback) {
const val = callback();
if (val === true) {
// اگر تماس برگشتی true است، کاری انجام دهید
}
}
let bool = false;
// بد
foo(() => bool = true);
// خوب
foo(() => {
bool = true;
});-
8.3 در صورتی که عبارت در چندین خط باشد، برای خوانایی بهتر، آن را در پرانتز قرار دهید.
چرا؟ این به وضوح نشان می دهد که تابع کجا شروع شده و به پایان می رسد.
// بد
['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
);
// خوب
['get', 'post', 'put'].map((httpMethod) => (
Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
));-
8.4 برای وضوح و سازگاری همیشه پرانتزها را در اطراف استدلال ها قرار دهید. eslint:
arrow-parensچرا؟ هنگام افزودن یا حذف آرگومانها، تغییر تفاوت را به حداقل میرساند.
// بد
[1, 2, 3].map(x => x * x);
// خوب
[1, 2, 3].map((x) => x * x);
// بد
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// خوب
[1, 2, 3].map((number) => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// بد
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// خوب
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});- 8.5 از گیج شدن نحو تابع پیکان (
=>) با عملگرهای مقایسه (<=،>=) خودداری کنید. eslint:no-confusing-arrow
// بد
const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize;
// بد
const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize;
// خوب
const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize);
// خوب
const itemHeight = (item) => {
const { height, largeSize, smallSize } = item;
return height <= 256 ? largeSize : smallSize;
};- 8.6 مکان بدنه های تابع پیکان را با بازگشت های ضمنی اعمال کنید. eslint:
implicit-arrow-linebreak
// بد
(foo) =>
bar;
(foo) =>
(bar);
// خوب
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)-
9.1 همیشه از
classاستفاده کنید. از دستکاری مستقیمprototypeخودداری کنید.چرا؟ سینتکس
classمختصرتر و سادهتر است.
// بد
function Queue(contents = []) {
this.queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
};
// خوب
class Queue {
constructor(contents = []) {
this.queue = [...contents];
}
pop() {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
}
}-
9.2 برای ارث بردن از
extendsاستفاده کنید.چرا؟ این یک روش داخلی برای به ارث بردن عملکرد نمونه اولیه بدون شکستن
instanceofاست.
// بد
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this.queue[0];
};
// خوب
class PeekableQueue extends Queue {
peek() {
return this.queue[0];
}
}- 9.3 متدها میتوانند
thisرا برای کمک به زنجیرهسازی متد برگردانند.
// بد
Jedi.prototype.jump = function () {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function (height) {
this.height = height;
};
const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined
// خوب
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);- 9.4 نوشتن یک متد سفارشی
()toStringاشکالی ندارد، فقط مطمئن شوید که با موفقیت کار می کند و عوارض جانبی ایجاد نمی کند.
class Jedi {
constructor(options = {}) {
this.name = options.name || 'no name';
}
getName() {
return this.name;
}
toString() {
return `Jedi - ${this.getName()}`;
}
}- 9.5 در صورتی که کلاس ها یک سازنده پیش فرض داشته باشند. یک تابع سازنده خالی یا تابعی که فقط به یک کلاس والد واگذار می شود، ضروری نیست. eslint:
no-useless-constructor
// بد
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// بد
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// خوب
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}-
9.6 از تکرار اعضای کلاس خودداری کنید. eslint:
no-dupe-class-membersچرا؟ اعلانهای تکراری اعضای کلاس بیصدا آخرین مورد را ترجیح میدهند - تقریباً و مطمئناً داشتن موارد تکراری یک اشکال و باگ است.
// بد
class Foo {
bar() { return 1; }
bar() { return 2; }
}
// خوب
class Foo {
bar() { return 1; }
}
// خوب
class Foo {
bar() { return 2; }
}- 9.7 متدهای کلاس باید از
thisاستفاده کنند یا به یک روش ثابت تبدیل شوند، مگر اینکه یک کتابخانه یا چارچوب خارجی نیاز به استفاده از روشهای غیراستاتیک خاصی داشته باشد. یک روش نمونه بودن باید نشان دهد که بر اساس ویژگی های گیرنده رفتار متفاوتی دارد.
eslint:class-methods-use-this
// بد
class Foo {
bar() {
console.log('bar');
}
}
// خوب - این استفاده می شود
class Foo {
bar() {
console.log(this.bar);
}
}
// خوب - سازنده معاف است
class Foo {
constructor() {
// ...
}
}
// خوب - انتظار نمی رود روش های استاتیک از این استفاده کنند
class Foo {
static bar() {
console.log('bar');
}
}-
10.1 همیشه از ماژول ها (
import/export) روی یک سیستم ماژول غیر استاندارد استفاده کنید. شما همیشه می توانید به سیستم ماژول دلخواه خود انتقال دهید.چرا؟ ماژول ها آینده هستند، از همین حالا از آینده استفاده کنید.
// بد
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// بد
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// بهترین
import { es6 } from './AirbnbStyleGuide';
export default es6;-
10.2 از واردات عام استفاده نکنید.
چرا؟ این اطمینان حاصل می کند که یک
export defaultدارید.
// بد
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// خوب
import AirbnbStyleGuide from './AirbnbStyleGuide';-
10.3 و مستقیماً از واردات، صادر نکنید.
چرا؟ اگرچه خط یک خط مختصر است، اما داشتن یک راه واضح برای واردات و یک راه مشخص برای صادرات، همه چیز را منسجمتر می کند.
// بد
// نام فایل es6.js
export { es6 as default } from './AirbnbStyleGuide';
// خوب
// نام فایل es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;- 10.4 فقط از یک مسیر در یک مکان وارد کنید.
eslint:
no-duplicate-importsچرا؟ داشتن چندین خط که از یک مسیر وارد می شوند، می تواند حفظ کد را سخت تر کند.
// بد
import foo from 'foo';
// … برخی دیگر از واردات … //
import { named1, named2 } from 'foo';
// خوب
import foo, { named1, named2 } from 'foo';
// خوب
import foo, {
named1,
named2,
} from 'foo';- 10.5 پیوندهای قابل تغییر صادر نکنید.
eslint:
import/no-mutable-exportsچرا؟ باید از mutation به طور کلی اجتناب شود، اما به طور خاص هنگام صادرات اتصالات قابل تغییر، در حالی که ممکن است این تکنیک برای برخی موارد خاص مورد نیاز باشد، به طور کلی، فقط مراجع ثابت باید صادر شوند.
// بد
let foo = 3;
export { foo };
// خوب
const foo = 3;
export { foo };- 10.6 در ماژولهایی با یک صادرات، صادرات پیشفرض را به صادرات نامگذاری شده ترجیح دهید.
eslint:
import/prefer-default-exportچرا؟ برای تشویق فایل های بیشتری که فقط یک چیز را صادر می کنند، که برای خوانایی و نگهداری بهتر است.
// بد
export function foo() {}
// خوب
export default function foo() {}- 10.7 همه
importها را بالای عبارات غیروارداتی قرار دهید. eslint:import/firstچرا؟ از آنجایی که
importها بالا میروند، نگه داشتن همه آنها در بالا از رفتار غیر منتظرانه کد جلوگیری میکند.
// بد
import foo from 'foo';
foo.init();
import bar from 'bar';
// خوب
import foo from 'foo';
import bar from 'bar';
foo.init();-
10.8 واردات چند خطی باید درست مانند آرایه های چند خطی و متغییر شیء ها دارای تورفتگی باشد. eslint:
object-curly-newlineچرا؟ کرلی بریس ها ( { ) از همان قوانین تورفتگی مانند هر بلوک کرلی بریس های دیگر در راهنمای سبک پیروی میکنند، مانند کاماهای انتهایی.
// بد
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
// خوب
import {
longNameA,
longNameB,
longNameC,
longNameD,
longNameE,
} from 'path';- 10.9 دستور لودر Webpack را در دستورات وارد کردن ماژول مجاز نکنید.
eslint:
import/no-webpack-loader-syntaxچرا؟ از آنجایی که استفاده از سینتکس Webpack در واردات، کد را به یک بستهکننده ماژول جفت میکند. ترجیحاً از سینتکس لودر در
webpack.config.jsاستفاده کنید.
// بد
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';
// خوب
import fooSass from 'foo.scss';
import barCss from 'bar.css';- 10.10 پسوندهای نام فایل جاوا اسکریپت را درج نکنید
eslint:
import/extensionsچرا؟ گنجاندن پسوندها از بازآفرینی کد جلوگیری میکند و بهطور نامناسب جزئیات پیادهسازی ماژولی را که وارد میکنید در هر مصرفکنندهای را کدگذاری میکند.
// بد
import foo from './foo.js';
import bar from './bar.jsx';
import baz from './baz/index.jsx';
// خوب
import foo from './foo';
import bar from './bar';
import baz from './baz';-
11.1 از تکرار کننده ها استفاده نکنید توابع مرتبه بالاتر جاوا اسکریپت را به جای حلقه هایی مانند
for-inیاfor-ofترجیح دهید.
eslint:no-iteratorno-restricted-syntaxچرا؟ این قانون تغییر ناپذیری ما را اجرا می کند. پرداختن به توابع خالصی که مقادیر را برمی گرداند آسان تر از داشتن عوارض جانبی است.
از
()map()/every()/filter()/find()/findIndex()/reduce()/some/ ... برای تکرار روی آرایه ها استفاده کنید و از()Object.keys()/Object.values()/Object.entriesبرای تولید آرایهها تا بتوانید روی اشیادستوراتتان را تکرار کنید.
const numbers = [1, 2, 3, 4, 5];
// بد
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// خوب
let sum = 0;
numbers.forEach((num) => {
sum += num;
});
sum === 15;
// بهترین (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
// بد
const increasedByOne = [];
for (let i = 0; i <br numbers.length; i++) {
increasedByOne.push(numbers[i] + 1);
}
// خوب
const increasedByOne = [];
numbers.forEach((num) => {
increasedByOne.push(num + 1);
});
// بهترین (عملکردی نگه داشتن آن)
const increasedByOne = numbers.map((num) => num + 1);-
11.2 فعلا از ژنراتور استفاده نکنید.
چرا؟ آنها به خوبی به ES5 منتقل نمی شوند.
-
11.3 اگر باید از ژنراتورها استفاده کنید، یا اگر توصیه مارا نادیده میگیرید، مطمئن شوید که امضای عملکرد آنها به درستی فاصله دارد. eslint:
generator-star-spacingچرا؟
functionو*بخشی از یک کلمه کلیدی مفهومی هستند - "*" یک اصلاح کننده برایfunctionنیست،function*یک ساختار منحصر به فرد است، متفاوت ازfunction.
// بد
function * foo() {
// ...
}
// بد
const bar = function * () {
// ...
};
// بد
const baz = function *() {
// ...
};
// بد
const quux = function*() {
// ...
};
// بد
function*foo() {
// ...
}
// بد
function *foo() {
// ...
}
// خیلی بد
function
*
foo() {
// ...
}
// خیلی بد
const wat = function
*
() {
// ...
};
// خوب
function* foo() {
// ...
}
// خوب
const foo = function* () {
// ...
};- 12.1 هنگام دسترسی به ویژگی ها از نماد نقطه استفاده کنید. eslint:
dot-notation
const luke = {
jedi: true,
age: 28,
};
// بد
const isJedi = luke['jedi'];
// خوب
const isJedi = luke.jedi;- 12.2 هنگام دسترسی به خصوصیات با یک متغیر، از علامت براکت
[]استفاده کنید.
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');- 12.3 هنگام محاسبه توان از عملگر توانی
**استفاده کنید. eslint:no-restricted-properties.
// بد
const binary = Math.pow(2, 10);
// خوب
const binary = 2 ** 10;- 13.1 همیشه از
constیاletبرای اعلام متغیرها استفاده کنید. عدم انجام این کار باعث ایجاد متغیرهای سراسری می شود. ما می خواهیم از آلودگی فضای نام جهانی جلوگیری کنیم.جلوتر به شما در این مورد هشدار داده ایم.
eslint:no-undefprefer-const
// بد
superPower = new SuperPower();
// خوب
const superPower = new SuperPower();-
13.2 برای هر متغیر یا تخصیص از یک اعلان
constیاletاستفاده کنید. eslint:one-varچرا؟ اضافه کردن اعلانهای متغیر جدید از این طریق آسانتر است، و هرگز لازم نیست نگران تعویض یک
;با,یا معرفی تفاوتهای فقط نشانهگذاری باشید. همچنین میتوانید بهجای اینکه بهطور همزمان از همه آنها عبور کنید، با دیباگر از هر اعلان عبور کنید.
// بد
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// بد
// (با بالا مقایسه کنید و سعی کنید اشتباه را تشخیص دهید)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// خوب
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';-
13.3 همه
constهای خود را گروه بندی کنید و سپس همهletهای خود را گروه بندی کنید.چرا؟ این زمانی مفید است که بعداً ممکن است لازم باشد متغیری را بسته به یکی از متغیرهای قبلاً اختصاص داده شده تغییر دهید.
// بد
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// بد
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// خوب
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;-
13.4 متغیرها را در جایی که به آنها نیاز دارید اختصاص دهید، اما آنها را در مکانی معقول قرار دهید.
چرا؟
letوconstدارای محدوده بلوکی هستند و محدوده عملکردی ندارند.
// بد - فراخوانی غیر ضروری عملکرد
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// خوب
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}-
13.5 تعاریف متغیر ها را زنجیره ای نکنید. eslint:
no-multi-assignچرا؟ تخصیص متغیرهای زنجیره ای، متغیرهای جهانی ضمنی ایجاد می کند.
// بد
(function example() {
// جاوا اسکریپت این را چنین تفسیر می کند
// let a = ( b = ( c = 1 ) );
// کلمه کلیدی let فقط برای متغیر a کاربرد دارد. متغیرهای b و c تبدیل می شوند
// متغیرهای جهانی.
let a = b = c = 1;
}());
console.log(a); // خطای ReferenceError
console.log(b); // 1
console.log(c); // 1
// خوب
(function example() {
let a = 1;
let b = a;
let c = a;
}());
console.log(a); // خطای ReferenceError
console.log(b); // خطای ReferenceError
console.log(c); // خطای ReferenceError
// همین امر برای 'const' نیز صدق می کند-
13.6 از استفاده از افزایش و کاهش یکنواخت خودداری کنید (
++،--). eslintno-plusplusچرا؟ طبق مستندات Eslint، گزارههای افزایش و کاهش یکنواخت مشمول درج خودکار نقطه ویرگول هستند و میتوانند باعث خطاهای بیصدا با مقادیر افزایش یا کاهش در یک برنامه شوند. همچنین جهش دادن مقادیر خود با عباراتی مانند
num += 1به جایnum++یاnum ++گویاتر است. عدم اجازه دادن به گزارههای افزایش و کاهش یکنواخت همچنین مانع از افزایش/پیش کاهش مقادیر غیرعمدی میشود که میتواند باعث رفتار غیرمنتظره در برنامههای شما شود.
// بد
const array = [1, 2, 3];
let num = 1;
num++;
--num;
let sum = 0;
let truthyCount = 0;
for (let i = 0; i < array.length; i++) {
let value = array[i];
sum += value;
if (value) {
truthyCount++;
}
}
// خوب
const array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;
const sum = array.reduce((a, b) => a + b, 0);
const truthyCount = array.filter(Boolean).length;-
13.7 از شکستن خط قبل یا بعد از
=در تعریف یک متغیر اجتناب کنید. If your assignment violatesmax-len, مقدار را در پرانتز احاطه کنید. eslintoperator-linebreak.چرا؟ شکستن خط ها اطراف
=می تواند مقدار یک انتساب را مبهم کند.
// بد
const foo =
superLongLongLongLongLongLongLongLongFunctionName();
// بد
const foo
= 'superLongLongLongLongLongLongLongLongString';
// خوب
const foo = (
superLongLongLongLongLongLongLongLongFunctionName()
);
// خوب
const foo = 'superLongLongLongLongLongLongLongLongString';-
13.8 متغیرهای استفاده نشده را مجاز نکنید. eslint:
no-unused-varsچرا؟ متغیرهایی که اعلان می شوند و در هیچ کجای کد مورد استفاده قرار نمی گیرند، به احتمال زیاد یک خطای ناقص هستند. چنین متغیرهایی فضایی را در کد اشغال می کنند و می توانند منجر به سردرگمی خوانندگان شوند.
// بد
const some_unused_var = 42;
// متغیرهای فقط نوشتن به عنوان استفاده شده در نظر گرفته نمی شوند.
let y = 10;
y = 5;
// خواندن برای اصلاح خود به عنوان مورد استفاده در نظر گرفته نمی شود.
let z = 0;
z = z + 1;
// آرگومان های تابع استفاده نشده
function getX(x, y) {
return x;
}
// خوب
function getXPlusY(x, y) {
return x + y;
}
const x = 1;
const y = a + 2;
alert(getXPlusY(x, y));
// 'type' نادیده گرفته می شود، حتی اگر استفاده نشده باشد، زیرا دارای یک خواهر و برادر دارایی استراحت است.
// این شکلی از استخراج یک شیء است که کلیدهای مشخص شده را حذف می کند.
const { type, ...coords } = data;
// 'coords' اکنون شیء 'data' بدون خاصیت 'type' آن است.- 14.1 اعلانهای
varبه بالای نزدیکترین محدوده تابع محصورکننده خود بالا میروند، اما تخصیص آنها اینطور نیست. اعلانهایconstوletبا مفهوم جدیدی به نام Temporal Dead Zones (TDZ) همراه هستند، مهم است بدانیم چراtypeofایمن نیست.
// ما می دانیم که این کار نمی کند (با فرض وجود
// متغیر جهانی notDefined تعریف نشده است)
function example() {
console.log(notDefined); // => خطای ReferenceError
}
// ایجاد یک اعلان متغیر پس از ارجاع به متغیر به دلیل بالا بردن متغیر کار خواهد کرد.
// توجه: مقدار تخصیص `true` بالا نمی رود.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// مفسر در حال بالا بردن اعلان متغیر در بالای دامنه است،
// به این معنی که مثال ما می تواند به صورت زیر بازنویسی شود:
function example() {
let declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// استفاده از const و let
function example() {
console.log(declaredButNotAssigned); // => خطای ReferenceError
console.log(typeof declaredButNotAssigned); // => خطای ReferenceError
const declaredButNotAssigned = true;
}- 14.2 عبارات تابع ناشناس نام متغیر خود را بالا می برند، اما تخصیص تابع نه.
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous یک تابع نیست
var anonymous = function () {
console.log('anonymous function expression');
};
}- 14.3 عبارات تابع نامگذاری شده نام متغیر را بالا می برند، نه نام تابع یا بدنه تابع.
function example() {
console.log(named); // => undefined
named(); // => TypeError named یک تابع نیست
superPower(); // => ReferenceError superPower تعریف نشده است
var named = function superPower() {
console.log('Flying');
};
}
// زمانی که نام تابع با نام متغیر یکسان باشد، همین امر صادق است.
function example() {
console.log(named); // => undefined
named(); // => TypeError named یک تابع نیست
var named = function named() {
console.log('named');
};
}- 14.4 اعلان های تابع نام و بدنه عملکرد را بالا می برند.
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}- برای اطلاعات بیشتر به جاوا اسکریپت Scoping and Hoisting مراجعه کنید. توسط Ben Cherry.
-
15.2 عبارات شرطی مانند عبارت
ifبیان خود را با استفاده از اجبار با روش انتزاعیToBooleanارزیابی می کنند و همیشه از این قوانین ساده پیروی می کنند.: -
Objects میشود true
-
Undefined میشود false
-
Null میشود false
-
Booleans میشود مقدار boolean
-
Numbers میشود false اگر +0, -0, or NaN, در غیر این صورت true
-
Strings میشود false اگر یک رشته خالی
'', در غیر این صورت true
if ([0] && []) {
// true
// یک آرایه (حتی یک آرایه خالی) یک شیء است، اشیاء به درستی ارزیابی می شوند
}- 15.3 از میانبرها برای
Booleanها استفاده کنید، اما از مقایسه صریح برای رشته ها و اعداد استفاده کنید.
// بد
if (isValid === true) {
// ...
}
// خوب
if (isValid) {
// ...
}
// بد
if (name) {
// ...
}
// خوب
if (name !== '') {
// ...
}
// بد
if (collection.length) {
// ...
}
// خوب
if (collection.length > 0) {
// ...
}- 15.4 برای اطلاعات بیشتر به برابری حقیقت و جاوا اسکریپت مراجعه کنید. توسط Angus Croll.
-
15.5 ز پرانتزها برای ایجاد بلوکهایی در عبارتهای
caseوdefaultاستفاده کنید که حاوی اعلانهای لغوی هستند (مثلاًlet،const،functionوclass). eslint:no-case-declarationsچرا؟ سینتکس های واژگانی در کل بلوک سوئیچ قابل مشاهده هستند، اما فقط زمانی که تخصیص داده میشوند، مقداردهی اولیه میشوند، که تنها زمانی اتفاق میافتد که به
حرفآن برسد. زمانی که چندین بندموردسعی میکنند یک چیز را تعریف کنند، این مشکل ایجاد میکند.
// بد
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {
// ...
}
break;
default:
class C {}
}
// خوب
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {
// ...
}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}- 15.6 ترنری ها نباید تودرتو باشند و عموماً باید عبارت های تک خطی باشند. eslint:
no-nested-ternary
// بد
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// به 2 عبارت سه تایی جدا شده تقسیم می شود
const maybeNull = value1 > value2 ? 'baz' : null;
// بهتر
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// بهترین
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;- 15.7 از اظهارات سه تایی غیر ضروری خودداری کنید. eslint:
no-unneeded-ternary
// بد
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
const quux = a != null ? a : b;
// خوب
const foo = a || b;
const bar = !!c;
const baz = !c;
const quux = a ?? b;-
15.8 هنگام مخلوط کردن عملگرها، آنها را داخل پرانتز قرار دهید. تنها استثنا عملگرهای حسابی استاندارد هستند:
+،-، و**زیرا تقدم آنها به طور گسترده درک شده است. توصیه میکنیم/و*را در پرانتز قرار دهید زیرا اولویت آنها ممکن است زمانی که با هم مخلوط میشوند مبهم باشد. eslint:no-mixed-operatorsچرا؟ این خوانایی را بهبود می بخشد و قصد توسعه دهنده را روشن می کند.
// بد
const foo = a && b < 0 || c > 0 || d + 1 === 0;
// بد
const bar = a ** b - 5 % d;
// بد
// ممکن است فرد در فکر کردن گیج شود (a || b) && c
if (a || b && c) {
return d;
}
// بد
const bar = a + b / c * d;
// خوب
const foo = (a && b <br 0) || c > 0 || (d + 1 === 0);
// خوب
const bar = a ** b - (5 % d);
// خوب
if (a || (b && c)) {
return d;
}
// خوب
const bar = a + (b / c) * d;- 16.1 در تمام بلوک های چند خطی از بریس ها استفاده کنید. eslint:
nonblock-statement-body-position
// بد
if (test)
return false;
// خوب
if (test) return false;
// خوب
if (test) {
return false;
}
// بد
function foo() { return false; }
// خوب
function bar() {
return false;
}- 16.2 اگر از بلوکهای چند خطی با
ifوelseاستفاده میکنید،elseرا در همان خط مهاربند بسته شدن بلوکifخود قرار دهید. eslint:brace-style
// بد
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// خوب
if (test) {
thing1();
thing2();
} else {
thing3();
}- 16.3 اگر یک بلوک
ifهمیشه عبارتreturnرا اجرا میکند، بلوکelseبعدی ضروری نیست. یکبازگشتدر بلوکاگر دیگربه دنبال بلوکاگرکه حاویبازگشتاست، میتواند به بلوکهایاگرمتعدد جدا شود. eslint:no-else-return
// بد
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// بد
function cats() {
if (x) {
return x;
} else if (y) {
return y;
}
}
// بد
function dogs() {
if (x) {
return x;
} else {
if (y) {
return y;
}
}
}
// خوب
function foo() {
if (x) {
return x;
}
return y;
}
// خوب
function cats() {
if (x) {
return x;
}
if (y) {
return y;
}
}
// خوب
function dogs(x) {
if (x) {
if (z) {
return y;
}
} else {
return z;
}
}-
17.1 در صورتی که دستور کنترل شما (
if,whileو غیره) بیش از حد طولانی شود یا از حداکثر طول خط فراتر رود، هر شرط (گروهبندی شده) را میتوان در یک خط جدید قرار داد. عملگر منطقی باید خط را شروع کند.چرا؟ نیاز به عملگرها در ابتدای خط، عملگرها را در یک راستا نگه میدارد و از الگوی مشابه زنجیرهبندی متد پیروی میکند. این همچنین خوانایی را با تسهیل بصری پیروی از منطق پیچیده بهبود می بخشد.
// بد
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// بد
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// بد
if (foo === 123
&& bar === 'abc') {
thing1();
}
// بد
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// خوب
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// خوب
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// خوب
if (foo === 123 && bar === 'abc') {
thing1();
}- 17.2 از عملگرهای انتخاب به جای دستورات کنترلی استفاده نکنید.
// بد
!isRunning && startRunning();
// خوب
if (!isRunning) {
startRunning();
}- 18.1 برای نظرات چند خطی از
/** ... */استفاده کنید.
// بد
// make() یک عنصر جدید را بر اساس نام تگ ارسال شده برمی گرداند
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...
return element;
}
// خوب
/**
* make() یک عنصر جدید را بر اساس نام تگ ارسال شده برمی گرداند
*/
function make(tag) {
// ...
return element;
}- 18.2 برای نظرات تک خطی از
//استفاده کنید. نظرات تک خطی را در خط جدید بالای موضوع نظر قرار دهید. یک خط خالی قبل از نظر قرار دهید مگر اینکه در اولین خط یک بلوک باشد.
// بد
const active = true; // برگه فعلی است
// خوب
// برگه فعلی است
const active = true;
// بد
function getType() {
console.log('fetching type...');
// نوع پیش فرض روی 'no type'
const type = this.type || 'no type';
return type;
}
// خوب
function getType() {
console.log('fetching type...');
// نوع پیش فرض روی 'no type'
const type = this.type || 'no type';
return type;
}
// هچنان خوب
function getType() {
// نوع پیش فرض روی 'no type'
const type = this.type || 'no type';
return type;
}- 18.3 همه نظرات را با یک فاصله شروع کنید تا خواندن آن آسان تر شود. eslint:
spaced-comment
// بد
//is current tab
const active = true;
// خوب
// is current tab
const active = true;
// بد
/**
* make() یک عنصر جدید را بر اساس نام تگ ارسال شده برمی گرداند
*/
function make(tag) {
// ...
return element;
}
// خوب
/**
* make() یک عنصر جدید را بر اساس نام تگ ارسال شده برمی گرداند
*/
function make(tag) {
// ...
return element;
}- 18.4 قرار دادن پیشوند نظرات خود با
FIXMEیاTODOبه سایر برنامهنویسان کمک میکند تا به سرعت متوجه شوند که آیا به مشکلی اشاره میکنید که باید دوباره بررسی شود یا راهحلی برای مشکلی پیشنهاد میکنید که باید اجرا شود. اینها با نظرات معمولی متفاوت هستند زیرا قابل اجرا هستند. اقدامات عبارتند از:FIXME: -- need to figure this outorTODO: -- need to implement.
- 18.5 برای حاشیه نویسی مشکلات از
// FIXME:استفاده کنید.
class Calculator extends Abacus {
constructor() {
super();
// FIXME: در اینجا نباید از جهانی استفاده کرد
total = 0;
}
}- 18.6 از
// TODO:برای حاشیه نویسی راه حل های مشکلات استفاده کنید.
class Calculator extends Abacus {
constructor() {
super();
// TODO: total باید توسط یک پارامتر گزینه قابل تنظیم باشد
this.total = 0;
}
} // بد
function foo() {
∙∙∙∙let name;
}
// بد
function bar() {
∙let name;
}
// خوب
function baz() {
∙∙let name;
}- 19.2 1 فاصله قبل از بریس پیشرو قرار دهید. eslint:
space-before-blocks
// بد
function test(){
console.log('test');
}
// خوب
function test() {
console.log('test');
}
// بد
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// خوب
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});- 19.3 فاصله قبل از پرانتز آغازین در دستورات کنترل (
if،whileو غیره) قرار دهید. هیچ فاصله ای بین لیست آرگومان و نام تابع در فراخوانی ها و اعلان های تابع قرار ندهید. eslint:keyword-spacing
// بد
if(isJedi) {
fight ();
}
// خوب
if (isJedi) {
fight();
}
// بد
function fight () {
console.log ('Swooosh!');
}
// خوب
function fight() {
console.log('Swooosh!');
}- 19.4 عملگرها را با فاصله تنظیم کنید. eslint:
space-infix-ops
// بد
const x=y+5;
// خوب
const x = y + 5; // بد
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6; // بد
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵
↵ // خوب
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵- 19.6 هنگام ساخت زنجیرهای متد بلند (بیش از 2 زنجیره متد) از تورفتگی استفاده کنید. از یک نقطه پیشرو استفاده کنید که
تاکید می کند که خط یک فراخوانی متد است، نه یک دستور جدید.
eslint:newline-per-chained-callno-whitespace-before-property
// بد
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// بد
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// خوب
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// بد
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', `translate(${radius + margin}, ${radius + margin})`)
.call(tron.led);
// خوب
const leds = stage.selectAll('.led')
.data(data)
.enter().append('svg:svg')
.classed('led', true)
.attr('width', (radius + margin) * 2)
.append('svg:g')
.attr('transform', `translate(${radius + margin}, ${radius + margin})`)
.call(tron.led);
// خوب
const leds = stage.selectAll('.led').data(data);
const svg = leds.enter().append('svg:svg');
svg.classed('led', true).attr('width', (radius + margin) * 2);
const g = svg.append('svg:g');
g.attr('transform', `translate(${radius + margin}, ${radius + margin})`).call(tron.led);- 19.7 بعد از بلوک ها و قبل از عبارت بعدی یک خط خالی بگذارید.
// بد
if (foo) {
return bar;
}
return baz;
// خوب
if (foo) {
return bar;
}
return baz;
// بد
const obj = {
foo() {
},
bar() {
},
};
return obj;
// خوب
const obj = {
foo() {
},
bar() {
},
};
return obj;
// بد
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// خوب
const arr = [
function foo() {
},
function bar() {
},
];
return arr;- 19.8 بلوک های خود را با خطوط خالی پر نکنید. eslint:
padded-blocks
// بد
function bar() {
console.log(foo);
}
// بد
if (baz) {
console.log(quux);
} else {
console.log(foo);
}
// بد
class Foo {
constructor(bar) {
this.bar = bar;
}
}
// خوب
function bar() {
console.log(foo);
}
// خوب
if (baz) {
console.log(quux);
} else {
console.log(foo);
}-
19.9 برای اضافه کردن کد خود از چندین خط خالی استفاده نکنید. eslint:
no-multiple-empty-lines
// بد
class Person {
constructor(fullName, email, birthday) {
this.fullName = fullName;
this.email = email;
this.setAge(birthday);
}
setAge(birthday) {
const today = new Date();
const age = this.getAge(today, birthday);
this.age = age;
}
getAge(today, birthday) {
// ..
}
}
// خوب
class Person {
constructor(fullName, email, birthday) {
this.fullName = fullName;
this.email = email;
this.setAge(birthday);
}
setAge(birthday) {
const today = new Date();
const age = getAge(today, birthday);
this.age = age;
}
getAge(today, birthday) {
// ..
}
}- 19.10 داخل پرانتز فاصله اضافه نکنید. eslint:
space-in-parens
// بد
function bar( foo ) {
return foo;
}
// خوب
function bar(foo) {
return foo;
}
// بد
if ( foo ) {
console.log(foo);
}
// خوب
if (foo) {
console.log(foo);
}- 19.11 داخل براکت ها فاصله اضافه نکنید. eslint:
array-bracket-spacing
// بد
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// خوب
const foo = [1, 2, 3];
console.log(foo[0]);- 19.12 فضاهای داخل کرلی بریس ها را اضافه کنید. eslint:
object-curly-spacing
// بد
const foo = {clark: 'kent'};
// خوب
const foo = { clark: 'kent' };-
19.13 از داشتن خطوط کد بیشتر از 100 کاراکتر (شامل فضای خالی) خودداری کنید. توجه: در بالا، رشته های طولانی از این قانون مستثنی هستند و نباید شکسته شوند. eslint:
max-lenچرا؟ این خوانایی و قابلیت نگهداری را تضمین می کند.
// بد
const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
// بد
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// خوب
const foo = jsonData
&& jsonData.foo
&& jsonData.foo.bar
&& jsonData.foo.bar.baz
&& jsonData.foo.bar.baz.quux
&& jsonData.foo.bar.baz.quux.xyzzy;
// بهتر
const foo = jsonData
?.foo
?.bar
?.baz
?.quux
?.xyzzy;
// خوب
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));- 19.14 نیاز به فاصله ثابت در داخل یک نشانه بلوک باز و نشانه بعدی در همان خط است. این قانون همچنین فاصله ثابتی را در داخل یک نشانه بلوک نزدیک و توکن قبلی در همان خط اعمال می کند. eslint:
block-spacing
// بد
function foo() {return true;}
if (foo) { bar = 0;}
// خوب
function foo() { return true; }
if (foo) { bar = 0; }- 19.15 از فاصله قبل از کاما اجتناب کنید و نیاز به فاصله بعد از کاما دارید. eslint:
comma-spacing
// بد
const foo = 1,bar = 2;
const arr = [1 , 2];
// خوب
const foo = 1, bar = 2;
const arr = [1, 2];- 19.16 اعمال فاصله در داخل براکت های ویژگی محاسبه شده. eslint:
computed-property-spacing
// بد
obj[foo ]
obj[ 'foo']
const x = {[ b ]: a}
obj[foo[ bar ]]
// خوب
obj[foo]
obj['foo']
const x = { [b]: a }
obj[foo[bar]]- 19.17 از فاصله بین توابع و فراخوانی آنها اجتناب کنید. eslint:
func-call-spacing
// بد
func ();
func
();
// خوب
func();- 19.18 اعمال فاصله بین کلیدها و مقادیر در ویژگی های لغوی شیء. eslint:
key-spacing
// بد
const obj = { foo : 42 };
const obj2 = { foo:42 };
// خوب
const obj = { foo: 42 };- 19.19 از فضاهای انتهایی در انتهای خطوط خودداری کنید. eslint:
no-trailing-spaces
-
19.20 از چند خط خالی اجتناب کنید، فقط یک خط جدید در انتهای فایل ها مجاز کنید و از خط جدید در ابتدای فایل ها اجتناب کنید. eslint:
no-multiple-empty-lines
// بد - چندین خط خالی
const x = 1;
const y = 2;
// بد - 2+ خط جدید در انتهای فایل
const x = 1;
const y = 2;
// بد - 1+ خط(های) جدید در ابتدای فایل
const x = 1;
const y = 2;
// خوب
const x = 1;
const y = 2;- 20.1 ویرگول اول: جواب منفیست. eslint:
comma-style
// بد
const story = [
once
, upon
, aTime
];
// خوب
const story = [
once,
upon,
aTime,
];
// بد
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// خوب
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};-
20.2 کاما انتهایی اضافی: آره. eslint:
comma-dangleچرا؟ این منجر به تفاوت های تمیزتر در git می شود. همچنین، ترانسپایلرهایی مانند Babel، کامای انتهایی اضافی را در کد ترجمه شده حذف میکنند، به این معنی که شما لازم نیست نگران مشکل کامای انتهایی باشید در مرورگرهای قدیمی.
// بد - git diff بدون کاما انتهایی
const hero = {
firstName: 'Florence',
- lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing']
};
// خوب - git diff با کاما انتهایی
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
}; // بد
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// خوب
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
// بد
function createHero(
firstName,
lastName,
inventorOf
) {
// هیچ کاری نمی کند
}
// خوب
function createHero(
firstName,
lastName,
inventorOf,
) {
// هیچ کاری نمی کند
}
// خوب (توجه داشته باشید که کاما نباید بعد از عنصر "rest" ظاهر شود)
function createHero(
firstName,
lastName,
inventorOf,
...heroArgs
) {
// هیچ کاری نمی کند
}
// بد
createHero(
firstName,
lastName,
inventorOf
);
// خوب
createHero(
firstName,
lastName,
inventorOf,
);
// خوب (توجه داشته باشید که کاما نباید بعد از عنصر "rest" ظاهر شود)
createHero(
firstName,
lastName,
inventorOf,
...heroArgs
);-
چرا؟ هنگامی که جاوا اسکریپت با شکست خط بدون نقطه ویرگول مواجه می شود، از مجموعه قوانینی به نام درج خودکار نقطه ویرگول استفاده می کند تا تعیین کند که آیا باید یک خط منتهی در نظر گرفته شود یا خیر. آن خط را به عنوان پایان یک عبارت شکسته و (همانطور که از نام آن پیداست) قبل از خط شکستن یک نقطه ویرگول در کد خود قرار دهید، اگر چنین فکر می کند. با این حال، ASI حاوی چند رفتار غیرعادی است و اگر جاوا اسکریپت شکست خط شما را اشتباه تفسیر کند، کد شما خراب میشود. این قوانین با تبدیل شدن ویژگی های جدید به بخشی از جاوا اسکریپت پیچیده تر می شوند. خاتمه دادن صریح عبارات خود و پیکربندی لیتر خود برای گرفتن نقطه ویرگول های گم شده به شما کمک می کند تا با مشکلاتی مواجه نشوید.
// بد - استثناء ایجاد می کند
const luke = {}
const leia = {}
[luke, leia].forEach((jedi) => jedi.father = 'vader')
// بد - استثناء ایجاد می کند
const reaction = "No! That’s impossible!"
(async function meanwhileOnTheFalcon() {
// handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
// ...
}())
// بد - به جای مقدار خط بعدی، `undefined` را برمی گرداند - همیشه زمانی اتفاق می افتد که `return` به خودی خود به دلیل ASI روی یک خط باشد!
function foo() {
return
'search your feelings, you know it to be foo'
}
// خوب
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) => {
jedi.father = 'vader';
});
// خوب
const reaction = 'No! That’s impossible!';
(async function meanwhileOnTheFalcon() {
// رسیدگی به `leia`, `lando`, `chewie`, `r2`, `c3p0`
// ...
}());
// خوب
function foo() {
return 'search your feelings, you know it to be foo';
}- 22.1 اجبار نوع را در ابتدای بیانیه انجام دهید.
- 22.2 رشته ها: eslint:
no-new-wrappers
// => this.reviewScore = 9;
// بد
const totalScore = new String(this.reviewScore); // نوع totalScore "object" است نه "string"
// بد
const totalScore = this.reviewScore + ''; // فراخوانی می کند this.reviewScore.valueOf()
// بد
const totalScore = this.reviewScore.toString(); // تضمینی برای بازگرداندن یک رشته نیست
// خوب
const totalScore = String(this.reviewScore);-
22.3 اعداد: از
Numberبرای ریختن نوع و ازparseIntهمیشه با یک ریشه برای تجزیه رشته ها استفاده کنید. eslint:radixno-new-wrappersچرا؟ تابع 'parseInt' یک مقدار صحیح تولید می کند که توسط تفسیر محتویات آرگومان رشته با توجه به ریشه مشخص شده دیکته می شود. فضای سفید پیشرو در رشته نادیده گرفته می شود. اگر ریشه
undefinedیا0باشد،10در نظر گرفته میشود، به جز زمانی که عدد با جفتهای کاراکتر0xیا0Xشروع میشود، در این صورت، ریشه 16 در نظر گرفته میشود. این با ECMAScript 3 متفاوت است، که صرفاً تفسیر اکتالی را منع می کرد (اما مجاز می دانست). بسیاری از پیادهسازیها از سال 2013 این رفتار را اتخاذ نکردهاند. و چون مرورگرهای قدیمیتر باید پشتیبانی شوند، همیشه یک رادیکس مشخص کنید.
const inputValue = '4';
// بد
const val = new Number(inputValue);
// بد
const val = +inputValue;
// بد
const val = inputValue >> 0;
// بد
const val = parseInt(inputValue);
// خوب
const val = Number(inputValue);
// خوب
const val = parseInt(inputValue, 10);- 22.4 اگر به هر دلیلی در حال انجام کاری غرمعمول هستید و
parseIntتنگنای شماست و به دلیل دلایل عملکرد باید از Bitshift استفاده کنید، یک نظر بگذارید و توضیح دهید که چرا و چه کاری انجام می دهید.
// خوب
/**
* parseInt دلیل کند بودن کد من بود.
* Bitshifting رشته برای وادار کردن آن به یک عدد آن را بسیار سریعتر کرد.
*/
const val = inputValue >> 0;- 22.5 نکته: هنگام استفاده از عملیات bitshift مراقب باشید. اعداد به صورت مقادیر 64 بیتی نشان داده می شوند، اما عملیات bitshift همیشه یک عدد صحیح 32 بیتی (source). Bitshift می تواند منجر به رفتار غیرمنتظره برای مقادیر صحیح بزرگتر از 32 بیت شود. بحث. بزرگترین Int 32 بیتی امضا شده 2,147,483,647 است:
2147483647 >> 0; // => 2147483647
2147483648 >> 0; // => -2147483648
2147483649 >> 0; // => -2147483647- 22.6 بولی ها:(Booleans) eslint:
no-new-wrappers
const age = 0;
// بد
const hasAge = new Boolean(age);
// خوب
const hasAge = Boolean(age);
// بهترین
const hasAge = !!age; // بد
function q() {
// ...
}
// خوب
function query() {
// ...
} // بد
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// خوب
const thisIsMyObject = {};
function thisIsMyFunction() {} // بد
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// خوب
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});-
23.4 از زیرخط های انتهایی یا پیشرو استفاده نکنید. eslint:
no-underscore-dangleچرا؟ جاوا اسکریپت از نظر ویژگی ها یا روش ها مفهوم حریم خصوصی را ندارد. اگر چه یک زیرخط پیشرو یک قرارداد رایج به معنای “private” است، اما در واقع، این ویژگیها کاملاً عمومی هستند و به این ترتیب، بخشی از قرارداد عمومی API شما هستند. این قرارداد ممکن است باعث شود توسعه دهندگان به اشتباه فکر کنند که تغییر به عنوان شکستگی به حساب نمی آید، یا آزمایش هایی لازم نیست. کوتاه بگوییم: اگر میخواهید چیزی “private” باشد، نباید بهطور قابل مشاهده وجود داشته باشد.
// بد
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// خوب
this.firstName = 'Panda';
// خوب، در محیط هایی که WeakMaps در دسترس است
// مشاهده کنید در https://kangax.github.io/compat-table/es6/#test-WeakMap
const firstNames = new WeakMap();
firstNames.set(this, 'Panda');- 23.5 ارجاعات به
thisرا ذخیره نکنید. از توابع پیکان یا Function#bind استفاده کنید.
// بد
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// بد
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// خوب
function foo() {
return () => {
console.log(this);
};
}- 23.6 نام فایل پایه باید دقیقاً با نام
exportپیش فرض آن مطابقت داشته باشد.
// محتویات فایل 1
class CheckBox {
// ...
}
export default CheckBox;
// محتویات فایل 2
export default function fortyTwo() { return 42; }
// محتویات فایل 3
export default function insideDirectory() {}
// در یک فایل دیگر
// بد
import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
// بد
import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
import forty_two from './forty_two'; // snake_case import/filename, camelCase export
import inside_directory from './inside_directory'; // snake_case import, camelCase export
import index from './inside_directory/index'; // requiring the index file explicitly
import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
// خوب
import CheckBox from './CheckBox'; // PascalCase export/import/filename
import fortyTwo from './fortyTwo'; // camelCase export/import/filename
import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
// ^ از insideDirectory.js و insideDirectory/index.js پشتیبانی می کند- 23.7 هنگام صادرات-پیشفرض (export-default) یک تابع، از camelCase استفاده کنید. نام فایل شما باید با نام تابع شما یکسان باشد.
function makeStyleGuide() {
// ...
}
export default makeStyleGuide;- 23.8 هنگامی که یک سازنده / کلاس / تک تن / کتابخانه تابع / شیء خالی را صادر می کنید از PascalCase استفاده کنید.
const AirbnbStyleGuide = {
es6: {
},
};
export default AirbnbStyleGuide;-
23.9 حروف اختصاری و حروف اولیه باید همیشه با حروف بزرگ یا کوچک باشند.
چرا؟ نام ها برای خوانایی هستند، نه برای کمک کردن به مماشات یک الگوریتم رایانه ای.
// بد
import SmsContainer from './containers/SmsContainer';
// بد
const HttpRequests = [
// ...
];
// خوب
import SMSContainer from './containers/SMSContainer';
// خوب
const HTTPRequests = [
// ...
];
// هچنان خوب
const httpRequests = [
// ...
];
// بهترین
import TextMessageContainer from './containers/TextMessageContainer';
// بهترین
const requests = [
// ...
];-
23.10 شما می توانید به صورت اختیاری یک ثابت را با حروف بزرگ فقط در صورتی که (1) صادر شده باشد، (2) یک 'const' باشد (نمی توان آن را دوباره اختصاص داد)، و (3) برنامه نویس می تواند به آن (و خصوصیات تودرتوی آن) اعتماد کند تا هرگز تغییر نکند.
چرا؟ این یک ابزار اضافی برای کمک به شرایطی است که برنامه نویس مطمئن نیست که آیا متغیری ممکن است تغییر کند. UPPERCASE_VARIABLES به برنامه نویس اجازه می دهد بداند که می تواند به تغییر نکردن متغیر (و خصوصیات آن) اعتماد کند.
- در مورد همه متغیرهای 'const' چطور؟ - این غیر ضروری است، بنابراین نباید از حروف بزرگ برای ثابت های داخل یک فایل استفاده کرد. اما باید برای ثابت های صادر شده استفاده شود.
- در مورد اشیاء صادراتی چطور؟ - حروف بزرگ در سطح بالای صادرات (به عنوان مثال
EXPORTED_OBJECT.key) و حفظ کنید که همه ویژگیهای تودرتو تغییر نمیکنند.
// بد
const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
// بد
export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
// بد
export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
// ---
// مجاز است اما ارزش معنایی را ارائه نمی کند
export const apiKey = 'SOMEKEY';
// در بیشتر موارد بهتر است
export const API_KEY = 'SOMEKEY';
// ---
// بد - نیاز نبدون به حروف بزرگ کلید در حالی که هیچ ارزش معنایی اضافه نمی کند
export const MAPPING = {
KEY: 'value'
};
// خوب
export const MAPPING = {
key: 'value',
};- 24.1 توابع Accessor برای خواص مورد نیاز نیست.
- 24.2 از دریافت کننده/تنظیم کننده های جاوا اسکریپت استفاده نکنید زیرا باعث ایجاد عوارض جانبی غیرمنتظره می شوند و آزمایش، نگهداری و استدلال در مورد آنها سخت تر است. در عوض، اگر توابع دسترسی را ایجاد میکنید، از
()getValو("سلام")setValاستفاده کنید.
// بد
class Dragon {
get age() {
// ...
}
set age(value) {
// ...
}
}
// خوب
class Dragon {
getAge() {
// ...
}
setAge(value) {
// ...
}
}- 24.3 اگر ویژگی/متدی
booleanاست، از()isValیا()hasValاستفاده کنید.
// بد
if (!dragon.age()) {
return false;
}
// خوب
if (!dragon.hasAge()) {
return false;
}- 24.4 ایجاد توابع
()getو()setاشکالی ندارد، اما سازگار باشید.
class Jedi {
constructor(options = {}) {
const lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
set(key, val) {
this[key] = val;
}
get(key) {
return this[key];
}
}- 25.1 هنگام پیوست کردن محمولههای داده به رویدادها (چه رویدادهای DOM یا چیزهای اختصاصیتر مانند رویدادهای Backbone)، به جای مقدار خام، یک شیء را به صورت تحت اللفظی (همچنین به عنوان "hash" شناخته میشود) ارسال کنید. این به مشارکتکننده بعدی اجازه میدهد تا دادههای بیشتری را بدون یافتن و بهروزرسانی هر کنترلکننده رویداد به بار رویداد اضافه کند. به عنوان مثال، به جای:
// بد
$(this).trigger('listingUpdated', listing.id);
// ...
$(this).on('listingUpdated', (e, listingID) => {
// عملیاتی با listingID
});ترجیح بدهید:
// خوب
$(this).trigger('listingUpdated', { listingID: listing.id });
// ...
$(this).on('listingUpdated', (e, data) => {
// عملیاتی با data.listingID
});- 26.1 متغیرهای شیء jQuery را با یک
$پیشوند کنید.
// بد
const sidebar = $('.sidebar');
// خوب
const $sidebar = $('.sidebar');
// خوب
const $sidebarBtn = $('.sidebar-btn');- 26.2 جستجوهای jQuery را ذخیره کنید.
// بد
function setSidebar() {
$('.sidebar').hide();
// ...
$('.sidebar').css({
'background-color': 'pink',
});
}
// خوب
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...
$sidebar.css({
'background-color': 'pink',
});
}- 26.3 برای جستارهای DOM از
$('.sidebar ul')آبشاری یا والد > فرزند$('.sidebar > ul')استفاده کنید. jsPerf
- 26.4 از
findبا پرس و جوهای شیء jQuery با محدوده استفاده کنید.
// بد
$('ul', '.sidebar').hide();
// بد
$('.sidebar').find('ul').hide();
// خوب
$('.sidebar ul').hide();
// خوب
$('.sidebar > ul').hide();
// خوب
$sidebar.find('ul').hide();- 27.1 به Kangax ES5 جدول سازگاری مراجعه کنید.
- 28.1 این مجموعه ای از پیوندها به ویژگی های مختلف ES6+ است.
- توابع پیکانی
- کلاس ها
- مخفف شیء ها
- شیء مختصر
- ویژگی های محاسبه شده شیء
- رشته های الگویی
- استخراج کردن(destructuring)
- پارامترهای پیش فرض
- رست(Rest)
- گسترش آرایه
- متغییر های Let و Const
- اپراتور توان
- تکرار کننده ها و مولدها
- ماژول ها
-
28.2 از پیشنهادات TC39 که به مرحله 3 نرسیدهاند استفاده نکنید.
چرا؟ آنها نهایی نشده اند، و ممکن است تغییر کنند یا به طور کامل پس گرفته شوند. ما می خواهیم از جاوا اسکریپت استفاده کنیم و پیشنهادات هنوز جاوا اسکریپت نیستند.
کتابخانه استاندارد شامل ابزارهایی است که از نظر عملکردی خراب هستند اما به دلایل قدیمی باقی می مانند.
-
29.1 از
Number.isNaNبه جایisNaNجهانی استفاده کنید. eslint: 'no-restricted-globals'چرا؟
isNaNجهانی، غیر اعداد را به اعداد وادار میکند، و برای هر چیزی که به NaN وادار میشود،trueبرمیگردد. اگر این رفتار مورد نظر است، آن را به صراحت بیان کنید.
// بد
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// خوب
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true-
29.2 از
Number.isFiniteبه جایisFiniteسراسری استفاده کنید. eslint: 'no-restricted-globals'چرا؟
isFiniteسراسری، غیر اعداد را به اعداد وادار می کند، و برای هر چیزی که به یک عدد متناهی وادار می شود،trueبرمی گردد. اگر این رفتار مورد نظر است، آن را به صراحت بیان کنید.
// بد
isFinite('2e3'); // true
// خوب
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true- 30.1 آره.
function foo() {
return true;
}- 30.2 نه ولی جدی:
- از هر چارچوب تستی که استفاده می کنید، باید تست بنویسید!
- سعی کنید بسیاری از توابع خالص کوچک را بنویسید و مکان هایی که جهش ها رخ می دهند را به حداقل برسانید.
- در مورد موارد خرد و تمسخر محتاط باشید - آنها می توانند تست های شما را شکننده تر کنند.
- ما در اصل از
mochaوjestدر Airbnb استفاده می کنیم. 'tape' نیز گهگاه برای ماژول های کوچک و جداگانه استفاده می شود. - پوشش 100% آزمون هدف خوبی برای تلاش کردن است، حتی اگر رسیدن به آن همیشه عملی نباشد.
- هر زمان که اشکالی را برطرف کردید، یک تست رگرسیون بنویسید. باگ رفع شده بدون تست رگرسیون تقریباً مطمئناً در آینده دوباره از بین خواهد رفت.
- در مورد چیدمان و عملکرد وب
- رشته در مقابل Concat آرایه
- در یک حلقه امتحان کنید/دریافت کنید
- عملکرد انفجاری
- در jQuery Find vs Context, Selector
- اچ تی ام ال داحلی در مقابل محتوای متنی برای متن اسکریپت
- الحاق رشته بلند
- آیا توابع جاوا اسکریپتی مانند
()mapو()reduceو()filterبرای عبور از آرایه ها بهینه شده اند؟ - موضوعات جدید در حال بارگیری...
یادگیری ES6+
این را بخوانید
ابزارها
- لینترهای سبک کد
- ESlint - Airbnb Style .eslintrc
- JSHint - Airbnb Style .jshintrc
- پیش تنظیم نوترینو - @neutrinojs/airbnb
سایر راهنماهای سبک کد
- راهنمای سبک جاوا اسکریپت گوگل
- راهنمای سبک جاوا اسکریپت گوگل (قدیمی)
- دستورالعمل های سبک هسته جی کوئری
- اصول نوشتن جاوا اسکریپت سازگار و اصطلاحی
- استاندارد JS
سبک های دیگر
- نامگذاری این در توابع تو در تو - Christian Johansen
- تماس های مشروط - Ross Allen
- قراردادهای کدنویسی محبوب جاوا اسکریپت در GitHub - JeongHoon Byun
- چند عبارت var در جاوا اسکریپت، اضافی نیست - Ben Alman
بیشتر خواندن
- آشنایی با بسته شدن در جاوا اسکریپت - Angus Croll
- جاوا اسکریپت اولیه برای برنامه نویس بی حوصله - Dr. Axel Rauschmayer
- ممکن است به jQuery نیاز نداشته باشید - Zack Bloom & Adam Schwartz
- ویژگی های ES6 - Luke Hoban
- دستورالعمل های Frontend - Benjamin De Cock
کتاب ها
- جاوا اسکریپت: قسمت های خوب - Douglas Crockford
- الگوهای جاوا اسکریپت - Stoyan Stefanov
- الگوهای طراحی حرفه ای جاوا اسکریپت - Ross Harmes and Dustin Diaz
- وب سایت های با کارایی بالا: دانش ضروری برای مهندسان فرانت اند - Steve Souders
- جاوا اسکریپت قابل نگهداری - Nicholas C. Zakas
- برنامه های کاربردی وب جاوا اسکریپت - Alex MacCaw
- تکنیک های جاوا اسکریپت حرفه ای - John Resig
- جاوا اسکریپت همه جا :Smashing Node.js - Guillermo Rauch
- اسرار جاوا اسکریپت نینجا - John Resig and Bear Bibeault
- جاوا اسکریپت انسانی - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- جی اس بوک ها - Julien Bouquillon
- جاوا اسکریپت شخص ثالث - Ben Vinegar and Anton Kovalyov
- جاوا اسکریپت موثر: 68 روش خاص برای استفاده از قدرت جاوا اسکریپت - David Herman
- جاوا اسکریپت شیوا - Marijn Haverbeke
- شما JS: ES6 و فراتر از آن را نمی دانید - Kyle Simpson
وبلاگ ها
- هفته نامه جاوا اسکریپت
- جاوا اسکریپت، جاوا اسکریپت...
- وبلاگ Bocoup
- به اندازه کافی خوب است
- آنلاین NCZOn
- کمال می کشد
- بن المان
- دیمیتری بارانوفسکی
- توری
پادکست ها
این لیستی از سازمان هایی است که از این راهنمای سبک استفاده می کنند. یک درخواست pull برای ما ارسال کنید و ما شما را به لیست اضافه خواهیم کرد.
- 123erfasst: 123erfasst/javascript
- 4Catalyzer: 4Catalyzer/javascript
- Aan Zee: AanZee/javascript
- Airbnb: airbnb/javascript
- AloPeyk: AloPeyk
- AltSchool: AltSchool/javascript
- Apartmint: apartmint/javascript
- Ascribe: ascribe/javascript
- Avant: avantcredit/javascript
- Axept: axept/javascript
- Billabong: billabong/javascript
- Bisk: bisk
- Bonhomme: bonhommeparis/javascript
- Brainshark: brainshark/javascript
- CaseNine: CaseNine/javascript
- Cerner: Cerner
- Chartboost: ChartBoost/javascript-style-guide
- Coeur d'Alene Tribe: www.cdatribe-nsn.gov
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- DoSomething: DoSomething/eslint-config
- Digitpaint digitpaint/javascript
- Drupal: www.drupal.org
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- EvozonJs: evozonjs/javascript
- ExactTarget: ExactTarget/javascript
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia
- General Electric: GeneralElectric/javascript
- Generation Tux: GenerationTux/javascript
- GoodData: gooddata/gdc-js-style
- GreenChef: greenchef/javascript
- Grooveshark: grooveshark/javascript
- Grupo-Abraxas: Grupo-Abraxas/javascript
- Happeo: happeo/javascript
- Honey: honeyscience/javascript
- How About We: howaboutwe/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InterCity Group: intercitygroup/javascript-style-guide
- Jam3: Jam3/Javascript-Code-Conventions
- JSSolutions: JSSolutions/javascript
- Kaplan Komputing: kaplankomputing/javascript
- KickorStick: kickorstick
- Kinetica Solutions: kinetica/javascript
- LEINWAND: LEINWAND/javascript
- Lonely Planet: lonelyplanet/javascript
- M2GEN: M2GEN/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- Muber: muber
- National Geographic Society: natgeosociety
- NullDev: NullDevCo/JavaScript-Styleguide
- Nulogy: nulogy/javascript
- Orange Hill Development: orangehill/javascript
- Orion Health: orionhealth/javascript
- Peerby: Peerby/javascript
- Pier 1: Pier1/javascript
- Qotto: Qotto/javascript-style-guide
- React: reactjs.org/docs/how-to-contribute.html#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- Sainsbury’s Supermarkets: jsainsburyplc
- Shutterfly: shutterfly/javascript
- Sourcetoad: sourcetoad/javascript
- Springload: springload
- StratoDem Analytics: stratodem/javascript
- SteelKiwi Development: steelkiwi/javascript
- StudentSphere: studentsphere/javascript
- SwoopApp: swoopapp/javascript
- SysGarage: sysgarage/javascript-style-guide
- Syzygy Warsaw: syzygypl/javascript
- Target: target/javascript
- Terra: terra
- TheLadders: TheLadders/javascript
- The Nerdery: thenerdery/javascript-standards
- Tomify: tomprats
- Traitify: traitify/eslint-config-traitify
- T4R Technology: T4R-Technology/javascript
- UrbanSim: urbansim
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
این راهنمای سبک به زبان های دیگر نیز موجود است:
پرتغالی برزیل: armoucar/javascript-style-guide
بلغاری: borislavvv/javascript
کاتالان: fpmweb/javascript-style-guide
چینی ساده شده: lin-123/javascript
چینی (سنتی): jigsawye/javascript
فرانسوی: nmussy/javascript-style-guide
آلمانی: timofurrer/javascript-style-guide
ایتالیایی: sinkswim/javascript-style-guide
ژاپنی: mitsuruog/javascript-style-guide
کره ای: ParkSB/javascript-style-guide
روسی: leonidlebedev/javascript-airbnb
اسپانیایی: paolocarrasco/javascript-style-guide
تایلندی: lvarayut/javascript-style-guide
ترکی: eraycetinay/javascript
اوکراینی: ivanzusko/javascript
ویتنامی: dangkyokhoang/javascript-style-guide
- ما را در gitter پیدا کنید.
(مجوز MIT)
Copyright (c) 2012 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ما شما را تشویق می کنیم که این راهنما را fork کنید و قوانین را متناسب با راهنمای سبک تیم خود تغییر دهید. در زیر، ممکن است برخی از اصلاحات در راهنمای سبک را فهرست کنید. این به شما این امکان را می دهد که به طور دوره ای راهنمای سبک خود را بدون نیاز به مقابله با تضادهای ادغام به روز کنید.