مخزن اصلی: 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-template
template-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-paren
space-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-iterator
no-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-undef
prefer-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 out
orTODO: -- 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-call
no-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:radix
no-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
کنید و قوانین را متناسب با راهنمای سبک تیم خود تغییر دهید. در زیر، ممکن است برخی از اصلاحات در راهنمای سبک را فهرست کنید. این به شما این امکان را می دهد که به طور دوره ای راهنمای سبک خود را بدون نیاز به مقابله با تضادهای ادغام به روز کنید.