- Notifications
You must be signed in to change notification settings - Fork44
Bản dịch tiếng Việt cho Định hướng Lối viết JavaScript của Airbnb
License
dangkyokhoang/javascript-style-guide
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Một cách tiếp cận hợp lý đối với JavaScript
Lưu ý của người dịch: Bản dịch này, với nỗ lực truyền đạt nội dung bằng tiếng Việt nhiều nhất có thể, đã dịch sang tiếng Việt các thuật ngữ, và/hoặc các từ, cụm từ mà thông thường không được dịch, như: "style guide", "object", "polyfill", v.v. Nếu bạn cảm thấy không quen thuộc hoặc khó khăn trong việc hiểu một số từ trong bản dịch này, hoặc muốn biết các từ tương ứng trong Tiếng Anh, vui lòng tham khảo phầnDanh mục các Thuật ngữ.
Lưu ý: Định hướng này giả định bạn đang sử dụngBabel, và đòi hỏi bạn sử dụngbabel-preset-airbnb hoặc một bộ tương đương. Nó cũng giả định rằng bạn đang cài bộ trợ năng cho ứng dụng của bạn, nhưairbnb-browser-shims hoặc một bộ tương đương.
Định hướng này cũng được dịch sang các ngôn ngữ khác. Xem phầnDịch.
Các Định hướng Lối viết Khác
- Các Kiểu giá trị
- Các Tham chiếu
- Các Đối tượng
- Các Mảng
- Trích xuất
- Các Chuỗi
- Các Hàm
- Các Hàm mũi tên
- Các Lớp & các Hàm tạo
- Các Mô-đun
- Các Đối tượng duyệt and các Hàm sinh trị
- Các Thuộc tính
- Các Biến
- Sự kéo lên
- Các Toán tử So sánh và Sự bằng nhau
- Các Khối
- Các Câu lệnh Điều khiển
- Các Chú thích
- Khoảng trắng
- Các Dấu phẩy
- Các Dấu chấm phẩy
- Sự ép kiểu
- Các Quy ước Đặt tên
- Các Hàm truy cập
- Các Sự kiện
- jQuery
- Tính tương thích của ECMAScript 5
- Lối viết ECMAScript 6+ (ES 2015+)
- Thư viện Tiêu chuẩn
- Sự kiểm thử
- Hiệu suất
- Các Tài nguyên
- Thực tế Áp dụng
- Danh mục các Thuật ngữ
- Dịch
- Về Hướng dẫn Lối viết JavaScript
- Nói chuyện với Chúng tôi về JavaScript
- Những Người đóng góp
- Giấy phép
- Các Sửa đổi
1.1Kiểu nguyên thủy: Khi bạn truy cập một giá trị kiểu nguyên thủy, bạn làm việc trực tiếp trên giá trị của nó.
stringnumberbooleannullundefinedsymbolbigint
constfoo=1;letbar=foo;bar=9;console.log(foo,bar);// => 1, 9
- Sự thiếu hỗ trợ cho các
SymbolvàBigIntkhông thể được lấp đầy bởi các bộ trợ năng một cách toàn diện, do đó, chúng không nên được sử dụng khi hướng đến các trình duyệt/môi trường không có hỗ trợ sẵn.
1.2Kiểu phức tạp: Khi bạn truy cập một giá trị kiểu phức tạp, bạn làm việc trên tham chiếu giá trị của nó.
objectarrayfunction
constfoo=[1,2];constbar=foo;bar[0]=9;console.log(foo[0],bar[0]);// => 9, 9
2.1 Sử dụng
constđối với tất cả các tham chiếu; tránh sử dụngvar. eslint:prefer-const,no-const-assignTại sao? Điều này đảm bảo rằng bạn không thể gán lại các tham chiếu, việc có thể gây ra các lỗi và gây khó khăn cho sự đọc hiểu mã nguồn.
// không tốtvara=1;varb=2;// tốtconsta=1;constb=2;
2.2 Nếu bạn bắt buộc phải gán lại các tham chiếu, sử dụng
let, thay vìvar. eslint:no-varTại sao?
letthuộc phạm vi khối mà nó được khởi tạo, thay vì thuộc phạm vi hàm nhưvar.// không tốtvarcount=1;if(true){count+=1;}// tốt, sử dụng let.letcount=1;if(true){count+=1;}
2.3 Lưu ý rằng cả
letvàconstđều thuộc phạm vi khối, cònvarthuộc phạm vi hàm.// const và let chỉ tồn tại trong phạm vi khối tạo ra chúng.{leta=1;constb=1;varc=1;}console.log(a);// ReferenceErrorconsole.log(b);// ReferenceErrorconsole.log(c);// In ra 1
Trong đoạn mã trên, bạn có thể thấy rằng lỗi ReferenceError xảy ra khi truy cập
avàb, trong khicvẫn là số đã gán. Nguyên nhân là vìavàbthuộc phạm vi khối, còncthuộc phạm vi hàm chứa đoạn mã trên.
3.1 Sử dụng cú pháp nguyên văn
{}để khởi tạo đối tượng. eslint:no-new-object// không tốtconstitem=newObject();// tốtconstitem={};
3.2 Sử dụng các tên được tính của thuộc tính
[key()]khi tạo các đối tượng có các tên của thuộc tính là động.Tại sao? Chúng cho phép bạn định nghĩa tất cả các thuộc tính của một đối tượng cùng một chỗ.
functiongetKey(k){return`tên của thuộc tính là${k}`;}// không tốtconstobj={id:5,name:'San Francisco',};obj[getKey('enabled')]=true;// tốtconstobj={id:5,name:'San Francisco',[getKey('enabled')]:true,};
3.3 Sử dụng cú pháp định nghĩa phương thức rút gọn để định nghĩa các phương thức của đối tượng. eslint:
object-shorthand// không tốtconstatom={value:1,addValue:function(value){returnatom.value+value;},};// tốtconstatom={value:1,addValue(value){returnatom.value+value;},};
3.4 Sử dụng cú pháp định nghĩa thuộc tính rút gọn để định nghĩa các thuộc tính của đối tượng. eslint:
object-shorthandTại sao? Nó ngắn gọn và súc tích.
constlukeSkywalker='Luke Skywalker';// không tốtconstobj={lukeSkywalker:lukeSkywalker,};// tốtconstobj={ lukeSkywalker,};
3.5 Gom tất cả các thuộc tính rút gọn ở trên cùng khi khai báo đối tượng.
Tại sao? Điều này giúp bạn dễ dàng biết được thuộc tính nào sử dụng cú pháp rút gọn.
constanakinSkywalker='Anakin Skywalker';constlukeSkywalker='Luke Skywalker';// không tốtconstobj={episodeOne:1,twoJediWalkIntoACantina:2, lukeSkywalker,episodeThree:3,mayTheFourth:4, anakinSkywalker,};// tốtconstobj={ lukeSkywalker, anakinSkywalker,episodeOne:1,twoJediWalkIntoACantina:2,episodeThree:3,mayTheFourth:4,};
3.6 Chỉ sử dụng dấu lược
' 'cho các thuộc tính có định danh không hợp lệ. eslint:quote-propsTại sao? Nhìn chung, chúng ta sẽ thấy nó dễ đọc hơn nhiều. Nó cải thiện nhấn mạnh cú pháp, và nó cũng giúp việc tối ưu hóa bằng các trình thực thi JS hiệu quả hơn.
// không tốtconstbad={'foo':3,'bar':4,'một-cái-tên':5,};// tốtconstgood={foo:3,bar:4,'một-cái-tên':5,};
3.7 Không gọi các phương thức
Object.prototypemột cách trực tiếp, ví dụ nhưhasOwnProperty,propertyIsEnumerable, vàisPrototypeOf. eslint:no-prototype-builtinsTại sao? Những phương thức này có thể bị thay thế bởi các thuộc tính của một đối tượng - như
{ hasOwnProperty: false }- hoặc, đối tượng có thể là một đối tượng rỗng (Object.create(null)).// không tốtconsole.log(object.hasOwnProperty(key));// tốtconsole.log(Object.prototype.hasOwnProperty.call(object,key));// tốt nhấtconsthas=Object.prototype.hasOwnProperty;// lưu tạm phương thức một lần, dùng cho cả mô-đun.console.log(has.call(object,key));/* hoặc */importhasfrom'has';// https://www.npmjs.com/package/hasconsole.log(has.call(object,key));
3.8 Ưu tiên sử dụng cú pháp liệt kê
...so vớiObject.assignđể tạo bản sao nhanh của một đối tượng. Sử dụng toán tử còn-lại...để tạo một đối tượng mới với một số thuộc tính đã bị loại bỏ. eslint:prefer-object-spread// rất không tốtconstoriginal={a:1,b:2};constcopy=Object.assign(original,{c:3});// cái này làm biến đổi `original` ಠ_ಠdeletecopy.a;// cái này cũng vậy// không tốtconstoriginal={a:1,b:2};constcopy=Object.assign({},original,{c:3});// copy => { a: 1, b: 2, c: 3 }// tốtconstoriginal={a:1,b:2};constcopy={ ...original,c:3};// copy => { a: 1, b: 2, c: 3 }const{ a, ...noA}=copy;// noA => { b: 2, c: 3 }
4.1 Sử dụng cú pháp nguyên văn
[]để khởi tạo mảng. eslint:no-array-constructor// không tốtconstitems=newArray();// tốtconstitems=[];
4.2 Sử dụngArray#push, thay vì phép gán, để thêm các mục cho một mảng.
constsomeStack=[];// không tốtsomeStack[someStack.length]='abracadabra';// tốtsomeStack.push('abracadabra');
4.3 Sử dụng toán tử liệt kê
...để sao nhanh một mảng.// không tốtconstlen=items.length;constitemsCopy=[];leti;for(i=0;i<len;i+=1){itemsCopy[i]=items[i];}// tốtconstitemsCopy=[...items];
4.4 Để chuyển đổi một đối tượng khả duyệt thành một mảng, sử dụng toán tử liệt kê
...thay vìArray.from.constfoo=document.querySelectorAll('.foo');// tốtconstnodes=Array.from(foo);// tốt nhấtconstnodes=[...foo];
4.5 Sử dụng
Array.fromđể chuyển đổi một đối tượng giống-mảng thành một mảng.constarrLike={0:'foo',1:'bar',2:'baz',length:3};// không tốtconstarr=Array.prototype.slice.call(arrLike);// tốtconstarr=Array.from(arrLike);
4.6 Sử dụng
Array.from, thay vì toán tử liệt kê..., để ánh xạ một đối tượng khả duyệt, vì nó không tạo ra một mảng trung gian.// không tốtconstbaz=[...foo].map(bar);// tốtconstbaz=Array.from(foo,bar);
4.7 Sử dụng các lệnh
returncho các hàm gọi lại dùng cho các phương thức của mảng. Được phép bỏ quareturnnếu phần thân hàm chỉ gồm một câu lệnh trả về một biểu thức không có hiệu ứng phụ, theo quy tắc8.2. eslint:array-callback-return// tốt[1,2,3].map((x)=>{consty=x+1;returnx*y;});// tốt[1,2,3].map((x)=>x+1);// không tốt - không có giá trị trả về đồng nghĩa với `acc` sẽ trở thành undefined sau lượt duyệt đầu tiên[[0,1],[2,3],[4,5]].reduce((acc,item,index)=>{constflatten=acc.concat(item);});// tốt[[0,1],[2,3],[4,5]].reduce((acc,item,index)=>{constflatten=acc.concat(item);returnflatten;});// không tốtinbox.filter((msg)=>{const{ subject, author}=msg;if(subject==='Con chim nhại'){returnauthor==='Harper Lee';}else{returnfalse;}});// tốtinbox.filter((msg)=>{const{ subject, author}=msg;if(subject==='Con chim nhại'){returnauthor==='Harper Lee';}returnfalse;});
4.8 Sử dụng dấu ngắt dòng trước và sau các dấu đóng và mở ngoặc vuông nếu một mảng nằm trên nhiều dòng.
// không tốtconstarr=[[0,1],[2,3],[4,5],];constobjectInArray=[{id:1,},{id:2,}];constnumberInArray=[1,2,];// tốtconstarr=[[0,1],[2,3],[4,5]];constobjectInArray=[{id:1,},{id:2,},];constnumberInArray=[1,2,];
5.1 Sử dụng trích xuất đối tượng khi truy cập và sử dụng nhiều thuộc tính của một đối tượng. eslint:
prefer-destructuringTại sao? Trích xuất giúp việc tạo các tham chiếu đến các thuộc tính trở nên dễ dàng hơn và hạn chế việc truy cập một đối tượng lặp đi lặp lại. Việc truy cập đối tượng lặp đi lặp lại tạo ra nhiều đoạn mã trùng lặp hơn, cần phải đọc nhiều hơn, và tăng khả năng xảy ra nhầm lẫn. Trích xuất đối tượng cũng tạo nên một ý tưởng về cấu trúc của đối tượng được sử dụng trong khối, thay vì cần phải đọc toàn bộ khối để xác định những thuộc tính được sử dụng.
// không tốtfunctiongetFullName(user){constfirstName=user.firstName;constlastName=user.lastName;return`${firstName}${lastName}`;}// tốtfunctiongetFullName(user){const{ firstName, lastName}=user;return`${firstName}${lastName}`;}// bestfunctiongetFullName({ firstName, lastName}){return`${firstName}${lastName}`;}
5.2 Hãy sử dụng trích xuất mảng. eslint:
prefer-destructuringconstarr=[1,2,3,4];// không tốtconstfirst=arr[0];constsecond=arr[1];// tốtconst[first,second]=arr;
5.3 Sử dụng trích xuất đối tượng khi có nhiều giá trị trả về, thay vì trích xuất mảng.
Tại sao? Bạn có thể thêm các thuộc tính mới qua thời gian hay thay đổi thứ tự các thứ mà không lo làm hỏng các phép gọi trước đó.
// không tốtfunctionprocessInput(input){// khi một phép màu xảy rareturn[left,right,top,bottom];}// người gọi cần nghĩ về thứ tự của giá trị trả vềconst[left,__,top]=processInput(input);// tốtfunctionprocessInput(input){// khi một phép màu xảy rareturn{ left, right, top, bottom};}// người gọi chỉ cần chọn giá trị mà họ muốnconst{ left, top}=processInput(input);
6.1 Sử dụng dấu lược cho các chuỗi. eslint:
quotes// không tốtconstname="Capt. Janeway";// không tốt - các nguyên văn mẫu nên chứa sự biến đổi chuỗi hoặc ngắt dòngconstname=`Capt. Janeway`;// tốtconstname='Capt. Janeway';
6.2 Các chuỗi, dù khiến cho độ dài của dòng lớn hơn 100 ký tự, không nên được viết thành nhiều dòng sử dụng ghép chuỗi.
Tại sao? Các chuỗi bị chia nhỏ rất khó để làm việc cùng và khiến việc tìm kiếm trong mã nguồn trở nên khó hơn.
// không tốtconsterrorMessage='Đây là một lỗi rất dài mà được ném ra bởi \Người Dơi. Khi bạn ngừng nghĩ về việc tại sao Người Dơi chẳng có liên \quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với \đâu.';// không tốtconsterrorMessage='Đây là một lỗi rất dài mà được ném ra bởi'+'Người Dơi. Khi bạn ngừng nghĩ về việc tại sao Người Dơi chẳng có liên'+'quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với'+'đâu.';// tốtconsterrorMessage='Đây là một lỗi rất dài mà được ném ra bởi Người Dơi. Khi bạn ngừng nghĩ về việc tại sao Người Dơi chẳng có liên quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với đâu.';
6.3 Khi xây dựng các chuỗi theo một chu trình, sử dụng mẫu chuỗi thay vì ghép chuỗi. eslint:
prefer-templatetemplate-curly-spacingTại sao? Các mẫu chuỗi cho bạn một cú pháp súc tích, dễ đọc với các ngắt dòng và các tính năng ghép chuỗi phù hợp.
// không tốtfunctionsayHi(name){return'Bạn có khỏe không, '+name+'?';}// không tốtfunctionsayHi(name){return['Bạn có khỏe không, ',name,'?'].join();}// tốtfunctionsayHi(name){return`Bạn có khỏe không,${name}?`;}
- 6.4 Không bao giờ sử dụng
eval()cho một chuỗi, điều đó mở ra rất nhiều các lỗ hổng và rủi ro. eslint:no-eval
6.5 Không sử dụng các ký tự thoát trong một chuỗi khi không cần thiết. eslint:
no-useless-escapeTại sao? Các dấu chéo ngược làm giảm tính khả đọc, vì thế chúng chỉ nên xuất hiện khi cần.
// không tốtconstfoo='\'cái này\' \đư\ợc \"cho trong ngoặc\"';// tốtconstfoo='\'cái này\' được "cho trong ngoặc"';constfoo=`tên của tôi là '${name}'`;
7.1 Sử dụng biểu thức hàm hữu danh thay vì khai báo hàm. eslint:
func-styleTại sao? Các khai báo hàm đều được kéo lên, đồng nghĩa với việc một hàm rất dễ có khả năng được sử dụng trước cả khi nó được định nghĩa trong tệp. Điều này làm giảm tính khả đọc và khả năng bảo trì. Nếu bạn thấy một hàm đủ lớn hoặc phức tạp đến mức ảnh hưởng đến việc đọc hiểu phần còn lại của tệp thì, có lẽ, nó nên được tách ra thành một mô-đun riêng! Đừng quên đặt tên cho biểu thức một cách rõ ràng, cho dù tên hàm có thể được suy ra từ tên biến chứa hàm đó (thường gặp ở các trình duyệt mới nhất hoặc các trình biên dịch như Babel). Điều này loại bỏ các nhận định liên quan đến ngăn xếp của một lỗi. (Cuộc thảo luận)
// không tốtfunctionfoo(){// ...}// không tốtconstfoo=function(){// ...};// tốt// tên riêng của hàm, phân biệt với tên tham chiếu được gọi khi cần sử dụngconstshort=functionlongUniqueMoreDescriptiveLexicalFoo(){// ...};
7.2 Đặt các biểu thức hàm gọi tức thời trong ngoặc. eslint:
wrap-iifeTại sao? Một biểu thức hàm gọi tức thời mà một đơn vị riêng - đặt nó và dấu ngoặc dùng để gọi nó
()trong ngoặc để biểu đạt nó một cách rõ ràng. Cũng cần biết là, trong cái thế giới mà mô-đun ngập tràn mọi nơi như bây giờ, bạn cũng chả mấy khi cần dùng đến biểu thức hàm gọi tức thời.// biểu thức hàm gọi tức thời(function(){console.log('Xin chào đến với thế giới. Hãy đi theo tôi.');}());
- 7.3 Không bao giờ khai báo một hàm bên trong một khối không phải hàm (
if,while, v.v.). Thay vào đó, hãy gán hàm cho một biến. Các trình duyệt đều sẽ cho phép bạn làm điều đó, nhưng tiếc là, cách mà chúng diễn dịch là khác nhau. eslint:no-loop-func
7.4Ghi chú: ECMA-262 định nghĩa một
khốilà tập hợp một hoặc một vài câu lệnh. Một khai báo hàm không phải là một câu lệnh.// không tốtif(currentUser){functiontest(){console.log('Đừng!');}}// tốtlettest;if(currentUser){test=()=>{console.log('Tốt đó.');};}
7.5 Không bao giờ đặt tên một tham số là
arguments. Tham số này sẽ được ưu tiên hơn đối tượngargumentsđược cung cấp cho mỗi phạm vi hàm.// không tốtfunctionfoo(name,options,arguments){// ...}// tốtfunctionfoo(name,options,args){// ...}
7.6 Không bao giờ sử dụng
arguments, thay vào đó, hãy sử dụng cú pháp còn-lại.... eslint:prefer-rest-paramsTại sao?
...định rõ các đối số mà bạn muốn lấy. Thêm nữa, kết quả của còn-lại là một mảng đúng nghĩa, thay vì chỉ là giống-mảng nhưarguments.// không tốtfunctionconcatenateAll(){constargs=Array.prototype.slice.call(arguments);returnargs.join('');}// tốtfunctionconcatenateAll(...args){returnargs.join('');}
7.7 Sử dụng tham số mặc định thay vì làm biến đổi các đối số truyền vào hàm.
// rất tệfunctionhandleThings(opts){// Không! Chúng ta không nên biến đổi các đối số.// Cái tệ thứ hai: Nếu opts là kiểu sai, nó sẽ bị đổi thành một đối tượng.// Đó có thể là điều bạn muốn, nhưng nó thi thoảng gây ra lỗi.opts=opts||{};// ...}// vẫn tệfunctionhandleThings(opts){if(opts===void0){opts={};}// ...}// tốtfunctionhandleThings(opts={}){// ...}
7.8 Tránh gây ra hiệu ứng phụ với tham số mặc định.
Tại sao? Chúng khá là rối để có thể hình dung.
varb=1;// không tốtfunctioncount(a=b++){console.log(a);}count();// 1count();// 2count(3);// 3count();// 3
7.9 Luôn để các tham số mặc định ở sau cùng. eslint:
default-param-last// không tốtfunctionhandleThings(opts={},name){// ...}// tốtfunctionhandleThings(name,opts={}){// ...}
7.10 Không bao giờ sử dụng hàm tạo
Functionđể tạo hàm. eslint:no-new-funcTại sao? Tạo một hàm theo cách này cũng thực thi chuỗi giống như
eval()vậy, thứ mà mở ra các lỗ hổng.// không tốtvaradd=newFunction('a','b','return a + b');// vẫn là không tốtvarsubtract=Function('a','b','return a - b');
7.11 Sử dụng các dấu cách giữa các bộ phận hàm. eslint:
space-before-function-parenspace-before-blocksTại sao? Sự đồng nhất vẫn cứ là tốt, và bạn không cần phải thêm hoặc bớt dấu cách khi không đặt tên hàm.
// không tốtconstf=function(){};constg=function(){};consth=function(){};// tốtconstx=function(){};consty=functiona(){};
7.12 Không bao giờ làm biến đổi các tham số. eslint:
no-param-reassignTại sao? Việc can thiệp vào các đối tượng được truyền vào dưới dạng tham số có thể gây hiệu ứng phụ không mong muốn đối với biến tại tiến trình gọi.
// không tốtfunctionf1(obj){obj.key=1;}// tốtfunctionf2(obj){constkey=Object.prototype.hasOwnProperty.call(obj,'key') ?obj.key :1;}
7.13 Không bao giờ gán lại các tham số. eslint:
no-param-reassignTại sao? Việc gán lại các tham số có thể dẫn tới hành vi không mong muốn, đặc biệt là khi truy cập đối tượng
arguments. Nó cũng có thể gây ra một số vấn đề về tối ưu hóa, nhất là trong V8.// không tốtfunctionf1(a){a=1;// ...}functionf2(a){if(!a){a=1;}// ...}// tốtfunctionf3(a){constb=a||1;// ...}functionf4(a=1){// ...}
7.14 Ưu tiên sử dụng cú pháp liệt kê
...để gọi các hàm bất định. eslint:prefer-spreadTại sao? Nó nhìn sáng sủa hơn, bạn không cần phải đặt ngữ cảnh, và bạn cũng đâu thể dễ dàng kết hợp
newvớiapply.// không tốtconstx=[1,2,3,4,5];console.log.apply(console,x);// tốtconstx=[1,2,3,4,5];console.log(...x);// không tốtnew(Function.prototype.bind.apply(Date,[null,2016,8,5]));// tốtnewDate(...[2016,8,5]);
7.15 Các hàm với các bộ phận hàm, hoặc các phép gọi, nằm trên nhiều dòng nên được căn đầu dòng như tất cả các danh sách nhiều dòng khác trong hướng dẫn này: với mỗi mục nằm trên một dòng riêng biệt, cùng với một dấu phẩy ngay sau mục cuối cùng. eslint:
function-paren-newline// không tốtfunctionfoo(bar,baz,quux){// ...}// tốtfunctionfoo(bar,baz,quux,){// ...}// không tốtconsole.log(foo,bar,baz);// tốtconsole.log(foo,bar,baz,);
8.1 Khi bạn phải sử dụng một hàm vô danh (như khi cần truyền một hàm gọi lại trên cùng dòng), sử dụng ký pháp hàm mũi tên. eslint:
prefer-arrow-callback,arrow-spacingTại sao? Nó tạo ra một hàm thực thi trên ngữ cảnh của
this, thường là thứ bạn cần, và nó rất súc tích.Khi nào thì không? Khi bạn có một hàm tương đối rắc rối, bạn cần phải chuyển lô-gíc của hàm đó sang biểu thức hàm hữu danh.
// không tốt[1,2,3].map(function(x){consty=x+1;returnx*y;});// tốt[1,2,3].map((x)=>{consty=x+1;returnx*y;});
8.2 Nếu như phần thân hàm chỉ gồm một câu lệnh trả về mộtbiểu thức mà không có hiệu ứng phụ, bỏ qua dấu ngoặc nhọn và sử dụng trả về ngầm định. Nếu không, giữ nguyên dấu ngoặc và sử dụng lệnh
return. eslint:arrow-parens,arrow-body-styleTại sao? Cú pháp tiện lợi. Nó dễ đọc khi nhiều hàm nối chuỗi nhau.
// không tốt[1,2,3].map((number)=>{constnextNumber=number+1;`Một chuỗi có chứa số${nextNumber}.`;});// tốt[1,2,3].map((number)=>`Một chuỗi có chứa số${number+1}.`);// tốt[1,2,3].map((number)=>{constnextNumber=number+1;return`Một chuỗi có chứa số${nextNumber}.`;});// tốt[1,2,3].map((number,index)=>({[index]:number,}));// Không dùng trả về ngầm định khi có hiệu ứng phụfunctionfoo(callback){constval=callback();if(val===true){// Thực hiện gì đó nếu hàm gọi lại trả về true}}letbool=false;// không tốtfoo(()=>bool=true);// tốtfoo(()=>{bool=true;});
8.3 Trong trường hợp biểu thức nằm trên nhiều dòng, nhóm nó trong ngoặc để dễ đọc hơn.
Tại sao? Nó cho thấy một cách rõ ràng điểm bắt đầu và kết thúc hàm.
// không tốt['get','post','put'].map((httpMethod)=>Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName,httpMethod,));// tốt['get','post','put'].map((httpMethod)=>(Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName,httpMethod,)));
8.4 Luôn sử dụng ngoặc tròn xung quanh các đối số để rõ ràng và nhất quán. eslint:
arrow-parensTại sao? Giảm thiểu sự khác biệt khi thêm và xóa các đối số.
// không tốt[1,2,3].map(x=>x*x);// tốt[1,2,3].map((x)=>x*x);// tốt[1,2,3].map((number)=>(`Một chuỗi thật là dài với số${number}. Nó quá dài để chúng ta có thể viết cùng dòng với dòng .map!`));// không tốt[1,2,3].map(x=>{consty=x+1;returnx*y;});// tốt[1,2,3].map((x)=>{consty=x+1;returnx*y;});
8.5 Tránh gây dễ nhầm lẫn giữa cú pháp hàm mũi tên (
=>) với các toán tử so sánh (<=,>=). eslint:no-confusing-arrow// không tốtconstitemHeight=(item)=>item.height<=256 ?item.largeSize :item.smallSize;// không tốtconstitemHeight=(item)=>item.height>=256 ?item.largeSize :item.smallSize;// tốtconstitemHeight=(item)=>(item.height<=256 ?item.largeSize :item.smallSize);// tốtconstitemHeight=(item)=>{const{ height, largeSize, smallSize}=item;returnheight<=256 ?largeSize :smallSize;};
8.6 Cách đặt vị trí của phần thân hàm mũi tên với trả về ngầm định. eslint:
implicit-arrow-linebreak// không tốt(foo)=>bar;(foo)=>(bar);// tốt(foo)=>bar;(foo)=>(bar);(foo)=>(bar)
9.1 Luôn sử dụng
class. Tránh việc can thiệp trực tiếp vàoprototype.Tại sao? Cú pháp
classsúc tích, dễ hiểu và dễ hình dung.// không tốtfunctionQueue(contents=[]){this.queue=[...contents];}Queue.prototype.pop=function(){constvalue=this.queue[0];this.queue.splice(0,1);returnvalue;};// tốtclassQueue{constructor(contents=[]){this.queue=[...contents];}pop(){constvalue=this.queue[0];this.queue.splice(0,1);returnvalue;}}
9.2 Sử dụng
extendscho thừa kế.Tại sao? Nó là cách sẵn có để thừa kế nguyên mẫu mà không làm ảnh hưởng đến
instanceof.// không tốtconstinherits=require('inherits');functionPeekableQueue(contents){Queue.apply(this,contents);}inherits(PeekableQueue,Queue);PeekableQueue.prototype.peek=function(){returnthis.queue[0];};// tốtclassPeekableQueueextendsQueue{peek(){returnthis.queue[0];}}
9.3 Các phương thức, mỗi khi có thể, hãy trả về
thisđể tiện cho việc nối chuỗi phương thức.// không tốtJedi.prototype.jump=function(){this.jumping=true;returntrue;};Jedi.prototype.setHeight=function(height){this.height=height;};constluke=newJedi();luke.jump();// => trueluke.setHeight(20);// => undefined// tốtclassJedi{jump(){this.jumping=true;returnthis;}setHeight(height){this.height=height;returnthis;}}constluke=newJedi();luke.jump().setHeight(20);
9.4 Có thể viết phương thức
toString()tùy ý, chỉ cần đảm bản nó hoạt động hoàn hảo và không gây ra các hiệu ứng phụ.classJedi{constructor(options={}){this.name=options.name||'vô danh';}getName(){returnthis.name;}toString(){return`Jedi -${this.getName()}`;}}
9.5 Các lớp có một hàm tạo mặc định nếu không được chỉ định. Một hàm tạo rỗng, hoặc chỉ trỏ đến lớp cha, là không cần thiết. eslint:
no-useless-constructor// không tốtclassJedi{constructor(){}getName(){returnthis.name;}}// không tốtclassReyextendsJedi{constructor(...args){super(...args);}}// tốtclassReyextendsJedi{constructor(...args){super(...args);this.name='Rey';}}
9.6 Tránh trùng lặp các thành viên của một lớp. eslint:
no-dupe-class-membersTại sao? Với các khai báo thành viên bị lặp, khai báo cuối được tự động ưu tiên - việc có sự trùng lặp gần như chắc chắn là một lỗi.
// không tốtclassFoo{bar(){return1;}bar(){return2;}}// tốtclassFoo{bar(){return1;}}// tốtclassFoo{bar(){return2;}}
9.7 Các phương thức của lớp nên sử dụng
thishoặc được chuyển thành phương thức tĩnh, trừ trường hợp thư viện bên ngoài hoặc bộ khung phần mềm bắt buộc sử dụng phương thức không phải phương thức tĩnh. Một phương thức là phương thức của thực thể nên mang ý nghĩa rằng nó hoạt động khác nhau dựa trên những thuộc tính của đối tượng đích. eslint:class-methods-use-this// không tốtclassFoo{bar(){console.log('bar');}}// tốt - this được sử dụngclassFoo{bar(){console.log(this.bar);}}// tốt - constructor là ngoại lệclassFoo{constructor(){// ...}}// tốt - phương thức tĩnh không nên sử dụng thisclassFoo{staticbar(){console.log('bar');}}
10.1 Luôn sử dụng mô-đun (
import/export) thay vì một hệ thống mô-đun phi chuẩn. Bạn luôn có thể dịch mã sang hệ thống mô-đun mà bạn thích.Tại sao? Mô-đun là tương lai, hãy cùng sử dụng tương lai ngay lúc này.
// không tốtconstAirbnbStyleGuide=require('./AirbnbStyleGuide');module.exports=AirbnbStyleGuide.es6;// okimportAirbnbStyleGuidefrom'./AirbnbStyleGuide';exportdefaultAirbnbStyleGuide.es6;// bestimport{es6}from'./AirbnbStyleGuide';exportdefaultes6;
10.2 Không sử dụng ký tự đại diện để nhập.
Tại sao? Điều này đảm bảo bạn chỉ xuất mặc định một giá trị.
// không tốtimport*asAirbnbStyleGuidefrom'./AirbnbStyleGuide';// tốtimportAirbnbStyleGuidefrom'./AirbnbStyleGuide';
10.3 Và không xuất trực tiếp từ một lệnh nhập.
Tại sao? Mặc dù cấu trúc một dòng là súc tích, việc nhập một cách rõ ràng và xuất một cách rõ ràng làm cho mọi thứ nhất quán.
// không tốt// tên tệp es6.jsexport{es6asdefault}from'./AirbnbStyleGuide';// tốt// tên tệp es6.jsimport{es6}from'./AirbnbStyleGuide';exportdefaultes6;
10.4 Chỉ nhập từ một đường dẫn ở chung một chỗ.eslint:
no-duplicate-importsTại sao? Có nhiều dòng nhập từ cùng một đường dẫn khiến mã nguồn trở nên khó bảo trì hơn.
// không tốtimportfoofrom'foo';// … và nhập một vài thứ nữa … //import{named1,named2}from'foo';// tốtimportfoo,{named1,named2}from'foo';// tốtimportfoo,{named1,named2,}from'foo';
10.5 Không xuất các ràng buộc có thể bị biến đổi.eslint:
import/no-mutable-exportsTại sao? Sự biến đổi, nói chung, nên được tránh, nhưng đặc biệt là đối với trường hợp xuất các giá trị có thể bị biến đổi. Trong khi kỹ thuật này có thể là cần thiết trong một số trường hợp đặc biệt, nhìn chung, chỉ nên xuất các giá trị là hằng.
// không tốtletfoo=3;export{foo};// tốtconstfoo=3;export{foo};
10.6 Trong các mô-đun chỉ có một địa chỉ xuất, ưu tiên xuất mặc định thay vì xuất hữu danh.eslint:
import/prefer-default-exportTại sao? Nhằm khuyến khích các tệp chỉ xuất một giá trị, giúp mã nguồn dễ đọc và dễ bảo trì.
// không tốtexportfunctionfoo(){}// tốtexportdefaultfunctionfoo(){}
10.7 Đặt tất cả các lệnh
importtrên cùng.eslint:import/firstTại sao? Vì các lệnh
importđược kéo lên, việc đặt tất cả chúng ở trên cùng nhằm ngăn chặn các hành vi không đáng có.// không tốtimportfoofrom'foo';foo.init();importbarfrom'bar';// tốtimportfoofrom'foo';importbarfrom'bar';foo.init();
10.8 Các lệnh nhập nhiều dòng nên được căn đầu dòng giống như các mảng hay đối tượng nguyên văn nhiều dòng. eslint:
object-curly-newlineTại sao? Các đấu ngoặc nhọn đều có cùng các quy tắc căn đầu dòng như tất cả mọi khối ngoặc nhọn trong bản định hướng này, cùng với như dấu phẩy ở cuối.
// không tốtimport{longNameA,longNameB,longNameC,longNameD,longNameE}from'path';// tốtimport{longNameA,longNameB,longNameC,longNameD,longNameE,}from'path';
10.9 Không cho phép cú pháp bộ tải Webpack trong các lệnh nhập mô-đun.eslint:
import/no-webpack-loader-syntaxTại sao? Vì sử dụng cú pháp Webpack trong các lệnh nhập gom mã thành một bộ tổng hợp mô-đun. Ưu tiên sử dụng cú pháp bộ tải trong
webpack.config.js.// không tốtimportfooSassfrom'css!sass!foo.scss';importbarCssfrom'style!css!bar.css';// tốtimportfooSassfrom'foo.scss';importbarCssfrom'bar.css';
10.10 Không thêm phần mở rộng của tên tệp JavaScript. eslint:
import/extensionsTạo sao? Việc thêm phần mở rộng của tệp khiến cho việc cải tiến mã nguồn trở nên khó khăn hơn, và tạo nên những chi tiết không cần thiết trong lệnh nhập mô-đun mỗi khi bạn sử dụng.
// không tốtimportfoofrom'./foo.js';importbarfrom'./bar.jsx';importbazfrom'./baz/index.jsx';// tốtimportfoofrom'./foo';importbarfrom'./bar';importbazfrom'./baz';
11.1 Không sử dụng các đối tượng duyệt. Ưu tiên sử dụng các hàm bậc cao hơn của JavaScript thay vì các vòng lặp như
for-inhayfor-of. eslint:no-iteratorno-restricted-syntaxTại sao? Điều này đảm bảo việc thực hiện quy tắc bất biến. Làm việc với các hàm thuần mà trả về các giá trị sẽ dễ tưởng tượng hơn so với các hiệu ứng phụ.
Sử dụng
map()/every()/filter()/find()/findIndex()/reduce()/some()/ ... để duyệt qua một mảng, vàObject.keys()/Object.values()/Object.entries()để tạo một mảng để bạn có thể duyệt qua một đối tượng.constnumbers=[1,2,3,4,5];// không tốtletsum=0;for(letnumofnumbers){sum+=num;}sum===15;// tốtletsum=0;numbers.forEach((num)=>{sum+=num;});sum===15;// tốt nhất, sử dụng hàmconstsum=numbers.reduce((total,num)=>total+num,0);sum===15;// không tốtconstincreasedByOne=[];for(leti=0;i<numbers.length;i++){increasedByOne.push(numbers[i]+1);}// tốtconstincreasedByOne=[];numbers.forEach((num)=>{increasedByOne.push(num+1);});// tốt nhất, vẫn là sử dụng hàmconstincreasedByOne=numbers.map((num)=>num+1);
11.2 Không sử dụng các hàm sinh trị
function*vào thời điểm này.Tại sao? Nó không thể được dịch mã sang ES5 một cách hoàn hảo.
11.3 Nếu bạn bắt buộc phải dùng các hàm sinh trị, hoặc bạn bỏ quakhuyến nghị của chúng tôi, hãy đảm bảo rằng bạn sử dụng dấu cách giữa các bộ phận hàm một cách hợp lý. eslint:
generator-star-spacingTại sao?
functionvà*là tạo thành một từ khóa riêng -*không phải là từ khóa điều chỉnh chofunction,function*là một cấu tạo riêng biệt, khác vớifunction.// không tốtfunction*foo(){// ...}// không tốtconstbar=function*(){// ...};// không tốtconstbaz=function*(){// ...};// không tốtconstquux=function*(){// ...};// không tốtfunction*foo(){// ...}// không tốtfunction*foo(){// ...}// rất tệfunction*foo(){// ...}// rất rất tệconstwat=function*(){// ...};// tốtfunction*foo(){// ...}// tốtconstfoo=function*(){// ...};
12.1 Sử dụng ký pháp chấm
.để truy cập các thuộc tính. eslint:dot-notationconstluke={jedi:true,age:28,};// không tốtconstisJedi=luke['jedi'];// tốtconstisJedi=luke.jedi;
12.2 Sử dụng ký pháp ngoặc
[]để truy cập thuộc tính với một biến.constluke={jedi:true,age:28,};functiongetProp(prop){returnluke[prop];}constisJedi=getProp('jedi');
12.3 Sử dụng toán tử lũy thừa
**để tính các lũy thừa. eslint:no-restricted-properties.// không tốtconstbinary=Math.pow(2,10);// tốtconstbinary=2**10;
13.1 Luôn sử dụng
consthoặcletđể khai báo biến. Không làm như vậy sẽ dẫn đến các biến toàn cục. Chúng ta muốn tránh việc làm ô nhiễm không gian tên toàn cục. Đội trưởng Hành tinh đã cảnh báo chúng ta. eslint:no-undefprefer-const// không tốtsuperPower=newSuperPower();// tốtconstsuperPower=newSuperPower();
13.2 Sử dụng một
consthoặcletkhai báo cho mỗi biến hoặc phép gán. eslint:one-varTại sao? Khai báo theo cách này giúp dễ thêm các khai báo mới, và bạn chẳng phải nghĩ về việc phải dùng
;hay,. Bạn còn có thể bước qua mỗi khai báo trong trình gỡ lỗi, thay vì nhảy qua toàn bộ chúng trong một bước.// không tốtconstitems=getItems(),goSportsTeam=true,dragonball='z';// không tốt// (so sánh với trên kia và thử tìm ra lỗi ở đây)constitems=getItems(),goSportsTeam=true;dragonball='z';// tốtconstitems=getItems();constgoSportsTeam=true;constdragonball='z';
13.3 Nhóm tất cả các
constvà rồi nhóm tất cả cáclet.Tại sao? Điều này hữu ích khi, sau đó, bạn sẽ cần gán lại một biến dựa trên các biến đã gán trước đó.
// không tốtleti,len,dragonball,items=getItems(),goSportsTeam=true;// không tốtleti;constitems=getItems();letdragonball;constgoSportsTeam=true;letlen;// tốtconstgoSportsTeam=true;constitems=getItems();letdragonball;leti;letlength;
13.4 Chỉ gán biến khi cần, nhưng nhớ đặt chúng ở một nơi hợp lý.
Tại sao?
letvàconstthuộc phạm vi khối, không phải phạm vi hàm.// không tốt - phép gọi hàm không cần thiếtfunctioncheckName(hasName){constname=getName();if(hasName==='thí nghiệm'){returnfalse;}if(name==='thí nghiệm'){this.setName('');returnfalse;}returnname;}// tốtfunctioncheckName(hasName){if(hasName==='thí nghiệm'){returnfalse;}constname=getName();if(name==='thí nghiệm'){this.setName('');returnfalse;}returnname;}
13.5 Đừng nối chuỗi các phép gán. eslint:
no-multi-assignTại sao? Việc nối chuỗi các phép gán tạo ra các biến toàn cục ngầm định.
// không tốt(functionexample(){// JavaScript diễn giải điều này như// let a = ( b = ( c = 1 ) );// Từ khóa let chỉ áp dụng đối với biến a; các biến b và c sẽ trở thành// các biến toàn cục.leta=b=c=1;}());console.log(a);// ném ra ReferenceErrorconsole.log(b);// 1console.log(c);// 1// tốt(functionexample(){leta=1;letb=a;letc=a;}());console.log(a);// ném ra ReferenceErrorconsole.log(b);// ném ra ReferenceErrorconsole.log(c);// ném ra ReferenceError// điều tương tự áp dụng với `const`
13.6 Tránh việc sử dụng các phép tăng và giảm một ngôi (
++,--). eslintno-plusplusTại sao? Theo như tài liệu của eslint, các phép tăng hoặc giảm một ngôi phụ thuộc vào Quy tắc thêm dấu chấm phẩy tự động và có thể gây ra các lỗi câm trong việc tăng hoặc giảm các giá trị trong một ứng dụng. Sự diễn đạt cũng trở nên rõ ràng hơn khi bạn biến đổi các giá trị với các lệnh, như
num += 1, thay vìnum++haynum ++. Việc không cho phép các lệnh tăng hoặc giảm một ngôi cũng giúp bạn tránh được các sự tiền tăng/tiền giảm các giá trị một cách không chủ ý, điều có thể cũng gây ra những hành vi không mong muốn cho chương trình của bạn.// không tốtconstarray=[1,2,3];letnum=1;num++;--num;letsum=0;lettruthyCount=0;for(leti=0;i<array.length;i++){letvalue=array[i];sum+=value;if(value){truthyCount++;}}// tốtconstarray=[1,2,3];letnum=1;num+=1;num-=1;constsum=array.reduce((a,b)=>a+b,0);consttruthyCount=array.filter(Boolean).length;
13.7 Tránh các dấu ngắt dòng trước và sau
=trong một phép gán. Nếu phép gán của bạn vi phạmmax-len, hãy đặt giá trị trong ngoặc tròn. eslintoperator-linebreak.Tại sao? Các dấu ngắt dòng quanh
=có thể làm mờ nhạt giá trị trong phép gán.// không tốtconstfoo=superLongLongLongLongLongLongLongLongFunctionName();// không tốtconstfoo='một chuỗi rất rất rất rất rất rất rất rất rất rất là dài';// tốtconstfoo=(superLongLongLongLongLongLongLongLongFunctionName());// tốtconstfoo='một chuỗi rất rất rất rất rất rất rất rất rất rất là dài';
13.8 Không cho phép các biến không được sử dụng. eslint:
no-unused-varsTại sao? Các biến được khai báo nhưng không được sử dụng ở khắp mọi nơi trong mã gần như chắc chắn là một lỗi do sự cải tiến mã nguồn chưa hoàn thiện. Những biến như vậy chiếm chỗ trong mã và có thể gây ra sự khó hiểu cho người đọc.
// không tốtvarsome_unused_var=42;// Các biến chỉ-viết không được coi là đã được sử dụng.vary=10;y=5;// Một phép đọc để sửa chính nó không được coi là đã sử dụng.varz=0;z=z+1;// Đối số không được sử dụng.functiongetX(x,y){returnx;}// tốtfunctiongetXPlusY(x,y){returnx+y;}varx=1;vary=a+2;alert(getXPlusY(x,y));// 'type' được bỏ qua kể cả khi nó không được sử dụng vì còn có// các thuộc tính đồng đẳng còn-lại.// Đây là một cách để trích xuất một đối tượng mà bỏ qua một vài thuộc tính.var{ type, ...coords}=data;// 'coords' bây giờ là 'data' đã loại bỏ thuộc tính 'type'.
14.1 Các khai báo bằng
varđược kéo lên đầu của phạm vi hàm gần nhất, còn phép gán thì không. Các khai báo bằngconstvàletthì mang trên mình một đặc tính khác làGiai đoạn chết. Điều này là quan trọng để biết tại saotypeofkhông còn an toàn.// chúng ta biết thứ này sẽ không hoạt động (giả định rằng// không có biến toàn cục nào tên là notDefined)functionexample(){console.log(notDefined);// => ném ra ReferenceError}// việc khai báo một biến sau khi bạn// sử dụng biến đó vẫn sẽ chạy bởi vì// sự nổi lên của biến. Lưu ý: phép gán// giá trị `true` không được kéo lên.functionexample(){console.log(declaredButNotAssigned);// => undefinedvardeclaredButNotAssigned=true;}// trình biên dịch sẽ kéo khai báo biến// lên trên đầu của phạm vi hàm,// điều này có nghĩa là ví dụ trên có thể được viết là:functionexample(){letdeclaredButNotAssigned;console.log(declaredButNotAssigned);// => undefineddeclaredButNotAssigned=true;}// dùng const và letfunctionexample(){console.log(declaredButNotAssigned);// => ném ra ReferenceErrorconsole.log(typeofdeclaredButNotAssigned);// => ném ra ReferenceErrorconstdeclaredButNotAssigned=true;}
14.2 Các biểu thức hàm vô danh sẽ được kéo tên biến lên, nhưng không được kéo phép gán hàm.
functionexample(){console.log(anonymous);// => undefinedanonymous();// => TypeError anonymous is not a functionvaranonymous=function(){console.log('biểu thức hàm vô danh');};}
14.3 Biểu thức hàm hữu danh sẽ được kéo tên biến lên, nhưng không được kéo tên hàm và thân hàm.
functionexample(){console.log(named);// => undefinednamed();// => TypeError named is not a functionsuperPower();// => ReferenceError superPower is not definedvarnamed=functionsuperPower(){console.log('Nhìn tui đang bay nè');};}// điều tương tự cũng đúng nếu// tên hàm là trùng với tên biến.functionexample(){console.log(named);// => undefinednamed();// => TypeError named is not a functionvarnamed=functionnamed(){console.log('named');};}
14.4 Khai báo hàm được kéo cả tên và thân hàm lên.
functionexample(){superPower();// => Nhìn tui đang bay nèfunctionsuperPower(){console.log('Nhìn tui đang bay nè');}}
Để tìm hiểu thêm, tham khảo bài viếtJavaScript Scoping & Hoisting bởiBen Cherry.
15.2 Các câu lệnh điều kiện như lệnh
ifxét biểu thức của chúng bằng cách ép kiểu bằng một phương thức ảoToBooleanvà đều tuân theo những quy tắc đơn giản sau:- Các đối tượng tương đương vớitrue
- Undefined tương đương vớifalse
- Null tương đương vớifalse
- Các boolean tương đương vớigiá trị của boolean
- Các số tương đương vớifalse nếu là+0, -0, hoặc NaN, còn không sẽ làtrue
- Các chuỗi tương đương vớivfalse nếu là một chuỗi rỗng
'', còn không sẽ làtrue
if([0]&&[]){// true// một mảng (dù là mảng rỗng) là một đối tượng,// mà đối tượng luôn tương đương với true}
15.3 Sử dụng dạng rút gọn cho các boolean, nhưng dùng dạng so sánh cụ thể đối với chuỗi và số.
// không tốtif(isValid===true){// ...}// tốtif(isValid){// ...}// không tốtif(name){// ...}// tốtif(name!==''){// ...}// không tốtif(collection.length){// ...}// tốtif(collection.length>0){// ...}
- 15.4 Để biết thêm chi tiết, xem bài viếtTruth Equality and JavaScript bởi Angus Croll.
15.5 Sử dụng các dấu ngoặc cho các khối của mệnh đề
casevàdefaultnếu nó có chứa các khai báo (nhưlet,const,function, vàclass). eslint:no-case-declarationsTại sao? Các khai báo tồn tại trong cả khối
switchnhưng chỉ được khởi tạo khi được gán, mà nó chỉ xảy ra khicasecủa nó xảy ra. Điều này gây ra các lỗi khi mà nhiều mệnh đềcasemuốn định nghĩa cùng một thứ.// không tốtswitch(foo){case1:letx=1;break;case2:consty=2;break;case3:functionf(){// ...}break;default:classC{}}// tốtswitch(foo){case1:{letx=1;break;}case2:{consty=2;break;}case3:{functionf(){// ...}break;}case4:bar();break;default:{classC{}}}
15.6 Các toán tử ba ngôi không nên được đặt trong ngoặc và thường được viết trên một dòng riêng. eslint:
no-nested-ternary// không tốtconstfoo=maybe1>maybe2 ?"hi hi" :value1>value2 ?"hi hi" :null;// chia thành hai biểu thức ba ngôi riêng biệt// là tốt nhấtconstmaybeNull=value1>value2 ?'hi hi' :null;constfoo=maybe1>maybe2 ?'hi hi' :maybeNull;
15.7 Tránh các câu lệnh ba ngôi không đáng có. eslint:
no-unneeded-ternary// không tốtconstfoo=a ?a :b;constbar=c ?true :false;constbaz=c ?false :true;// tốtconstfoo=a||b;constbar=!!c;constbaz=!c;
15.8 Khi kết hợp các toán tử, nhớ đóng chúng trong ngoặc. Ngoại lệ duy nhất là các toán tử tiêu chuẩn:
+,-và**vì chúng có thứ tự ưu tiên mà ai ai cũng hiểu. Chúng tôi khuyến khích việc sử dụng đóng ngoặc cho/và*vì thứ tự ưu tiên của chúng có thể bị nhầm lẫn khi chúng được sử dụng gần nhau. eslint:no-mixed-operatorsTại sao? Điều này cả thiện tính khả đọc và làm rõ ý định của nhà phát triển.
// không tốtconstfoo=a&&b<0||c>0||d+1===0;// không tốtconstbar=a**b-5%d;// không tốt// ai đó có thể bị rối và nghĩ nó là (a || b) && cif(a||b&&c){returnd;}// không tốtconstbar=a+b/c*d;// tốtconstfoo=(a&&b<0)||c>0||(d+1===0);// tốtconstbar=a**b-(5%d);// tốtif(a||(b&&c)){returnd;}// tốtconstbar=a+(b/c)*d;
16.1 Sử dụng các dấu ngoặc cho các khối nhiều dòng. eslint:
nonblock-statement-body-position// không tốtif(test)returnfalse;// tốtif(test)returnfalse;// tốtif(test){returnfalse;}// không tốtfunctionfoo(){returnfalse;}// tốtfunctionbar(){returnfalse;}
16.2 Nếu bạn đang sử dụng các khối nhiều dòng với
ifvàelse, đặtelsetrên cùng dòng với dấu đóng ngoặc của khốiif. eslint:brace-style// không tốtif(test){thing1();thing2();}else{thing3();}// tốtif(test){thing1();thing2();}else{thing3();}
16.3 Nếu một khối
ifluôn thực hiện lệnhreturn, những khốielsetiếp theo là không cần thiết. Một lệnhreturntrong một khốielse iftheo sau một khốiifmà có chứareturncó thể được tách thành nhiều khốiif. eslint:no-else-return// không tốtfunctionfoo(){if(x){returnx;}else{returny;}}// không tốtfunctioncats(){if(x){returnx;}elseif(y){returny;}}// không tốtfunctiondogs(){if(x){returnx;}else{if(y){returny;}}}// tốtfunctionfoo(){if(x){returnx;}returny;}// tốtfunctioncats(){if(x){returnx;}if(y){returny;}}// tốtfunctiondogs(x){if(x){if(z){returny;}}else{returnz;}}
17.1 Nếu trong trường hợp lệnh điều khiển (
if,while, v.v.) của bạn trở lên quá dài và vượt quá giới hạn độ dài dòng, mỗi (nhóm) điều kiện có thể được đặt ở một dòng mới. Toán tử lô-gíc nên được đặt ở đầu dòng.Tại sao? Việc đặt các toán tử ở đầu dòng giúp các toán tử được căn đều và tuân theo cùng một mô hình với việc nối chuỗi phương thức. Điều này cũng cải thiện tính khả đọc vì khiến cho việc theo dõi một lô-gíc phức tạp trở nên đơn giản hơn.
// không tốtif((foo===123||bar==='abc')&&doesItLookGoodWhenItBecomesThatLong()&&isThisReallyHappening()){thing1();}// không tốtif(foo===123&&bar==='abc'){thing1();}// không tốtif(foo===123&&bar==='abc'){thing1();}// không tốtif(foo===123&&bar==='abc'){thing1();}// tốtif(foo===123&&bar==='abc'){thing1();}// tốtif((foo===123||bar==='abc')&&doesItLookGoodWhenItBecomesThatLong()&&isThisReallyHappening()){thing1();}// tốtif(foo===123&&bar==='abc'){thing1();}
17.2 Không sử dụng toán tử lựa chọn thay cho các câu lệnh điều khiển.
// không tốt!isRunning&&startRunning();// tốtif(!isRunning){startRunning();}
18.1 Sử dụng
/** ... */cho các chú thích nhiều dòng.// không tốt// make() trả về một phần tử// dựa trên tag được truyền vào////@param {String} tag//@return {Element} elementfunctionmake(tag){// ...returnelement;}// tốt/** * make() trả về một phần tử * dựa trên tag được truyền vào */functionmake(tag){// ...returnelement;}
18.2 Sử dụng
//cho các chú thích một dòng. Đặt các chú thích một dòng ở một dòng riêng, bên trên chủ đề của chú thích. Để một dòng trống trước chú thích trừ khi chú thích là dòng đầu tiên của một khối.// không tốtconstactive=true;// là thẻ hiện tại// tốt// là thẻ hiện tạiconstactive=true;// không tốtfunctiongetType(){console.log('đang lấy loại...');// đặt loại mặc định là 'không phân loại'consttype=this.type||'không phân loại';returntype;}// tốtfunctiongetType(){console.log('đang lấy loại...');// đặt loại mặc định là 'không phân loại'consttype=this.type||'không phân loại';returntype;}// như này cũng tốtfunctiongetType(){// đặt loại mặc định là 'không phân loại'consttype=this.type||'không phân loại';returntype;}
18.3 Bắt đầu tất cả các chú thích bằng một dấu cách để dễ đọc hơn. eslint:
spaced-comment// không tốt//là thẻ hiện tạiconstactive=true;// tốt// là thẻ hiện tạiconstactive=true;// không tốt/** *make() trả về một phần tử *dựa trên tag được truyền vào */functionmake(tag){// ...returnelement;}// tốt/** * make() trả về một phần tử * dựa trên tag được truyền vào */functionmake(tag){// ...returnelement;}
- 18.4 Thêm
FIXMEhoặcTODOvào đầu chú thích giúp các nhà phát triển dễ dàng biết được rằng bạn đang chỉ ra một vấn đề cần được xem lại, hoặc bạn đang đề xuất cách giải quyết cho vấn đề nên mà được áp dụng. Các hành động có thể nhưFIXME: -- cần xem xét về thứ nàyhoặcTODO: -- cần áp dụng.
18.5 Sử dụng
// FIXME:để chú giải các vấn đề.classCalculatorextendsAbacus{constructor(){super();// FIXME: không nên dùng biến toàn cục ở đâytotal=0;}}
18.6 Sử dụng
// TODO:để chú giải các cách giải quyết cho các vấn đề.classCalculatorextendsAbacus{constructor(){super();// TODO: giá trị của total nên được chuyển thành tham sốthis.total=0;}}
19.1 Sử dụng các tab ngắn (dấu cách) đặt về 2 dấu cách. eslint:
indent// không tốtfunctionfoo(){∙∙∙∙letname;}// không tốtfunctionbar(){∙letname;}// tốtfunctionbaz(){∙∙letname;}
19.2 Đặt 1 cách trước dấu mở ngoặc. eslint:
space-before-blocks// không tốtfunctiontest(){console.log('ví dụ');}// tốtfunctiontest(){console.log('ví dụ');}// không tốtdog.set('attr',{age:'1 năm',breed:'Chó núi Bern',});// tốtdog.set('attr',{age:'1 năm',breed:'Chó núi Bern',});
19.3 Đặt 1 dấu cách trước dấu mở ngoặc tròn của các lệnh điều khiển (
if,while, v.v.). Không đặt dấu cách giữa danh sách đối số và tên hàm trong các phép gọi và khai báo hàm. eslint:keyword-spacing// không tốtif(isJedi){fight();}// tốtif(isJedi){fight();}// không tốtfunctionfight(){console.log('Uiiiiii!');}// tốtfunctionfight(){console.log('Uiiiiii!');}
19.4 Đặt dấu cách trước và sau các toán tử. eslint:
space-infix-ops// không tốtconstx=y+5;// tốtconstx=y+5;
19.5 Kết thúc tệp với một dấu ngắt dòng. eslint:
eol-last// không tốtimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;
// không tốtimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;↵↵
// tốtimport{es6}from'./AirbnbStyleGuide';// ...exportdefaultes6;↵
19.6 Căn đầu dòng khi tạo các chuỗi phương thức (nhiều hơn 2 chuỗi phương thức). Đặt dấu chấm ở đầu, để nhấn mạnh dòng này là một phép gọi phương thức, không phải là một câu lệnh mới. eslint:
newline-per-chained-callno-whitespace-before-property// không tốt$('#items').find('.selected').highlight().end().find('.open').updateCount();// không tốt$('#items').find('.selected').highlight().end().find('.open').updateCount();// tốt$('#items').find('.selected').highlight().end().find('.open').updateCount();// không tốtconstleds=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);// tốtconstleds=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);// tốtconstleds=stage.selectAll('.led').data(data);constsvg=leds.enter().append('svg:svg');svg.classed('led',true).attr('width',(radius+margin)*2);constg=svg.append('svg:g');g.attr('transform',`translate(${radius+margin},${radius+margin})`).call(tron.led);
19.7 Để một dòng trống sau mỗi khối và trước câu lệnh tiếp theo.
// không tốtif(foo){returnbar;}returnbaz;// tốtif(foo){returnbar;}returnbaz;// không tốtconstobj={foo(){},bar(){},};returnobj;// tốtconstobj={foo(){},bar(){},};returnobj;// không tốtconstarr=[functionfoo(){},functionbar(){},];returnarr;// tốtconstarr=[functionfoo(){},functionbar(){},];returnarr;
19.8 Không kê các khối với các dòng trống. eslint:
padded-blocks// không tốtfunctionbar(){console.log(foo);}// không tốtif(baz){console.log(qux);}else{console.log(foo);}// không tốtclassFoo{constructor(bar){this.bar=bar;}}// tốtfunctionbar(){console.log(foo);}// tốtif(baz){console.log(qux);}else{console.log(foo);}
19.9 Do not use multiple blank lines to pad your code. eslint:
no-multiple-empty-lines// không tốtclassPerson{constructor(fullName,email,birthday){this.fullName=fullName;this.email=email;this.setAge(birthday);}setAge(birthday){consttoday=newDate();constage=this.getAge(today,birthday);this.age=age;}getAge(today,birthday){// ..}}// tốtclassPerson{constructor(fullName,email,birthday){this.fullName=fullName;this.email=email;this.setAge(birthday);}setAge(birthday){consttoday=newDate();constage=getAge(today,birthday);this.age=age;}getAge(today,birthday){// ..}}
19.10 Không thêm các dấu cách trong dấu ngoặc tròn. eslint:
space-in-parens// không tốtfunctionbar(foo){returnfoo;}// tốtfunctionbar(foo){returnfoo;}// không tốtif(foo){console.log(foo);}// tốtif(foo){console.log(foo);}
19.11 Không thêm các dấu cách trong các dấu ngoặc vuông. eslint:
array-bracket-spacing// không tốtconstfoo=[1,2,3];console.log(foo[0]);// tốtconstfoo=[1,2,3];console.log(foo[0]);
19.12 Thêm các dấu cách giữa các dấu ngoặc nhọn. eslint:
object-curly-spacing// không tốtconstfoo={clark:'kent'};// tốtconstfoo={clark:'kent'};
19.13 Tránh các dòng mã có nhiều hơn 100 ký tự (kể cả khoảng trắng). Lưu ý: theo nhưtrên đây, các chuỗi được loại trừ bởi quy tắc này, và bạn không nên chia chúng ra. eslint:
max-lenTại sao? Điều này đảm bảo tính khả đọc và khả năng bảo trì.
// không tốtconstfoo=jsonData&&jsonData.foo&&jsonData.foo.bar&&jsonData.foo.bar.baz&&jsonData.foo.bar.baz.quux&&jsonData.foo.bar.baz.quux.xyzzy;// không tốt$.ajax({method:'POST',url:'https://airbnb.com/',data:{name:'John'}}).done(()=>console.log('Chúc mừng!')).fail(()=>console.log('You have failed this city.'));// tốtconstfoo=jsonData&&jsonData.foo&&jsonData.foo.bar&&jsonData.foo.bar.baz&&jsonData.foo.bar.baz.quux&&jsonData.foo.bar.baz.quux.xyzzy;// tốt$.ajax({method:'POST',url:'https://airbnb.com/',data:{name:'John'},}).done(()=>console.log('Chúc mừng!')).fail(()=>console.log('You have failed this city.'));
19.14 Đảm bảo sự nhất quán về dấu cách sau dấu mở ngoặc và trước ký tự đầu tiên sau nó trên cùng một dòng. Quy tắc này cũng yêu cầu sự nhất quán về dấu cách trước dấu đóng ngoặc và sau ký tự cuối cùng trước nó trên cùng một dòng. eslint:
block-spacing// không tốtfunctionfoo(){returntrue;}if(foo){bar=0;}// tốtfunctionfoo(){returntrue;}if(foo){bar=0;}
19.15 Không sử dụng dấu cách trước dấu phẩy và phải sử dụng dấu cách sau dấu phẩy. eslint:
comma-spacing// không tốtvarfoo=1,bar=2;vararr=[1,2];// tốtvarfoo=1,bar=2;vararr=[1,2];
19.16 Không đặt dấu cách bên trong dấu ngoặc của thuộc tính được tính. eslint:
computed-property-spacing// không tốtobj[foo]obj['foo']varx={[b]:a}obj[foo[bar]]// tốtobj[foo]obj['foo']varx={[b]:a}obj[foo[bar]]
19.17 Tránh sử dụng dấu cách giữa các hàm và phép gọi chúng. eslint:
func-call-spacing// không tốtfunc();func();// tốtfunc();
19.18 Đặt dấu cách giữa các tên và giá trị của các thuộc tính nguyên văn. eslint:
key-spacing// không tốtvarobj={foo :42};varobj2={foo:42};// tốtvarobj={foo:42};
- 19.19 Tránh các dấu cách ở cuối các dòng. eslint:
no-trailing-spaces
19.20 Tránh để nhiều dòng trống liên tiếp, chỉ để một dòng trống ở cuối tệp, và không để dòng trống ở đầu tệp. eslint:
no-multiple-empty-lines// không tốt - nhiều dòng trống liên tiếpvarx=1;vary=2;// bad - 2+ dòng trống ở cuối tệpvarx=1;vary=2;// không tốt - 1+ dòng trống ở đầu tệpvarx=1;vary=2;// tốtvarx=1;vary=2;
20.1 Các dấu phẩy ở đầu:Đừng! eslint:
comma-style// không tốtconststory=[once,upon,aTime];// tốtconststory=[once,upon,aTime,];// không tốtconsthero={firstName:'Ada',lastName:'Lovelace',birthYear:1815,superPower:'máy tính'};// tốtconsthero={firstName:'Ada',lastName:'Lovelace',birthYear:1815,superPower:'máy tính',};
20.2 Thêm một dấu phẩy ở cuối:Đúng đó! eslint:
comma-dangleTại sao? Điều này làm cho các so sánh git gọn gàng hơn. Ngoài ra, các trình dịch mã như Babel sẽ xóa các dấu phẩy ở cuối trong mã được dịch, có nghĩa là bạn không cần lo lắng vềvấn đề của dấu phẩy ở cuối trên các trình duyệt cũ.
// không tốt - so sánh git khi không có dấu phẩy ở cuốiconst hero = { firstName: 'Florence',- lastName: 'Nightingale'+ lastName: 'Nightingale',+ inventorOf: ['coxcomb chart', 'modern nursing']};// tốt - so sánh git khi có các dấu phẩy ở cuốiconst hero = { firstName: 'Florence', lastName: 'Nightingale',+ inventorOf: ['coxcomb chart', 'modern nursing'],};// không tốtconsthero={firstName:'Dana',lastName:'Scully'};constheroes=['Batman','Superman'];// tốtconsthero={firstName:'Dana',lastName:'Scully',};constheroes=['Batman','Superman',];// không tốtfunctioncreateHero(firstName,lastName,inventorOf){// không làm gì cả}// tốtfunctioncreateHero(firstName,lastName,inventorOf,){// không làm gì cả}// tốt (lưu ý là không được đặt dấu phẩy sau phần từ "còn-lại")functioncreateHero(firstName,lastName,inventorOf, ...heroArgs){// không làm gì cả}// không tốtcreateHero(firstName,lastName,inventorOf);// tốtcreateHero(firstName,lastName,inventorOf,);// tốt (lưu ý là không được đặt dấu phẩy sau phần từ "còn-lại")createHero(firstName,lastName,inventorOf, ...heroArgs);
Tại sao? Khi JavaScript gặp một dấu ngắt dòng mà không có dấu chấm phẩy, nó sử dụng một bộ quy tắc gọi làQuy tắc thêm dấu chấm phẩy tự động để xác định xem dấu ngắt dòng có phải là kết thúc của một câu lệnh hay không, và (như cái tên gợi ý) đặt một dấu chấn phẩy vào mã của bạn, trước dấu ngắt dòng, nếu nó cho rằng nên làm vậy. Quy tắc thêm dấu chấm phẩy tự động có một vài hành vi lập dị, và mã của bạn sẽ hỏng nếu JavaScript hiểu sai dấu ngắt dòng của bạn. Những quy tắc này ngày càng trở nên phức tạp khi các tính năng mới được bổ sung vào JavaScript. Việc kết thúc các câu lệnh một cách rõ ràng và thiết lập trình phân tích mã của bạn bắt các lỗi thiếu dấu phẩy sẽ giúp bạn tránh được các vấn đề.
// không tốt - ném ra một ngoại lệconstluke={}constleia={}[luke,leia].forEach((jedi)=>jedi.father='vader')// không tốt - ngém ra một ngoại lệconstreaction="Không! Không thể nào!"(asyncfunctionmeanwhileOnTheFalcon(){// xử lý `leia`, `lando`, `chewie`, `r2`, `c3p0`// ...}())// không tốt - trả về `undefined` thay vì giá trị ở dòng tiếp theo - điều luôn xảy ra khi `return` nằm một mình một dòng, do Quy tắc thêm dấu chấm phẩy tự động!functionfoo(){return'search your feelings, you know it to be foo'}// tốtconstluke={};constleia={};[luke,leia].forEach((jedi)=>{jedi.father='vader';});// tốtconstreaction="Không! Không thể nào!";(asyncfunctionmeanwhileOnTheFalcon(){// xử lý `leia`, `lando`, `chewie`, `r2`, `c3p0`// ...}());// tốtfunctionfoo(){return'search your feelings, you know it to be foo';}
- 22.1 Thực hiện ép kiểu ở đầu mỗi câu lệnh.
22.2 Đối với các chuỗi: eslint:
no-new-wrappers// => this.reviewScore = 9;// không tốtconsttotalScore=newString(this.reviewScore);// typeof totalScore là "object", không phải "string"// không tốtconsttotalScore=this.reviewScore+'';// cái này gọi this.reviewScore.valueOf()// không tốtconsttotalScore=this.reviewScore.toString();// không chắc chắn sẽ thu được một chuỗi// tốtconsttotalScore=String(this.reviewScore);
- 22.3 Đối với các số: Sử dụng
Numberđể ép kiểu vàparseIntluôn phải được dùng với một cơ số. eslint:radixno-new-wrappers
Tại sao? Hàm
parseIntsinh ra một số nguyên bằng cách diễn giải nội dung của một chuỗi dựa trên một cơ số đã định. Ký tự trống ở đầu chuỗi được bỏ qua. Nếu cơ số làundefinedhoặc0, cơ số đó được ngầm định là10, trừ trường hợp số trong chuỗi bắt đầu bằng cặp ký tự0xhoặc0X, khi đó cơ số16được sử dụng. Điều này khác với ECMAScript 3, khi nó chỉ không khuyến khích (nhưng cho phép) sử dụng diễn giải số theo hệ bát phân. Nhiều trình duyệt chưa áp dụng theo điều trên kể từ 2013. Và, vì những trình duyệt cũ cũng cần được hỗ trợ, hãy luôn sử dụng một cơ số.
``` javascriptconst inputValue = '4';// không tốtconst val = new Number(inputValue);// không tốtconst val = +inputValue;// không tốtconst val = inputValue >> 0;// không tốtconst val = parseInt(inputValue);// tốtconst val = Number(inputValue);// tốtconst val = parseInt(inputValue, 10);```22.4 Nếu, vì bất cứ lý do gì, bạn đang làm một điều gì đó thật điên và bạn gặp nghẽn cổ chai do
parseInt, và bạn cần sử dụng phép dịch chuyển bit vìcác lý do hiệu suất, nhớ để lại một chú thích để giải thích về thứ bạn đang làm và tại sao bạn làm vậy.// tốt/** * parseInt là lý do khiến mã của tôi chạy chậm. * Việc áp dụng phép dịch chuyển bit cho một chuỗi * để ép nó sang kiểu số nhanh hơn nhiều. */constval=inputValue>>0;
22.5Lưu ý: Cẩn thận khi sử dụng các phép dịch chuyển bit. Các số được biểu diễn dưới dạng cácgiá trị 64-bit, nhưng các phép dịch chuyển bit luôn trả về một số nguyên 32-bit (nguồn). Phép dịch chuyển bit cũng có thể dẫn đến các hành vi không mong đợi đối với các giá trị lớn hơn 32 bit.Cuộc thảo luận. Số nguyên có dấu 32-bit lớn nhất là 2,147,483,647:
2147483647>>0;// => 21474836472147483648>>0;// => -21474836482147483649>>0;// => -2147483647
22.6 Đối với các boolean: eslint:
no-new-wrappersconstage=0;// không tốtconsthasAge=newBoolean(age);// tốtconsthasAge=Boolean(age);// tốt nhấtconsthasAge=!!age;
23.1 Tránh sử dụng các tên chỉ có một chữ cái. Hãy đặt những cái tên thật ý nghĩa. eslint:
id-length// không tốtfunctionq(){// ...}// tốtfunctionquery(){// ...}
23.2 Sử dụng camelCase khi đặt tên các đối tượng, các hàm và các thực thể. eslint:
camelcase// không tốtconstOBJEcttsssss={};constthis_is_my_object={};functionc(){}// tốtconstthisIsMyObject={};functionthisIsMyFunction(){}
23.3 Sử dụng PascalCase chỉ khi đặt tên các hàm tạo hay các lớp. eslint:
new-cap// không tốtfunctionuser(options){this.name=options.name;}constbad=newuser({name:'đừnggg',});// tốtclassUser{constructor(options){this.name=options.name;}}constgood=newUser({name:'đúng nè',});
23.4 Không sử dụng các dấu gạch dưới ở đằng trước hoặc đằng sau. eslint:
no-underscore-dangleTại sao? JavaScript không có khái niệm về tính riêng tư khi nói đến các thuộc tính hay các phương thức. Tuy rằng một dấu gạch dưới đặt ở đằng trước là một quy ước chung mang nghĩa “riêng tư”, thực tế, các thuộc tính trên đều hoàn toàn công khai, và vì vậy, là các thành phần trong API của bạn. Quy ước này có thể khiến các nhà phát triển nghĩ, một cách sai lầm, rằng một sự thay đổi chẳng làm hỏng điều gì, hoặc không cần thiết phải kiểm thử. tl;dr: nếu bạn muốn thứ gì đó thật “riêng tư”, sự tồn tại của nó phải được giấu đi.
// không tốtthis.__firstName__='Panda';this.firstName_='Panda';this._firstName='Panda';// tốtthis.firstName='Panda';// tốt, đối với các môi trường hỗ trợ WeakMap// xem https://kangax.github.io/compat-table/es6/#test-WeakMapconstfirstNames=newWeakMap();firstNames.set(this,'Panda');
23.5 Đừng lưu các tham chiếu đến
this. Hãy sử dụng hàm mũi tên hoặcFunction#bind.// không tốtfunctionfoo(){constself=this;returnfunction(){console.log(self);};}// không tốtfunctionfoo(){constthat=this;returnfunction(){console.log(that);};}// tốtfunctionfoo(){return()=>{console.log(this);};}
23.6 Phần tên của một tên tệp nên giống với địa chỉ xuất mặc định của tệp đó.
// file 1 contentsclassCheckBox{// ...}exportdefaultCheckBox;// file 2 contentsexportdefaultfunctionfortyTwo(){return42;}// file 3 contentsexportdefaultfunctioninsideDirectory(){}// in some other file// không tốtimportCheckBoxfrom'./checkBox';// nhập PascalCase, tên camelCaseimportFortyTwofrom'./FortyTwo';// nhập/tên PascalCase, xuất camelCaseimportInsideDirectoryfrom'./InsideDirectory';// nhập/tên PascalCase, xuất camelCase// không tốtimportCheckBoxfrom'./check_box';// nhập/xuất PascalCase, tên snake_caseimportforty_twofrom'./forty_two';// nhập/tên snake_case, xuất camelCaseimportinside_directoryfrom'./inside_directory';// nhập snake_case, xuất camelCaseimportindexfrom'./inside_directory/index';// ghi tên tệp indeximportinsideDirectoryfrom'./insideDirectory/index';// ghi tên tệp index// tốtimportCheckBoxfrom'./CheckBox';// xuất/nhập/tên PascalCaseimportfortyTwofrom'./fortyTwo';// xuất/nhập/tên camelCaseimportinsideDirectoryfrom'./insideDirectory';// xuất/nhập/tên camelCase; ngầm định "index"// ^ hỗ trợ cả insideDirectory.js và insideDirectory/index.js
23.7 Sử dụng camelCase khi xuất mặc định một hàm. Tên tệp nên trùng với tên hàm.
functionmakeStyleGuide(){// ...}exportdefaultmakeStyleGuide;
23.8 Sử dụng PascalCase khi xuất mặc định một hàm tạo / lớp / đối tượng độc nhật / một thư viện các hàm / đối tượng trần.
constAirbnbStyleGuide={es6:{},};exportdefaultAirbnbStyleGuide;
23.9 Các từ viết tắt nên được viết hoa hoặc viết thường toàn bộ.
Tại sao? Các tên dùng để đọc, không phải để giải thích thuật toán.
// không tốtimportSmsContainerfrom'./containers/SmsContainer';// không tốtconstHttpRequests=[// ...];// tốtimportSMSContainerfrom'./containers/SMSContainer';// tốtconstHTTPRequests=[// ...];// như này cũng tốtconsthttpRequests=[// ...];// tốt nhấtimportTextMessageContainerfrom'./containers/TextMessageContainer';// tốt nhấtconstrequests=[// ...];
23.10 Bạn có chọn viết hoa một hằng chỉ khi hằng đó (1) được xuất, và (2) một lập trình viên có thể tin tưởng rằng nó (và các thuộc tính của nó) là bất biến.
Tại sao? Đây là một công cụ khác để hỗ trợ chúng ta trong các hoàn cảnh mà một lập trình viên có thể không chắc chắn là một biến có bị thay đổi hay chưa. UPPERCASE_VARIABLES đang cho lập trình viên đó biết là biến này (và thuộc tính của nó) không có thay đổi gì hết.
- Thế còn các
const? - Điều này là không cần thiết, vì việc viết hoa không nên được sử dụng cho các hằng ở trong cùng một tệp. Nó chỉ nên dùng cho các hằng được xuất. - Thế còn một đối tượng được xuất thì sao? - Chỉ viết hoa ở hàng cao nhất của đối tượng xuất (kiểu như:
EXPORTED_OBJECT.key) và đảm bảo rằng những thuộc tính của nó không thay đổi.
// không tốtconstPRIVATE_VARIABLE='không nên viết hoa bừa bãi các biến trong một tệp';// không tốtexportconstTHING_TO_BE_CHANGED='rõ ràng không nên viết hoa';// không tốtexportletREASSIGNABLE_VARIABLE='đừng có sử dụng let với tên viết hóa';// ---// được cho phép, nhưng không không rõ về mặt ngữ nghĩaexportconstapiKey='SOMEKEY';// tốt hơn hầu hết các trường hợp khácexportconstAPI_KEY='SOMEKEY';// ---// không tốt - viết hoa không cần thiết chẳng cung cấp gì trị gì về mặt ngữ nghĩaexportconstMAPPING={KEY:'giá trị'};// tốtexportconstMAPPING={key:'giá trị'};
- Thế còn các
- 24.1 Các hàm truy cập cho các thuộc tình là không bắt buộc.
24.2 Không sử dụng hàm đọc/hàm ghi của JavaScript vì chúng gây ra các hiệu ứng phụ không mong muốn và khó để kiểm thử, bảo trì, và hình dung. Thay vào đó, nếu bạn muốn tạo hàm truy cập, sử dụng
getVal()vàsetVal('hello').// không tốtclassDragon{getage(){// ...}setage(value){// ...}}// tốtclassDragon{getAge(){// ...}setAge(value){// ...}}
24.3 Nếu thuộc tính/phương thức là một
boolean, dùngisVal()hoặchasVal().// không tốtif(!dragon.age()){returnfalse;}// tốtif(!dragon.hasAge()){returnfalse;}
24.4 Có thể dùng các hàm
get()vàset(), nhưng nhớ là phải nhất quán.classJedi{constructor(options={}){constlightsaber=options.lightsaber||'xanh dương';this.set('lightsaber',lightsaber);}set(key,val){this[key]=val;}get(key){returnthis[key];}}
25.1 Khi gắn các trọng tải dữ liệu cho các sự kiện (dù là các sự kiện DOM hay thứ gì đó tư hữu hơn như các sự kiện trong Backbone), hãy truyền vào một đối tượng nguyên văn (hay còn gọi là "giá trị băm") thay vì giá trị gốc. Điều này cho phép những người đóng góp sau này có thể thêm dữ liệu vào trọng tải mà không cần phải tìm và cập nhật mỗi hàm xử lý cho sự kiện. Ví dụ, thay vì:
// không tốt$(this).trigger('listingUpdated',listing.id);// ...$(this).on('listingUpdated',(e,listingID)=>{// làm gì đó với listingID});
hãy dùng:
// tốt$(this).trigger('listingUpdated',{listingID:listing.id});// ...$(this).on('listingUpdated',(e,data)=>{// làm gì đó với listingID});
26.1 Bắt đầu các biến lưu các đối tượng jQuery với
$.// không tốtconstsidebar=$('.sidebar');// tốtconst$sidebar=$('.sidebar');// tốtconst$sidebarBtn=$('.sidebar-btn');
26.2 Lưu tạm các truy vấn jQuery.
// không tốtfunctionsetSidebar(){$('.sidebar').hide();// ...$('.sidebar').css({'background-color':'pink',});}// tốtfunctionsetSidebar(){const$sidebar=$('.sidebar');$sidebar.hide();// ...$sidebar.css({'background-color':'pink',});}
- 26.3 Với các truy vấn, hãy sử dụng truy vấn xếp tầng
$('.sidebar ul')hoặc cha > con$('.sidebar > ul').jsPerf
26.4 Sử dụng
findvới một phạm vi đối tượng jQuery cho các truy vấn.// không tốt$('ul','.sidebar').hide();// không tốt$('.sidebar').find('ul').hide();// tốt$('.sidebar ul').hide();// tốt$('.sidebar > ul').hide();// tốt$sidebar.find('ul').hide();
- 27.1 Tham khảobảng tính tương thích ES5 củaKangax.
- 28.1 Đây là một bộ sưu tập các liên kết tới các tính năng khác nhau của ES6+.
- Các Hàm mũi tên
- Các Lớp
- Cú pháp Định nghĩa Phương thức Rút gọn
- Cú pháp Định nghĩa Thuộc tính Rút gọn
- Các Tên Được tính của Thuộc tính
- Các Mẫu chuỗi
- Trích xuất
- Các Tham số Mặc định
- Còn-lại
- Liệt kê Mảng
- Let và Const
- Toán tử Lũy thừa
- Các Đối tượng duyệt và các Hàm sinh trị
- Các Mô-đun
28.2 Không sử dụngcác đề xuất TC39 mà chưa đến giai đoạn 3.
Tại sao?Chúng chưa được hoàn thiện, và chúng có thể thay đổi bất cứ lúc nào hoặc bị rút lại hoàn toàn. Chúng ta muốn sử dụng JavaScript, mà các đề xuất thì chưa phải là JavaScript.
Thư viện tiêu chuẩnchứa các hàm tiện ích không hoạt động đúng lắm nhưng vẫn tồn tại vì các lý do cũ.
29.1 Sử dụng
Number.isNaNthay vì hàm toàn cụcisNaN.eslint:no-restricted-globalsTại sao? Hàm toàn cục
isNaNép các giá trị không phải số thành số và trả về true cho tất cả những gì mà bị ép thành NaN.Nếu đây là hành vi mong muốn, hãy khiến nó được biểu đạt rõ ràng.// không tốtisNaN('1.2');// falseisNaN('1.2.3');// true// tốtNumber.isNaN('1.2.3');// falseNumber.isNaN(Number('1.2.3'));// true
29.2 Sử dụng
Number.isFinitethay vì hàm toàn cụcisFinite.eslint:no-restricted-globalsTại sao? Hàm toàn cục
isFiniteép các giá trị không phải số thành số và trả về true cho tất cả những gì bị ép thành một số mà không phải là vô hạn.Nếu đây là hành vi mong muốn, hãy khiến nó được biểu đạt rõ ràng.// không tốtisFinite('2e3');// true// tốtNumber.isFinite('2e3');// falseNumber.isFinite(parseInt('2e3',10));// true
30.1Có chứ.
functionfoo(){returntrue;}
- 30.2Không, nhưng nghiêm túc này:
- Dù bạn dùng nền tảng kiểm thử nào thì bạn cũng nên viết các kiểm thử!
- Cố gắng viết thật nhiều các hàm thuần, nhỏ và giảm thiểu số các sự biến đổi.
- Cẩn thận với các giả lập mô-đun và đối tượng - chúng có thể khiến các chương trình kiểm thử của bạn dễ vỡ.
- Chúng tôi chủ yếu sử dụng
mochavàjesttại Airbnb.tapecũng đôi khi được sử dụng cho các mô-đun nhỏ và tách biệt. - 100% độ bao phủ kiểm thử là một mục tiêu tốt để phấn đấu, dù không phải lúc nào cũng khả thi.
- Mỗi khi bạn sửa một lỗi,viết một kiểm thử hồi quy. Một lỗi được sửa nhưng không được viết kiểm thử lại gần như chắc chắn sẽ lại hỏng trong tương lai.
- 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
- Are Javascript functions like
map(),reduce(), andfilter()optimized for traversing arrays? - Đang tải...
Học ES6+
Đọc cái này đi
Các công cụ
- Trình phân tích lối viết mã
- Gói Neutrino -@neutrinojs/airbnb
Các Định hướng Lối viết Khác
- Google JavaScript Style Guide
- Google JavaScript Style Guide (Old)
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
- StandardJS
Các Lối viết Khác
- 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
Đọc thêm
- 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
Các Tựa sách
- #"https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752" rel="nofollow">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 #"http://eloquentjavascript.net/" rel="nofollow">Eloquent JavaScript - Marijn Haverbeke
- You Don’t Know JS: ES6 & Beyond - Kyle Simpson
Các Bài viết
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- nettuts
Các Bản phát thanh
Đây là danh sách những tổ chức sử dụng định hướng lối viết này. Gửi cho chúng tôi một yêu cầu kéo và chúng tôi sẽ thêm bạn vào danh sách.
- 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
- Digitpaintdigitpaint/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:natgeo
- NullDev:NullDevCo/JavaScript-Styleguide
- Nulogy:nulogy/javascript
- Orange Hill Development:orangehill/javascript
- Orion Health:orionhealth/javascript
- OutBoxSoft:OutBoxSoft/javascript
- Peerby:Peerby/javascript
- Pier 1:Pier1/javascript
- Qotto:Qotto/javascript-style-guide
- React:facebook.github.io/react/contributing/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
Dưới đây là danh mục các từ tiếng Anh tương ứng của các thuật ngữ, và/hoặc các từ, cụm từ mà thông thường không được dịch, như: "style guide", "object", "polyfill", v.v. Các từ, cụm từ được dịch có thể chỉ đúng trong ngữ cảnh là bản dịch này.
Nếu bạn cảm thấy một thuật ngữ có vẻ được dịch chưa hợp lý, hoặc bạn cần sự giải thích về một thuật ngữ, bạn có thể mở mộtVấn đề để thảo luận.
Nếu bạn biết một từ/cụm từ tiếng Việt thích hợp hơn cho một thuật ngữ, và nếu bạn sẵn lòng, bạn có thể mở mộtĐề nghị kéo cho một sửa đổi.
| Tiếng Việt | English |
|---|---|
| Ánh xạ | Map/mapping |
| Ba ngôi | Ternary |
| Bản sao/sao | Copy |
| Bản sao nhanh/sao nhanh | Shallow-copy |
| Bắt | Catch |
| Bất biến | Immutable |
| Bẻ nhánh | Fork |
| Biến | Variable/var |
| Biến đổi/sự biến đổi | Mutate/mutation |
| Biểu thức | Expression |
| Biểu thức hàm | Function expression |
| Biểu thức hàm gọi tức thời | Immediately invoked function expression/IIFE |
| Bộ khung phần mềm | Framework |
| Bộ phận hàm | Function signature |
| Bộ tải | Loader |
| Bộ tổng hợp | Bundler |
| Bộ trợ năng | Shim/polyfill |
| Bước | Step |
| Cải tiến mã nguồn | Refactor code/code refactoring |
| Căn đầu dòng | Indent |
| Câu lệnh/lệnh | Statement |
| Cấu trúc một dòng | One-liner |
| Chỉ-viết | Write-only |
| Chuỗi | String |
| Chú thích | Comment |
| Còn-lại | Rest |
| Cơ số | Radix |
| Cú pháp | Syntax |
| Cú pháp tiện lợi | Syntactic sugar |
| Cũ | Legacy |
| Dấu gạch dưới | Underscore |
| Dấu lược/dấu nháy đơn | Single quote |
| Dấu ngắt dòng/dấu xuống dòng | Line break |
| Dấu ngoặc | Brace |
| Dấu ngoặc nhọn | Curly brace |
| Dấu ngoặc tròn | Parenthesis/parentheses |
| Dấu ngoặc vuông | Array bracket |
| Dịch mã | Transpile |
| Duyệt | Iterate |
| Đề xuất | Proposal |
| Đề nghị kéo | Pull request |
| Định danh | Identifier |
| Định hướng lối viết | Style guide |
| Định nghĩa | Define |
| Đối số | Argument |
| Đối tượng | Object |
| Đối tượng duyệt | Iterator/iterator object |
| Đối tượng đích | Receiver |
| Đối tượng độc nhất | Singleton |
| Đối tượng khả duyệt | Iterable object |
| Đối tượng rỗng | Null object |
| Đối tượng trần | Bare object |
| Độ bao phủ | Coverage |
| Đường dẫn | Path |
| Ép kiểu/sự ép kiểu | Coerce/coercion/cast/casting |
| Gán/phép gán | Assign/assignment |
| Gán lại | Reassign |
| Ghép | Concatenate/concatenation/concat |
| Giai đoạn chết | Temporal dead zone/TDZ |
| Giá trị băm | Hash/hash value |
| Giá trị gốc | Raw value |
| Giả lập đối tượng | Mock |
| Giả lập mô-đun | Stub |
| Giống-mảng | Array-like |
| Gọi/phép gọi | Call/invoke/invocation |
| Hàm | Function |
| Hàm bất định | Variadic function |
| Hàm bậc cao hơn | Higher-order function |
| Hàm đọc | Getter/getter function |
| Hàm ghi | Setter/setter function |
| Hàm gọi ngược | Callback/callback function |
| Hàm gọi tức thời | Immediately invoked function |
| Hàm hữu danh | Named function |
| Hàm mũi tên | Arrow function |
| Hàm sinh trị | Generator/generator function |
| Hàm tạo | Constructor |
| Hàm thuần | Pure function |
| Hàm tiện ích | Utility/utility function |
| Hàm truy cập | Accessor/accessor function |
| Hàm vô danh | Anonymous function |
| Hàm xử lý | Handler |
| Hằng | Constant/const |
| Hiệu suất | Performance/perf |
| Hiệu ứng phụ | Side effect |
| Kéo lên/sự kéo lên/nổi lên/sự nổi lên | Hoist/hoisting |
| Kê | Pad |
| Khai báo | Declare/declaration |
| Khoảng trắng | Whitespace |
| Không gian tên | Namespace |
| Khối | Block |
| Kiểm thử/sự kiểm thử | Test/testing |
| Kiểu giá trị | Type |
| Kiểu nguyên thủy | Primitive |
| Kiểu sai | Falsy/falsey |
| Ký pháp | Notation |
| Ký pháp chấm | Dot notation |
| Ký tự đại diện | Wildcard/wildcard character |
| Ký tự thoát | Escape character |
| Liên kết | Link |
| Liệt kê | Spread |
| Lô-gíc | Logic |
| Lỗ hổng | Vulnerability |
| Lỗi câm | Silent error |
| Lớp | Class |
| Lớp cha | Parent class/parent |
| Lũy thừa | Exponentiation |
| Lưu tạm | Cache |
| Lựa chọn | Select/selection |
| Mã/mã nguồn | Code/source code |
| Mảng | Array |
| Mô-đun | Module |
| Một ngôi | Unary |
| Ném ra | Throw |
| Ngăn xếp | Call stack/stack |
| Ngầm định | Implicit |
| Nghẽn cổ chai | Bottleneck |
| Ngoại lệ | Exception |
| Nguyên mẫu | Prototype |
| Nguyên văn | Literal |
| Ngữ cảnh | Context |
| Nhà phát triển | Developer/dev |
| Nhập/lệnh nhập | Import |
| Nối chuỗi | Chain/chaining |
| Phần tử | Element |
| Phép dịch chuyển bit | Bit-shift/bit-shift operation |
| Phép tăng | Increment |
| Phép giảm | Decrement |
| Phép tiền tăng/sự tiền tăng | Pre-increment |
| Phép tiền giảm/sự tiền giảm | Pre-decrement |
| Phi chuẩn | Non-standard |
| Phương thức | Method |
| Quy tắc chèn dấu chấm phẩy tự động | Automatic semicolon insertion/ASI |
| Quy ước đặt tên | Naming convention |
| Ràng buộc | Binding |
| Riêng tư | Private |
| Rút gọn/dạng rút gọn | Shorthand/shortcut |
| So sánh/sự so sánh | Compare/comparision |
| Sự bằng nhau | Equality |
| Sự kiện | Event/ev |
| Tên của thuộc tính | Property name/key |
| Tên được tính của thuộc tính | Computed property name |
| Tham chiếu | Reference |
| Tham số | Parameter |
| Thành viên | Member |
| Thân hàm | Function body |
| Thẻ | Tab |
| Thuộc phạm vi hàm | Function-scoped |
| Thuộc phạm vi khối | Block-scoped |
| Thuộc tính | Property |
| Thư viện | Library/lib |
| Thừa kế | Inherit/inheritance |
| Thực thể | Instance |
| Tiến trình gọi | Caller |
| Tính khả đọc | Readability |
| Tính tương thích | Compatibility |
| Toàn cục | Global |
| Toán tử | Operator |
| Trình gỡ lỗi | Debugger |
| Trình phân tích mã | Linter |
| Trình thực thi | Engine |
| Trích xuất/sự trích xuất | Destructure/destructuring/extract |
| Trọng tải | Payload |
| Truy cập | Access |
| Truy vấn | Query |
| Từ khóa | Keyword |
| Từ khóa điều chỉnh | Modifier |
| Ứng dụng | Application/app |
| Vấn đề | Issue |
| Xếp tầng | Cascade/cascading |
| Xuất/lệnh xuất | Export |
| Xuất hữu danh | Named export |
| Xuất mặc định | Default export |
| Xung đột khi gộp | Merge conflict |
Định hướng này cũng được dịch sang các ngôn ngữ khác:
English (United States):airbnb/javascript
Brazilian Portuguese:armoucar/javascript-style-guide
Bulgarian:borislavvv/javascript
Catalan:fpmweb/javascript-style-guide
Chinese (Simplified):lin-123/javascript
Chinese (Traditional):jigsawye/javascript
French:nmussy/javascript-style-guide
German:timofurrer/javascript-style-guide
Italian:sinkswim/javascript-style-guide
Japanese:mitsuruog/javascript-style-guide
Korean:ParkSB/javascript-style-guide
Russian:leonidlebedev/javascript-airbnb
Spanish:paolocarrasco/javascript-style-guide
Thai:lvarayut/javascript-style-guide
Turkish:eraycetinay/javascript
Ukrainian:ivanzusko/javascript
- Tìm chúng tôi trêngitter.
(The MIT License)
Copyright (c) 2012 Airbnb
Permission is hereby granted, free of charge, to any person obtaininga copy of this software and associated documentation files (the'Software'), to deal in the Software without restriction, includingwithout limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and topermit persons to whom the Software is furnished to do so, subject tothe following conditions:
The above copyright notice and this permission notice shall beincluded 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 OFMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANYCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THESOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chúng tôi khuyến khích bạn bẻ nhánh bản định hướng này và thay đổi các quy tắc để phù hợp với định hướng lối viết của nhóm của bạn. Dưới đây, bạn có thể liệt kê các sửa đổi đối với bản định hướng này. Điều này cho phép bạn thỉnh thoảng cập nhật lối viết mà không cần giải quyết các xung đột khi gộp.
About
Bản dịch tiếng Việt cho Định hướng Lối viết JavaScript của Airbnb
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.