Photo by Pankaj Patel on Unsplash
دليل أسلوب Airbnb JavaScript()
نهج معقول للغة JavaScript.
أدلة أسلوب أخرى
مترجم من Airbnb JavaScript Style Guide.
الأنواع (Types)
- 1.1 الأنواع الأولية (Primitives): يمكنك الوصول إلى الأنواع الأولية مباشرة.
stringnumberbooleannullundefined
const foo = 1;
let bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
- 1.2 الأنواع المركبة (Complex): يمكنك الوصول إلى الأنواع المركبة عن طريق المرجع (by reference).
objectarrayfunction
const foo = [1, 2];
const bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
المراجع (References)
- 2.1 استخدم
constلكل مراجعك؛ وتجنب استخدامvar. eslint:prefer-const,no-const-assign
لماذا؟ هذا يضمن أنك لا تستطيع إعادة تعيين مراجعك، مما قد يؤدي إلى أخطاء وكود صعب الفهم.
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
- 2.2 إذا كنت بحاجة إلى إعادة تعيين المراجع، فاستخدم
letبدلاً منvar. eslint:no-varjscs:disallowVar
لماذا؟
letلها نطاق كتلة (block-scoped)، بينماvarلها نطاق دالة (function-scoped).
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
- 2.3 لاحظ أن
letوconstكلاهما ذو نطاق كتلة.
// const and let only exist in the blocks they are defined in.
{
let a = 1;
const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
الكائنات (Objects)
- 3.1 استخدم الصيغة الحرفية لإنشاء الكائنات. eslint rules:
no-new-object.
// bad
const item = new Object();
// good
const item = {};
- 3.2 لا تستخدم الكلمات المحجوزة كمفاتيح. لن يعمل هذا في IE8. المزيد من المعلومات. ومع ذلك، يمكن استخدامها في وحدات ES6 وكود الجانب الخادم. jscs:
disallowIdentifierNames
// bad
const superman = {
default: { clark: 'kent' },
private: true,
};
// good
const superman = {
defaults: { clark: 'kent' },
hidden: true,
};
- 3.3 استخدم مرادفات مقروءة بدلاً من الكلمات المحجوزة. jscs:
disallowIdentifierNames
// bad
const superman = {
class: 'alien',
};
// bad
const superman = {
klass: 'alien',
};
// good
const superman = {
type: 'alien',
};
- 3.4 استخدم أسماء الخصائص المحسوبة (computed property names) عند إنشاء كائنات بأسماء خصائص ديناميكية.
لماذا؟ تتيح لك تحديد جميع خصائص الكائن في مكان واحد.
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
- 3.5 استخدم الاختصار لأساليب الكائن (object method shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
- 3.6 استخدم الاختصار لقيم الخصائص (property value shorthand). eslint:
object-shorthandjscs:requireEnhancedObjectLiterals
لماذا؟ إنه أقصر وأكثر وصفاً.
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- 3.7 قم بتجميع اختصاراتك في بداية إعلان الكائن الخاص بك.
لماذا؟ من السهل معرفة الخصائص التي تستخدم الاختصار.
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
- 3.8 ضع علامات الاقتباس فقط حول الخصائص التي تعد معرفات غير صالحة. eslint:
quote-propsjscs:disallowQuotedKeysInObjects
لماذا؟ بشكل عام، نعتبر أنه من الأسهل قراءتها بشكل ذاتي. إنه يحسن تسليط الضوء على بناء الجملة، وهو أيضًا أسهل في التحسين بواسطة العديد من محركات JS.
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
المصفوفات (Arrays)
- 4.1 استخدم الصيغة الحرفية لإنشاء المصفوفات. eslint:
no-array-constructor
// bad
const items = new Array();
// good
const items = [];
- 4.2 استخدم Array#push بدلاً من التعيين المباشر لإضافة عناصر إلى مصفوفة.
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
- 4.3 استخدم انتشار المصفوفة
...لنسخ المصفوفات.
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
- 4.4 لتحويل كائن شبيه بالمصفوفة (array-like object) إلى مصفوفة، استخدم Array#from.
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
- 4.5 استخدم عبارات الإرجاع في عمليات الاسترجاعات لأساليب المصفوفة. لا بأس بحذف الإرجاع إذا كان نص الوظيفة يتكون من عبارة واحدة تتبع 8.2. eslint:
array-callback-return
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map(x => x + 1);
// bad
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = memo.concat(item);
});
// good
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
const flatten = memo.concat(item);
flat[index] = flatten;
return flatten;
});
// bad
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// good
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
التفكيك (Destructuring)
- 5.1 استخدم تفكيك الكائن عند الوصول واستخدام خصائص متعددة للكائن. jscs:
requireObjectDestructuring
لماذا؟ يوفر لك التفكيك إنشاء مراجع مؤقتة لتلك الخصائص.
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
- 5.2 استخدم تفكيك المصفوفة. jscs:
requireArrayDestructuring
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
- 5.3 استخدم تفكيك الكائن لقيم الإرجاع المتعددة، وليس تفكيك المصفوفة.
لماذا؟ يمكنك إضافة خصائص جديدة أو تغيير ترتيب الأشياء دون كسر مواقع الاستدعاء (call sites).
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, right } = processInput(input);
السلاسل النصية (Strings)
- 6.1 استخدم علامات اقتباس مفردة
''للسلاسل النصية. eslint:quotesjscs:validateQuoteMarks
// bad
const name = "Capt. Janeway";
// good
const name = 'Capt. Janeway';
- 6.2 لا يجب كتابة السلاسل النصية التي تزيد عن 100 حرف عبر أسطر متعددة باستخدام تسلسل السلاسل.
- 6.3 ملاحظة: إذا تم استخدامها بشكل مفرط، فإن السلاسل الطويلة ذات التسلسل يمكن أن تؤثر على الأداء. jsPerf & Discussion.
// bad
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.';
// bad
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.';
// good
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.4 عند بناء السلاسل النصية برمجياً، استخدم القوالب النصية (template strings) بدلاً من التسلسل. eslint:
prefer-templatetemplate-curly-spacingjscs:requireTemplateStrings
لماذا؟ تمنحك القوالب النصية صيغة مقروءة وموجزة مع ميزات الأسطر الجديدة واستيفاء السلاسل.
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// bad
function sayHi(name) {
return `How are you, ${ name }?`;
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
- 6.5 لا تستخدم
eval()على سلسلة نصية أبداً، فهي تفتح الكثير من الثغرات الأمنية.
الدوال (Functions)
- 7.1 استخدم إعلانات الدوال (function declarations) بدلاً من تعبيرات الدوال (function expressions). jscs:
requireFunctionDeclarations
لماذا؟ إعلانات الدوال مُسماة، لذا يسهل التعرف عليها في تتبع المكدس. بالإضافة إلى ذلك، يتم رفع (hoisted) إعلانات الدوال، بينما لا يتم رفع تعبيرات الدوال. تسمح هذه القاعدة لـ الدوال السهمية باستبدال تعبيرات الدوال بالكامل.
// bad
const foo = function () {
};
// good
function foo() {
}
- 7.2 تغليف التعبيرات الوظيفية المستدعاة فوراً (IIFE): eslint:
wrap-iifejscs:requireParenthesesAroundIIFE
لماذا؟ IIFE هي وحدة واحدة - تغليف كل من الدالة واستدعائها بين قوسين يوضح ذلك. لاحظ أنه في عالم به وحدات، لست بحاجة إلى IIFE تقريباً.
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
-
7.3 لا تعلن أبداً عن دالة في كتلة غير وظيفية (if، while، etc). قم بتعيين الدالة إلى متغير بدلاً من ذلك. ستسمح لك المتصفحات بالقيام بذلك، لكنهم جميعاً يفسرونها بشكل مختلف. eslint:
no-loop-func -
7.4 ملاحظة: يعرف ECMA-262
blockكقائمة من العبارات. إعلان الدالة ليس عبارة. اقرأ ملاحظة ECMA-262 حول هذه المشكلة.
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
let test;
if (currentUser) {
test = () => {
console.log('Yup.');
};
}
- 7.5 لا تسمي أبداً المعامل
arguments. سيؤدي هذا إلى سيطرة على كائنargumentsالذي يتم إعطاؤه لكل نطاق دالة.
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
- 7.6 لا تستخدم
argumentsأبداً، اختر صيغة الراحة...بدلاً من ذلك.prefer-rest-params
لماذا؟
...يوضح المعاملات التي تريد سحبها. بالإضافة إلى ذلك، فإن معاملات الراحة هي مصفوفة حقيقية، وليست مجرد شبيهة بالمصفوفة مثلarguments.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 7.7 استخدم صيغة المعاملات الافتراضية بدلاً من تغيير معاملات الدالة.
// really bad
function handleThings(opts) {
// No! We shouldn't mutate function arguments.
// Double bad: if opts is false it will be set to an object which may
// be what you want but it can cause subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- 7.8 تجنب الآثار الجانبية مع المعاملات الافتراضية.
لماذا؟ إنها محيرة للفهم.
var b = 1;
// bad
function count(a = b++) {
console.log(a);
}
count(); // 1
count(); // 2
count(3); // 3
count(); // 3
- 7.9 ضع المعاملات الافتراضية دائماً في النهاية.
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
- 7.10 لا تستخدم أبداً مُنشئ الوظيفة لإنشاء دالة جديدة.
لماذا؟ يؤدي إنشاء دالة بهذه الطريقة إلى تقييم سلسلة نصية مشابهة لـ eval()، مما يفتح ثغرات أمنية.
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
- 7.11 التباعد في توقيع الدالة.
لماذا؟ التناسق جيد، ولا يجب عليك إضافة أو إزالة مسافة عند إضافة أو إزالة اسم.
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
- 7.12 لا تقم أبداً بتغيير المعاملات. eslint:
no-param-reassign
لماذا؟ يمكن أن يتسبب التلاعب بالكائنات التي تم تمريرها كمعاملات في حدوث آثار جانبية غير مرغوب فيها في المستدعي الأصلي.
// bad
function f1(obj) {
obj.key = 1;
};
// good
function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
};
- 7.13 لا تقم أبداً بإعادة تعيين المعاملات. eslint:
no-param-reassign
لماذا؟ يمكن أن تؤدي إعادة تعيين المعاملات إلى سلوك غير متوقع، خاصة عند الوصول إلى كائن
arguments. يمكن أن يسبب أيضًا مشكلات في التحسين، خاصة في V8.
```javascript
// bad
function f1(a) {
a = 1;
}
function f2(a) {
if (!a) { a = 1; }
}
// good
function f3(a) {
const b = a || 1;
}
function f4(a = 1) {
}
```
الدوال السهمية (Arrow Functions)
- 8.1 عندما تحتاج إلى استخدام تعبير دالة (كما هو الحال عند تمرير دالة مجهولة)، استخدم تدوين الدالة السهمية. eslint:
prefer-arrow-callback,arrow-spacingjscs:requireArrowFunctions
لماذا؟ تنشئ نسخة من الدالة يتم تنفيذها في سياق
this، وهو ما تريده عادةً، وهي صيغة أكثر إيجازًا.
لماذا لا؟ إذا كان لديك دالة معقدة إلى حد ما، فقد تنقل هذا المنطق إلى إعلان دالة مسماة خاصة بها.
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.2 إذا كان نص الدالة يتكون من عبارة واحدة تُرجع تعبيرًا بدون آثار جانبية، فاحذف الأقواس واستخدم الإرجاع الضمني. بخلاف ذلك، احتفظ بالأقواس واستخدم عبارة
return. eslint:arrow-parens,arrow-body-stylejscs:disallowParenthesesAroundArrowParam,requireShorthandArrowFunctions
لماذا؟ التجميل النحوي (Syntactic sugar). يكون أكثر قابلية للقراءة عندما يتم تقييد وظائف متعددة معًا.
لماذا لا؟ إذا كنت تخطط لإرجاع كائن.
// bad
[1, 2, 3].map(number => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map(number => `A string containing the ${number}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
- 8.3 إذا امتد التعبير لأسطر متعددة، فقم بلفه بين قوسين لسهولة القراءة بشكل أفضل.
لماذا؟ يوضح بوضوح أين تبدأ الدالة وأين تنتهي.
// bad
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
`${number} became much longer. So we needed to break it over multiple ` +
'lines.'
);
// good
[1, 2, 3].map(number => (
`As time went by, the string containing the ${number} became much ` +
'longer. So we needed to break it over multiple lines.'
));
- 8.4 إذا كانت وظيفتك تأخذ وسيطة واحدة ولا تستخدم الأقواس، فاحذف الأقواس. بخلاف ذلك، قم دائمًا بتضمين الأقواس حول الوسائط. eslint:
arrow-parensjscs:disallowParenthesesAroundArrowParam
لماذا؟ فوضى بصرية أقل.
// bad
[1, 2, 3].map((x) => x * x);
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we’ve broken it ` +
'over multiple lines!'
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 8.5 تجنب الخلط بين بناء جملة الدالة السهمية (
=>) ومشغلات المقارنة (<=،>=). eslint:no-confusing-arrow
// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; }
المنشئون (Constructors)
- 9.1 استخدم دائمًا
class. تجنب التلاعب بـprototypeمباشرة.
لماذا؟ بناء جملة
classأكثر إيجازًا وأسهل في التفكير فيه.
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
- 9.2 استخدم
extendsللوراثة.
لماذا؟ إنها طريقة مدمجة لوراثة وظيفة النموذج الأولي دون كسر
instanceof.
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this._queue[0];
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
- 9.3 يمكن للطرق إرجاع
thisللمساعدة في تسلسل الطرق (method chaining).
// bad
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
// good
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 الفئات لديها منشئ افتراضي إذا لم يتم تحديده. منشئ فارغ أو منشئ يفوض فقط إلى فئة أصل غير ضروري.
no-useless-constructor
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
الوحدات (Modules)
- 10.1 استخدم دائمًا الوحدات (
import/export) عبر نظام وحدات غير قياسي. يمكنك دائمًا التحويل إلى نظام الوحدات المفضل لديك.
لماذا؟ الوحدات هي المستقبل، دعونا نبدأ في استخدام المستقبل الآن.
// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
- 10.2 لا تستخدم استيرادات البدل (wildcard imports).
لماذا؟ هذا يضمن أن لديك تصدير افتراضي واحد.
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
- 10.3 ولا تصدر مباشرة من الاستيراد.
لماذا؟ على الرغم من أن الكتابة في سطر واحد موجزة، فإن وجود طريقة واضحة للاستيراد وطريقة واضحة للتصدير يجعل الأمور متسقة.
// bad
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
المكررات والمولدات (Iterators and Generators)
- 11.1 لا تستخدم المكررات. فضل وظائف JavaScript ذات الترتيب العالي مثل
map()وreduce()بدلاً من الحلقات مثلfor-of. eslint:no-iterator
لماذا؟ هذا يفرض قاعدة اللامتبدل لدينا. التعامل مع الوظائف النقية التي تُرجع قيمًا أسهل في التفكير من الآثار الجانبية.
eslint rules: no-iterator.
const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach(num => sum += num);
sum === 15;
// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
- 11.2 لا تستخدم المولدات في الوقت الحالي.
لماذا؟ إنها لا تتحول بشكل جيد إلى ES5 حتى الآن.
الخصائص (Properties)
- 12.1 استخدم تدوين النقطة (dot notation) عند الوصول إلى الخصائص. eslint:
dot-notationjscs:requireDotNotation
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
- 12.2 استخدم تدوين الأقواس
[]عند الوصول إلى الخصائص باستخدام متغير.
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
المتغيرات (Variables)
- 13.1 استخدم دائمًا
constأوletلتعريف المتغيرات. عدم القيام بذلك سيؤدي إلى متغيرات عامة. نريد تجنب تلويث مساحة الاسم العالمية. حذرنا كابتن بلانيت من ذلك.
// bad
superPower = new SuperPower();
// good
const superPower = new SuperPower();
- 13.2 استخدم تعريف
constأوletواحد لكل متغير. eslint:one-varjscs:disallowMultipleVarDecl
لماذا؟ من الأسهل إضافة إعلانات متغيرات جديدة بهذه الطريقة، ولن تقلق أبدًا بشأن استبدال
;بـ,أو إدخال اختلافات علامات الترقيم فقط.
// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, notice the error)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
- 13.3 قم بتجميع كل
constثم كلlet.
لماذا؟ هذا مفيد عندما تحتاج لاحقًا إلى تعيين متغير اعتمادًا على أحد المتغيرات المعينة سابقًا.
// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
- 13.4 قم بتعيين المتغيرات حيث تحتاجها، ولكن ضعها في مكان معقول.
لماذا؟
letوconstهما في نطاق الكتلة (block scoped) وليسا في نطاق الدالة (function scoped).
// bad - unnecessary function call
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// good
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
الرفع (Hoisting)
- 14.1 يتم رفع إعلانات
varإلى قمة نطاقها، لكن تعيينها لا يتم رفعه. تُبارك إعلاناتconstوletبمفهوم جديد يسمى المناطق الميتة المؤقتة (TDZ). من المهم معرفة سبب أن نوع typeof لم يعد آمنًا.
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// The interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
let declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// using const and let
function example() {
console.log(declaredButNotAssigned); // => throws a ReferenceError
console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
const declaredButNotAssigned = true;
}
- 14.2 تعبيرات الدوال المجهولة ترفع اسم المتغير الخاص بها، ولكن ليس تعيين الدالة.
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
- 14.3 تعبيرات الدوال المسماة ترفع اسم المتغير، وليس اسم الدالة أو نص الدالة.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
}
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
}
}
- 14.4 ترفع إعلانات الدوال اسمها ونص الدالة.
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
- لمزيد من المعلومات، راجع JavaScript Scoping & Hoisting بواسطة Ben Cherry.
مشغلات المقارنة والمساواة (Comparison Operators & Equality)
-
15.2 تقوم العبارات الشرطية مثل
ifبتقييم تعبيرها باستخدام الإكراه باستخدام طريقةToBooleanالمجردة وتتبع دائمًا هذه القواعد البسيطة:
- Objects يتم تقييمها إلى true
- Undefined يتم تقييمها إلى false
- Null يتم تقييمها إلى false
- Booleans يتم تقييمها إلى قيمة البوليان
- Numbers يتم تقييمها إلى false إذا كانت +0، -0، أو NaN، وإلا true
- Strings يتم تقييمها إلى false إذا كانت سلسلة فارغة
''، وإلا true
if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}
- 15.3 استخدم الاختصارات.
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
- 15.4 لمزيد من المعلومات، راجع Truth Equality and JavaScript بواسطة Angus Croll.
- 15.5 استخدم الأقواس لإنشاء كتل في عبارات
caseوdefaultالتي تحتوي على إعلانات معجمية (مثلletوconstوfunctionوclass).
لماذا؟ الإعلانات المعجمية مرئية في كتلة التبديل بأكملها ولكن يتم تهيئتها فقط عند تعيينها، والذي يحدث فقط عندما يتم الوصول إلى
caseالخاص بها. يسبب هذا مشاكل عند محاولة عباراتcaseمتعددة تعريف نفس الشيء.
eslint rules: no-case-declarations.
// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {}
break;
default:
class C {}
}
// good
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.7 لا يجب تداخل المشغلات الثلاثية ويجب أن تكون عمومًا تعبيرات سطر واحد.
eslint rules: no-nested-ternary.
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// better
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
- 15.8 تجنب العبارات الثلاثية غير الضرورية.
eslint rules: no-unneeded-ternary.
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
الكتل (Blocks)
- 16.1 استخدم الأقواس مع جميع الكتل متعددة الأسطر.
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
- 16.2 إذا كنت تستخدم كتل متعددة الأسطر مع
ifوelse، ضعelseفي نفس السطر مع قوس الإغلاق الخاص بكتلةif. eslint:brace-stylejscs:disallowNewlineBeforeBlockStatements
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
عبارات التحكم (Control Statements)
- 17.1 في حالة أن عبارة التحكم الخاصة بك (
if,whileetc.) تصبح طويلة جدًا أو تتجاوز الحد الأقصى لطول السطر، يمكن وضع كل شرط (مجمع) في سطر جديد. يجب أن يبدأ المشغل المنطقي السطر.
لماذا؟ يؤدي طلب المشغلين في بداية السطر إلى إبقاء المشغلين محاذاة واتباع نمط مشابه لتسلسل الطريقة. هذا يحسن أيضًا إمكانية القراءة من خلال تسهيل متابعة المنطق المعقد بصريًا.
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// bad
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
- 17.2 لا تستخدم مشغلات التحديد بدلاً من عبارات التحكم.
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
التعليقات (Comments)
- 18.1 استخدم
/** ... */للتعليقات متعددة الأسطر. قم بتضمين وصف ومواصفات للأنواع والقيم لجميع المعلمات وقيم الإرجاع.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
* make() returns a new element
* based on the passed in tag name
*
* @param {String} tag
* @return {Element} element
*/
function make(tag) {
// ...stuff...
return element;
}
- 18.2 استخدم
//للتعليقات ذات السطر الواحد. ضع تعليقات السطر الواحد في سطر جديد أعلى موضوع التعليق. ضع سطرًا فارغًا قبل التعليق، ما لم يكن في السطر الأول من الكتلة.
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this._type || 'no type';
return type;
}
-
18.3 يساعد البدء بـ
FIXMEأوTODOفي تعليقاتك المطورين الآخرين على فهم سريع ما إذا كنت تشير إلى مشكلة تحتاج إلى إعادة النظر فيها أو إذا كنت تقترح حلاً يحتاج إلى التنفيذ. هذه تختلف عن التعليقات العادية لأنها قابلة للتنفيذ. الإجراءات هيFIXME: -- need to figure this outأوTODO: -- need to implement. -
18.4 استخدم
// FIXME:للتعليق على المشاكل.
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
- 18.5 استخدم
// TODO:للتعليق على حلول للمشاكل.
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
المسافة البيضاء (Whitespace)
- 19.1 استخدم علامات التبويب اللينة (مسافات) مضبوطة على مسافتين. eslint:
indentjscs:validateIndentation
// bad
function foo() {
∙∙∙∙const name;
}
// bad
function bar() {
∙const name;
}
// good
function baz() {
∙∙const name;
}
- 19.2 ضع مسافة واحدة قبل القوس المفتوح. eslint:
space-before-blocksjscs:requireSpaceBeforeBlockStatements
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});
- 19.3 ضع مسافة واحدة قبل القوس المفتوح في عبارات التحكم (
if,whileetc.). لا تضع مسافة بين قائمة الوسائط واسم الدالة في استدعاءات وإعلانات الدوال. eslint:space-after-keywords,space-before-keywordsjscs:requireSpaceAfterKeywords
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
- 19.4 افصل المشغلات بمسافات. eslint:
space-infix-opsjscs:requireSpaceBeforeBinaryOperators,requireSpaceAfterBinaryOperators
// bad
const x=y+5;
// good
const x = y + 5;
- 19.5 قم بإنهاء الملفات بسطر جديد واحد.
// bad
(function (global) {
// ...stuff...
})(this);
// bad
(function (global) {
// ...stuff...
})(this);↵
↵
// good
(function (global) {
// ...stuff...
})(this);↵
- 19.6 استخدم المسافة البادئة عند تسلسل الطرق الطويلة (أكثر من طريقتين). استخدم نقطة رائدة للتأكيد على أن السطر هو استدعاء طريقة، وليس عبارة جديدة. eslint:
newline-per-chained-callno-whitespace-before-property
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
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);
// good
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);
// good
const leds = stage.selectAll('.led').data(data);
- 19.7 اترك سطرًا فارغًا بعد الكتل وقبل العبارة التالية. jscs:
requirePaddingNewLinesAfterBlocks
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
// bad
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// good
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
- 19.8 لا تملأ كتلتك بأسطر فارغة. eslint:
padded-blocksjscs:disallowPaddingNewlinesInBlocks
// bad
function bar() {
console.log(foo);
}
// also bad
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
- 19.9 لا تضف مسافات داخل الأقواس. eslint:
space-in-parensjscs:disallowSpacesInsideParentheses
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
- 19.10 لا تضف مسافات داخل الأقواس المربعة. eslint:
array-bracket-spacingjscs:disallowSpacesInsideArrayBrackets
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
- 19.11 أضف مسافات داخل الأقواس المعقوفة. eslint:
object-curly-spacingjscs: [disallowSpacesInsideObjectBrackets](http://jscs.info/rule/
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
- 19.12 تجنب الأسطر التي يزيد طولها عن 100 حرف (بما في ذلك المسافات). eslint:
max-lenjscs:maximumLineLength
لماذا؟ هذا يضمن القراءة والصيانة.
// bad
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';
// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// good
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
'Whatever wizard constrains a helpful ally. The counterpart ascends!';
// good
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));
الفواصل (Commas)
- 20.1 الفواصل البادئة (Leading commas): لا. eslint:
comma-stylejscs:requireCommaBeforeLineBreak
// bad
const story = [
once
, upon
, aTime
];
// good
const story = [
once,
upon,
aTime,
];
// bad
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// good
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};
- 20.2 فاصلة زائدة إضافية (Additional trailing comma): نعم. eslint:
comma-danglejscs:requireTrailingComma
لماذا؟ يؤدي هذا إلى اختلافات git أنظف. أيضًا، ستزيل المحولات مثل Babel الفاصلة الزائدة الإضافية في الكود المحول، مما يعني أنك لست مضطرًا للقلق بشأن مشكلة الفاصلة الزائدة في المتصفحات القديمة.
// bad - git diff without trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb graph', 'modern nursing']
};
// good - git diff with trailing comma
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
};
// bad
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
الفواصل المنقوطة (Semicolons)
- 21.1 نعم. eslint:
semijscs:requireSemicolons
// bad
(function () {
const name = 'Skywalker'
return name
})()
// good
(() => {
const name = 'Skywalker';
return name;
}());
// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(() => {
const name = 'Skywalker';
return name;
}());
تحويل النوع والإكراه (Type Casting & Coercion)
// => this.reviewScore = 9;
// bad
const totalScore = this.reviewScore + '';
// good
const totalScore = String(this.reviewScore);
- 22.3 الأرقام: استخدم
Numberلتحويل النوع وparseIntدائمًا مع أساس لتحليل السلاسل النصية. eslint:radix
const inputValue = '4';
// bad
const val = new Number(inputValue);
// bad
const val = +inputValue;
// bad
const val = inputValue >> 0;
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
- 22.4 إذا كنت لسبب ما تفعل شيئًا مجنونًا وكان
parseIntهو عنق الزجاجة لديك وتحتاج إلى استخدام Bitshift لأسباب تتعلق بـ الأداء، فاترك تعليقًا يشرح سبب وما تفعله.
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
const val = inputValue >> 0;
- 22.5 ملاحظة: كن حذرًا عند استخدام عمليات bitshift. يتم تمثيل الأرقام كـ قيم 64 بت، لكن عمليات bitshift تُرجع دائمًا عددًا صحيحًا 32 بت (المصدر). يمكن أن يؤدي Bitshift إلى سلوك غير متوقع لقيم عدد صحيح أكبر من 32 بت. مناقشة. أكبر عدد صحيح موقع 32 بت هو 2,147,483,647:
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
- 22.6 القيم المنطقية:
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// good
const hasAge = !!age;
اتفاقيات التسمية (Naming Conventions)
- 23.1 تجنب الأسماء ذات الحرف الواحد. كن وصفيًا مع تسميتك.
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
- 23.2 استخدم camelCase عند تسمية الكائنات والدوال والمثيلات. eslint:
camelcasejscs:requireCamelCaseOrUpperCaseIdentifiers
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
- 23.3 استخدم PascalCase فقط عند تسمية المنشئات أو الفئات. eslint:
new-capjscs:requireCapitalizedConstructors
// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
});
- 23.4 استخدم شرطة سفلية رائدة
_عند تسمية الخصائص الخاصة. eslint:no-underscore-danglejscs:disallowDanglingUnderscores
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
- 23.5 لا تخزن المراجع إلى
this. استخدم الدوال السهمية أو Function#bind. jscs:disallowNodeTypes
// bad
function foo() {
const self = this;
return function () {
console.log(self);
};
}
// bad
function foo() {
const that = this;
return function () {
console.log(that);
};
}
// good
function foo() {
return () => {
console.log(this);
};
}
- 23.6 إذا كان ملفك يصدر فئة واحدة، فيجب أن يتطابق اسم ملفك تمامًا مع اسم فئتك.
// file contents
class CheckBox {
// ...
}
export default CheckBox;
// in some other file
// bad
import CheckBox from './checkBox';
// bad
import CheckBox from './check_box';
// good
import CheckBox from './CheckBox';
- 23.7 استخدم camelCase عند تصدير دالة كافتراضي. يجب أن يكون اسم ملفك مطابقًا لاسم الدالة الخاصة بك.
function makeStyleGuide() {
}
export default makeStyleGuide;
- 23.8 استخدم PascalCase عند تصدير كائن فردي / مكتبة دوال / كائن فارغ.
const AirbnbStyleGuide = {
es6: {
}
};
export default AirbnbStyleGuide;
الموصلات (Accessors)
- 24.1 وظائف الموصل للممتلكات ليست مطلوبة.
- 24.2 لا تستخدم JavaScript getters/setters لأنها تسبب آثارًا جانبية غير متوقعة ويصعب اختبارها وصيانتها والتفكير فيها. بدلاً من ذلك، إذا قمت بإنشاء وظائف موصل، فاستخدم getVal() و setVal(‘hello’).
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
- 24.3 إذا كانت الخاصية منطقية، فاستخدم
isVal()أوhasVal().
// bad
if (!dragon.age()) {
return false;
}
// good
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];
}
}
الأحداث (Events)
- 25.1 عند إرفاق حمولات البيانات بالأحداث (سواء كانت أحداث DOM أو شيء أكثر ملكية مثل أحداث Backbone)، مرر تججزئة بدلاً من قيمة خام. يتيح ذلك للمساهم اللاحق إضافة المزيد من البيانات إلى حمولة الحدث دون إيجاد وتحديث كل معالج للحدث. على سبيل المثال، بدلاً من:
// bad
$(this).trigger('listingUpdated', listing.id);
...
$(this).on('listingUpdated', (e, listingId) => {
// do something with listingId
});
فضل:
// good
$(this).trigger('listingUpdated', { listingId: listing.id });
...
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingId
});
jQuery
- 26.1 بادئة كائنات jQuery بـ
$. jscs:requireDollarBeforejQueryAssignment
// bad
const sidebar = $('.sidebar');
// good
const $sidebar = $('.sidebar');
// good
const $sidebarBtn = $('.sidebar-btn');
- 26.2 تخزين عمليات بحث jQuery مؤقتًا.
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
const $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
- 26.3 لاستعلامات DOM، استخدم Cascading
$('.sidebar ul')أو parent > child$('.sidebar > ul'). jsPerf - 26.4 استخدم
findمع استعلامات كائن jQuery ذات النطاق.
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
توافق ECMAScript 5 (ECMAScript 5 Compatibility)
- 27.1 ارجع إلى Kangax’s ES5 compatibility table.
أنماط ECMAScript 6 (ECMAScript 6 Styles)
- 28.1 هذه مجموعة من الروابط لميزات ES6 المختلفة.
- Arrow Functions
- Classes
- Object Shorthand
- Object Concise
- Computed Object Properties
- Template Strings
- Destructuring
- Default Parameters
- Rest
- Array Spreads
- Let and Const
- Iterators and Generators
- Modules
المكتبة القياسية (Standard Library)
تحتوي المكتبة القياسية على بعض الأدوات المساعدة المعطلة ولكن يتم الاحتفاظ بها لأسباب قديمة.
- 29.1 استخدم
Number.isNaNبدلاً منisNaN.
لماذا؟
isNaNيكره القيم غير الرقمية للأرقام، ويعود true لأي شيء يكره لـ NaN. إذا كان هذا السلوك مطلوبًا، فاجعله صريحًا.
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
- 29.2 استخدم
Number.isFiniteبدلاً منisFinite.
لماذا؟
isFiniteيكره القيم غير الرقمية للأرقام، ويعود true لأي شيء يكره لعدد محدود. إذا كان هذا السلوك مطلوبًا، فاجعله صريحًا.
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true
الاختبار (Testing)
- 30.1 نعم.
function foo() {
return true;
}
- 30.2 لا، بجدية:
- بغض النظر عن إطار الاختبار الذي تستخدمه، يجب عليك كتابة اختبارات!
- حاول كتابة الكثير من الوظائف النقية الصغيرة، وقلل من مكان حدوث الطفرات.
- كن حذرًا مع stubs و mocks - يمكن أن تجعل اختباراتك أكثر هشاشة.
- نحن نستخدم بشكل أساسي
mochaفي Airbnb. يتم استخدامtapeأيضًا أحيانًا لعينات صغيرة منفصلة. - تغطية اختبار 100٪ هدف جيد للسعي إليه، حتى لو لم يكن عمليًا دائمًا للوصول إليه.
- كلما قمت بإصلاح خطأ، اكتب اختبار انحدار. من المؤكد أن الخطأ الذي تم إصلاحه بدون اختبار انحدار سينكسر مرة أخرى في المستقبل.
الأداء (Performance)
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Loading…
الموارد (Resources)
تعلم ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
اقرأ هذا
أدوات
- Code Style Linters
أدلة أسلوب أخرى
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
أنماط أخرى
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on Github - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
قراءة متعمقة
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
كتب
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don’t Know JS: ES6 & Beyond - Kyle Simpson
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript…
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts
في البرية (In the Wild)
هذه قائمة بالمنظمات التي تستخدم دليل الأسلوب هذا. أرسل لنا طلب سحب أو مشكلة، وسنضيفك إلى القائمة.
- Aan Zee: AanZee/javascript
- Adult Swim: adult-swim/javascript
- Airbnb: airbnb/javascript
- Apartmint: apartmint/javascript
- Avalara: avalara/javascript
- Avant: avantcredit/javascript
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/javascript
- Brainshark: brainshark/javascript
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- Digitpaint digitpaint/javascript
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- ExactTarget: ExactTarget/javascript
- Expensify Expensify/Style-Guide
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia/javascript
- General Electric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Huballin: huballin/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InfoJobs: InfoJobs/JavaScript-Style-Guide
- Intent Media: intentmedia/javascript
- Jam3: Jam3/Javascript-Code-Conventions
- JeopardyBot: kesne/jeopardy-bot
- JSSolutions: JSSolutions/javascript
- Kinetica Solutions: kinetica/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- Muber: muber/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Nimbl3: nimbl3/javascript
- Orion Health: orionhealth/javascript
- OutBoxSoft: OutBoxSoft/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- React: /facebook/react/blob/master/CONTRIBUTING.md#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- Springload: springload/javascript
- StudentSphere: studentsphere/javascript
- Target: target/javascript
- TheLadders: TheLadders/javascript
- T4R Technology: T4R-Technology/javascript
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
الترجمة (Translation)
دليل الأسلوب هذا متاح أيضًا بلغات أخرى:
Brazilian Portuguese: armoucar/javascript-style-guide
Bulgarian: borislavvv/javascript
Catalan: fpmweb/javascript-style-guide
Chinese (Simplified): sivan/javascript-style-guide
Chinese (Traditional): jigsawye/javascript
French: nmussy/javascript-style-guide
German: timofurrer/javascript-style-guide
Italian: sinkswim/javascript-style-guide
Japanese: mitsuruog/javacript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Vietnamese: f1remoon/javascript-style-guide
دليل دليل أسلوب JavaScript (The JavaScript Style Guide Guide)
دردش معنا حول JavaScript
- تجدنا على gitter.
المساهمون (Contributors)
الترخيص (License)
(The MIT License)
Copyright (c) 2014-2016 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.
التعديلات (Amendments)
نشجعك على عمل تفرع لهذا الدليل وتغيير القواعد لتناسب دليل أسلوب فريقك. أدناه، يمكنك سرد بعض التعديلات على دليل الأسلوب. يتيح لك هذا تحديث دليل الأسلوب الخاص بك بشكل دوري دون الحاجة إلى التعامل مع تعارضات الدمج (merge conflicts).