/**
* 數值類型
*/
// 原始值類型 string number boolean null undefined
var foo = 1;
var bar = foo;
bar = 9;
console.log(foo,bar);
// 非原始值類型 object array function
var foo = [1,2];
var bar = foo;
bar[0] = 9;
console.log(foo[0],bar[0]);
/**
* 對象
*/
// 對象 使用字面量創建對象
var item = new Object();//bad
var item = {};//good
// 不要使用保留字作為鍵名 他們在IE8下不工作
// bad
var superman = {
default:{clark:'kent'},
private:true
};
// good
var superman = {
defaults:{clark:'kent'},
hidden:true
};
// 使用同義詞替換需要使用的保留字
// bad
var superman = {
class:'alien'
};
// bad
var superman = {
kclass:'alien'
};
// good
var superman = {
type:'alien'
}
/**
* 數組
*/
// 使用字面量創建數組
var items = new Array();//bad
var items = [];//good
// 向數組添加元素時使用push來替代直接賦值
var someStack = [];
someStack[someStack.length] = 'abcdefbaba';//dad
someStack.push('abcdefbaba');//good
//當你需要拷貝數組時,使用slice
var len = items.length;
var itemsCopy = [];
var i;
//bad
for (i = 0;i < len;i++) {
itemsCopy[i] = items[i];
}
// good
itemsCopy = items.slice();
// 使用slice將類數組對象轉換為數組
function trigger() {
var args = Array.prototype.slice.call(arguments);
// ...
}
/**
* 字符串
*/
// 使用單引號包裹字符串
var name = "Bob Parr";//bad
var name = 'Bob Parr';//good;
var fullName = "Bob" + this.lastName;//bad
var fullName = 'Bob' + this.lastName;//good
// 超過100個字符的字符串應該使用連詞符寫成多行。
// 通過過度使用,通過連詞符鏈接的長度可能會影響性能
// bad
var errorMessage = 'This is a super long error that was thrown beacause of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'
// bad
var 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
var 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.';
// 程序化生成的字符串使用join鏈接而不是使用連接符,尤其是IE下
var items;
var messages;
var length;
var i;
messages = [{
state:'success',
message:'This one wroked'
},{
state:'suceess',
message:'This one worked as well'
},{
state:'error',
message:'This one did not work'
}];
length = messages.length;
//bad
function inbox(message) {
items = '<ul>';
for (i = 0;i<length;i++){
items += '<li>' + messages[i].message + '</li>'
}
return items + '</ul>';
}
// good
function inbox(messages) {
items = [];
for(i = 0;i<length;i++){
items[i] = '<li>' + messages[i].message + '</li>';
}
return '<ul>' + items.join('') + '</ul>';
}
/**
* 函數
*/
// 函數表達式
// 匿名函數表達式
var annoymous = function(){
return true;
};
// 命名函數表達式
var named = function named() {
return true;
};
// 立即調用的函數表達式IIFE
(function(){
console.log('Welcome to the Internet. Please follow me.');
}());
// 永遠不要在一個非函數代碼塊if while 等 中聲明一個函數,瀏覽器允許你這么做,但它們的解析表現不一致,正確的做法是在塊兒外定義一個變量,然后將函數賦值給它。
// ECMA-262 把塊定義為一組語句。函數聲明不是語句。
// bad
if (currentUser){
function test () {
console.log('Nope.');
}
}
// good
var test;
if (currentUser) {
test = function test(){
console.log('Yup.');
};
}
// 永遠不要把參數命名為arguments 這將取代函數作用域內的 arguments 對象
// bad
function nope(name,options,arguments) {
// ...stuff
}
// good
function yup(name,options,args){
// ...stuff...
}
/**
* 屬性
*/
// 使用.來訪問對象的屬性
var luke = {
jedi:true,
age:28
};
//bad
var isJedi = luke['jedi'];
// good
var isJedi = luke.jedi;
// 當通過變量訪問屬性時使用中括號
function getProp(prop){
return luke[prop];
}
var isJedi = getProp('jedi');
/**
* 變量
*/
// 總是使用 var 來聲明變量。不這么做將會導致產生全局變量。我們要避免污染全局命名空間。
//bad
superPower = new SuperPower();
//good
var superPower = new SuperPower();
// 使用var 聲明每一個 變量。 這樣做的好處是增加變量將變得更加容易。而且你永遠不用再擔心調換錯;和,
//bad
var items = getItems(),
goSportsItem = true,
dragonball = 'z';
//bad
// (跟上面的代碼比較一下,看看哪里錯了)
var items = getItems(),
goSportsItem = true;
dragonball = 'z';
// good
var items = getItems(),
var goSportsItem = true;
var dragonball = 'z';
// 最后在聲明未賦值的變量。當你需要引用前面的變量賦值時,這將變得很有用。
// bad
var i,len,dragonball,
item = getItems(),
goSportsTeam = true;
// bad
var i;
var items = getItems();
var dragonball;
var goSportsItem = true;
var len;
// good
var items = getItems();
var goSportsItem = true;
var dragonball;
var length;
var i;
// 在作用域頂部聲明變量,這將幫你避免聲明變量提升的相關問題
//bad
function lalala (){
test();
console.log('doing stuff...');
// ...other stuff
var name = getName();
if (name === 'test'){
return false;
}
return name;
}
// good
function lalala (){
var name = getName();
test();
console.log('doing stuff...');
// ...other stuff...
if (name === 'test') {
return false;
}
}
// bad - 不必要的函數調用
function lalala(){
var name = getName();
if (!arguments.length) {
return false;
}
this.setFirstName(name);
return true;
}
// good
function lalala(){
var name;
if (!arguments.length) {
return false;
}
name = getName();
this.setFirstName(name);
return true;
}
/**
* 提升
*/
// 變量提升會提升至作用域頂部,但賦值不會
// 我們知道這樣不能正常工作(假設這里沒有名為 notDefined 的全局變量)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// 但由于變量聲明提升的原因,在一個變量引用后再創建它的變量聲明將可以正常工作。
// 注:變量賦值為 `true` 不會提升。
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// 解釋器會把變量聲明提升到作用域頂部,意味著我們的例子將被重寫成:
function example() {
var declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// 匿名函數表達式會提升它們的變量名,但不會提升函數的賦值。
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
// 函數聲明提升它們的名字和函數體。
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
/**
* 比較運算符 & 等號
*/
// 優先使用 === 和 !== 而不是 == 和 !=
// 條件表達式例如 if 語句 通過抽象方法 ToBoolean 強制計算它們的表達式并總是遵循下面的規則:
// 對象被計算為true
// undefined被計算為 false
// Null 被計算為false
// 布爾值被計算為布爾的值
// 數字 如果是 +0 -0 或者 NaN 被計算為 false 否則為true
// 字符串 如果是空字符串''被計算為false 否則為true
if ([0]) {
//true 一個數組就是一個對象,對象被計算為true
}
// 使用快捷方式
// bad
if (name != '') {
//...stuff...
}
// good
if (name) {
//...stuff
}
// bad
if (collection.length > 0) {
//...stuff...
}
// good
if (collection.length) {
//...stuff...
}
/**
* 塊
*/
// 使用大括號包括的多行代碼塊
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function test() {return false};
// good
function test(){
return false;
}
// 如果通過 if 和 else 使用多行代碼塊,把else 放在if代碼塊 關閉括號的同一行。
// bad
if (test) {
thing1();
thing2();
}
else{
thing3();
}
// good
if (test) {
thing1();
thing2();
}else {
thing3();
}
/**
* 注釋
*/
// 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;
}
/**
* make() returns a new element
* based on the passed in tah name
*
* @param {String} tag
* @return {Element} elment
*/
function make(tag) {
// ...stuff...
return element;
}
// 使用//作為單行注釋,在評論對象上面另起一行使用單行注釋。在注釋前插入空行
// bad
var active = ture;//is current tab
// good
// is current tab
var active = ture;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
var type = this.type || 'no type';
return type;
}
// good 在注釋前插入空行
function getType() {
console.log('fetching type...');
// set the defalut type to 'no type'
var type = this.type || 'no type';
return type;
}
// 給注釋增加FIXME 或 TODO 的前綴可以幫助其他開發者快速了解這是一個需要復查的問題
// 或是給要實現的功能提供一個解決方案。這有別于常見注釋,因為他們是可操作的。
// 使用 FIXME -- need to figure this out 或者 TODO -- need to implement
function Calculator() {
// FIXME: shouldn't use a global here
total = 0;
return this;
}
function Calculator(){
// TODO: total should be configurable by an options pamr
this.total = 0;
return this;
}
/**
* 空白
*/
// 使用2個空格作為縮進
// bad
function test() {
var name;
}
// bad
function test() {
var name;
}
// good
function test() {
var name;
}
// 在打括號前放一個空格
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Benrnese Mountain Dog'
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Benrnese Mountain Dog'
});
// 在控制語句 if while 等 的小括號前放一個空格。在函數調用及聲明中,不在函數的參數列表前加空格
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log ('Swooosh!');
}
// 使用空格把運算符隔開
// bad
var x=y+5;
// good
var x = y + 5;
// 在文件末尾插入一個空行
// bad
(function (global) {
// ...stuff...
})(this);
// bad
(function (global) {
// ...stuff...
})(this);?
?
// good
(function (global) {
// ...stuff...
})(this);?
// 在使用長方法鏈時進行縮進。使用前面的點 . 強調這是方法調用而不是新語句。
// 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
var 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
var 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);
// 在塊末和新語句前插入空行。
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
var obj = {
foo: function () {
},
bar: function () {
}
};
return obj;
// good
var obj = {
foo: function () {
},
bar: function () {
}
};
return obj;
// 逗號
// 行首逗號 不需要
// bad
var story = [
once
, upon
, aTime
];
// good
var story = [
once,
upon,
aTime
];
// bad
var hero = {
firstName: 'Bob'
, lastName: 'Parr'
, heroName: 'Mr. Incredible'
, superPower: 'strength'
};
// good
var hero = {
firstName: 'Bob',
lastName: 'Parr',
heroName: 'Mr. Incredible',
superPower: 'strength'
};
// 額外的行末逗號不需要
// bad
var hero = {
firstName: 'Kevin',
lastName: 'Flynn',
};
var heroes = [
'Batman',
'Superman',
];
// good
var hero = {
firstName: 'Kevin',
lastName: 'Flynn'
};
var heroes = [
'Batman',
'Superman'
];
// 使用分號
// bad
(function () {
var name = 'Skywalker'
return name
})()
// good
(function () {
var name = 'Skywalker';
return name;
})();
// good (防止函數在兩個 IIFE 合并時被當成一個參數
;(function () {
var name = 'Skywalker';
return name;
})();
// 類型轉換
// 在語句開始時執行類型轉換
// 字符串
this.reviewScore = 9;
// bad
var totalScore = this.reviewScore + '';
// good
var totalScore = '' + this.reviewScore;
// bad
var totalScore = '' + this.reviewScore + 'total score';
// good
var totalScore = this.reviewScore + 'total score';
// 使用 parseInt 轉換數字時總是帶上類型轉換的基數
var inputValue = '4';
// bad
var val = new Number(inputValue);
// bad
var val = +inputValue;
// bad
var val = inputValue >> 0;
// bad
var val = parseInt(inputValue);
// good
var val = Number(inputValue);
// good
var val = parseInt(inputValue,10);
// 如果因為某些原因 parseInt 成為你所做的事的瓶頸而需要使用位操作解決性能問題時,留個注釋說清楚原因和你的目的。
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
var val = inputValue >> 0;
// 注: 小心使用位操作運算符。數字會被當成 64 位值,但是位操作運算符總是返回 32 位的整數(source)。位操作處理大于 32 位的整數值時還會導致意料之外的行為。討論。最大的 32 位整數是 2,147,483,647:
// 布爾
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
// 命名規則
// 避免單字母命名,命名應具有描述性
// bad
function q() {
// ...stuff
}
// good
function query() {
// ..stuff..
}
// 使用駝峰式命名對象、函數和實例
// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
var o = {};
function c() {}
// good
var thisIsMyObject = {};
function thisIsMyFunction() {}
// 使用帕斯卡式命名構造函數或類。
// bad
function user(options) {
this.name = options.name;
}
var bad = new user({
name: 'nope'
});
// good
function User(options) {
this.name = options.name;
}
var good = new User({
name: 'yup'
});
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// good
this.firstName = 'Panda';
// 不要保存 this 的引用。使用 Function#bind。
// bad
function test() {
var self = this;
return function(){
console.log(self);
};
}
// bad
function test() {
var that = this;
return function () {
console.log(that);
};
}
// bad
function test() {
var _this = this;
return function () {
console.log(_this);
};
}
// good
function test() {
return function(){
console.log(this);
}.bind(this);
}
// 給函數命名,這在做堆棧時很有幫助
// bad
var log = function (msg) {
console.log(msg);
};
// good
var log = function log(msg) {
console.log(msg);
};
// 如果你的一個文件導出一個類,你的文件名應該與類名完全相同
// file contents
class CheckBox {
// ...
}
module.exports = CheckBox;
// in some other file
// bad
var CheckBox = require('./checkBox');
// bad
var CheckBox = require('./check_box');
// good
var CheckBox = require('./CheckBox');
/**
* 存取器
*/
// 屬性的存取函數不是必須的。
// 如果你需要存取函數時使用 getVal() 和 setVal('hello')。
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
// 如果屬性是布爾值,使用 isVal() 或 hasVal()。
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
// 創建 get() 和 set() 函數是可以的,但要保持一致。
function Jedi(options) {
options || (options = {});
var lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
Jedi.prototype.set = function set(key, val) {
this[key] = val;
};
Jedi.prototype.get = function get(key) {
return this[key];
};
/**
* 構造函數
*/
// 給對象原型分配方法,而不是使用一個新的對象覆蓋原型,覆蓋原型將導致繼承出現問題:重設原型將覆蓋原有原型!
function Jedi() {
console.log('new jedi');
}
// bad
Jedi.prototype = {
fight: function fight() {
console.log('fighting');
},
block: function block() {
console.log('blocking');
}
};
// good
Jedi.prototype.fight = function fight() {
console.log('fighting');
};
Jedi.prototype.block = function block() {
console.log('blocking');
};
// 方法可以返回 this 來實現方法鏈式使用。
// bad
Jedi.prototype.jump = function jump() {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function setHeight(height) {
this.height = height;
};
var luke = new Jedi();
luke.jump();//=>true
luke.setHeight(20);//=>undefined
// good
Jedi.prototype.jump = function jump() {
this.jumping = true;
return this;
}
Jedi.prototype.setHeight = function setHeight(height) {
this.height = height;
return this;
};
var luke = new Jedi();
luke.jump()
.setHeight(20);
// 寫一個自定義的 toString() 方法是可以的,但是確保它可以正常工作且不會產生副作用。
function Jedi(options) {
options || (options = {});
this.name = options.name || 'no name';
}
Jedi.prototype.getName = function getName() {
return this.name;
};
Jedi.prototype.toString = function() {
return 'Jedi -' + this.getName();
};
/**
* 事件
*/
// 當給事件附加數據時(無論是 DOM 事件還是私有事件),傳入一個哈希而不是原始值。
// 這樣可以讓后面的貢獻者增加更多數據到事件數據而無需找出并更新事件的每一個處理器。例如,不好的寫法:
// bad
$(this).trigger('listingUpdated', listing.id);
// bad
$(this).trigger('listingUpdated', listing.id);
$(this).on('listingUpdated', function (e, listingId) {
// do something with listingId
});
// 更好的寫法:
// good
$(this).trigger('listingUpdated', { listingId : listing.id });
$(this).on('listingUpdated', function (e, data) {
// do something with data.listingId
});
/**
* 模塊
*/
// 模塊應該以 ! 開始。這樣確保了當一個不好的模塊忘記包含最后的分號時,在合并代碼到生產環境后不會產生錯誤。詳細說明
// 文件應該以駝峰式命名,并放在同名的文件夾里,且與導出的名字一致。
// 增加一個名為 noConflict() 的方法來設置導出的模塊為前一個版本并返回它。
// 永遠在模塊頂部聲明 'use strict';。
// fancyInput/fancyInput.js
!function (global) {
'use strict';
var previousFancyInput = global.FancyInput;
function FancyInput(options) {
this.options = options || {};
}
FancyInput.noConflict = function noConflict() {
global.FancyInput = previousFancyInput;
return FancyInput;
};
global.FancyInput = FancyInput;
}(this);
/**
* jQuery
*/
// 使用 $ 作為存儲 jQuery 對象的變量名前綴。
// bad
var sidebar = $('.sidebar');
// good
var $sidebar = $('.sidebar');
// 緩存 jQuery 查詢。
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
var $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
// 對 DOM 查詢使用層疊 $('.sidebar ul') 或 父元素 > 子元素 $('.sidebar > ul')。 jsPerf
// 對有作用域的 jQuery 對象查詢使用 find。
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
js代碼規范
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
- 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
- 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
推薦閱讀更多精彩內容
- 前端 通過分析github代碼庫總結出來的工程師代碼書寫習慣 HTML&CSS編碼規范 by @mdo 團隊合作的...
- 本文首發于我的個人網站:http://cherryblog.site/ (背景更換了不知道大家有沒有發現呢,嘻嘻)...