編程風(fēng)格
基本格式化
注釋
語(yǔ)句和表達(dá)式
-
塊語(yǔ)句都應(yīng)使用花括號(hào)
- if...else...
- switch
- for
- while
- do..while..
- try...catch...
- ...
-
花括號(hào)對(duì)齊方式,左花括號(hào)擋在塊語(yǔ)句的第一行末尾
if () {
} else {
}
-
塊語(yǔ)句間隔
-
語(yǔ)句名,小括號(hào),花括號(hào)都沒(méi)有空格
if(true){
}
-
小括號(hào)左右加空格
if (true) {
}
-
小括號(hào)左右加空格,小括號(hào)與小括號(hào)內(nèi)容之間加空格
if ( true ) {
}
-
switch 語(yǔ)句
-
縮進(jìn)
-
每條 case 語(yǔ)句相對(duì)于 switch 關(guān)鍵字縮進(jìn)一個(gè)層級(jí),每條 case 語(yǔ)句后都有一個(gè)空行
switch (color) {
case '#000':
break
case '#f00':
break
case '#00F':
break
default:
break
}
-
case 和 switch 左對(duì)齊,且沒(méi)有空行
switch (color) {
case '#000':
break
case '#00F':
break
default:
break
}
- 連續(xù)執(zhí)行: 有意連續(xù)執(zhí)行需要加注釋,其他情況默認(rèn)每條語(yǔ)句結(jié)束必須是 break,return,throw
- default:如果default什么也沒(méi)做,加上注釋,省略default
-
while 語(yǔ)句 盡量避免使用,因?yàn)樵趪?yán)格模式下不能運(yùn)行,而且容易造成對(duì)于變量的認(rèn)知錯(cuò)誤
let message = '你好!'
let book = {
name: '少少',
age: 18,
message: '你好嗎?'
}
with (book) {
message += name
console.log(message)
}
-
for 循環(huán) 遍歷數(shù)組
- break 立即退出循環(huán)
- commit 跳過(guò)本次循環(huán) // 盡量避免這種方式
-
for-in 循環(huán) 遍歷對(duì)象
變量 函數(shù) 運(yùn)算符
編程實(shí)踐
UI 層的松耦合
- 什么是松耦合:修改一個(gè)組件而不需要修改其他的組件;組件知道的越少,越有利于形成整個(gè)系統(tǒng)
- 將 js 代碼和 css 代碼分離開(kāi),需要操作樣式時(shí)最佳方法是操作 className,除非需要 js 計(jì)算 css 的屬性(比如常見(jiàn)的輪播圖)
-
將 html 和 js 代碼分離開(kāi)
- 從服務(wù)器加載
- 客戶端模板(Handlebars)
避免使用全局變量
-
全局變量帶來(lái)的問(wèn)題
- 命名沖突
- 代碼脆弱性,依賴全局變量,任何地方都能改變?nèi)肿兞康闹?/li>
- 難以測(cè)試依賴全局變量的函數(shù)
-
意外的全局變量
- 當(dāng)使用一個(gè)未被聲明的變量時(shí),JavaScript會(huì)自動(dòng)創(chuàng)建為全局變量
-
單全局變量
-
創(chuàng)建的這個(gè)唯一全局對(duì)象名是獨(dú)一無(wú)二的(不會(huì)和內(nèi)置API產(chǎn)生沖突),并將所有的功能代碼全都掛載到這個(gè)全局對(duì)象上,因此每個(gè)可能的全局變量都會(huì)成為你唯一的全局對(duì)象的屬性,從而不會(huì)創(chuàng)建多個(gè)全局變量
// 再比如表示三本書(shū)
// 方法一
function Book (name) {
return `書(shū)名:${name}`
}
const Book1 = Book("name1")
const Book2 = Book("name2")
const Book3 = Book("name3")
console.log(Book1, Book2, Book3)
// 單全局變量
class Books {
Book1 = Book("name1")
Book2 = Book("name2")
Book3 = Book("name3")
Book (name) {
return `書(shū)名:${name}`
}
}
console.log(Books.Book1, Books.Book2, Books.Book3)
/*
*其他例子: jQuery 定義了 $ 和 jQuery
*以及vue 定義了 Vue
*/
-
命名空間(在類中定義分組,方便管理)
class My {
dom = {
addDom () {
...
},
removeDom () {
...
}
...
}
event = {
onClick () {
...
},
oninput () {
...
}
...
}
}
事件處理
-
典型用法 (流水賬式寫(xiě)法)
// 常見(jiàn)但是不推薦的寫(xiě)法
handleClick (event) {
const popup = document.getElementById("popup")
popup.style.left = event.clientX
popup.style.top = event.clientY
popup.className = "show"
}
-
隔離應(yīng)用邏輯 應(yīng)用邏輯和用戶行為應(yīng)該區(qū)分開(kāi)(一個(gè)函數(shù)只做一件事,便于函數(shù)復(fù)用)
clas Myapp {
handleClick (event) {
this.showPopup(event)
},
showPopup (event) {
const popup = document.getElementById("popup")
popup.style.left = event.clientX
popup.style.top = event.clientY
popup.className = "show"
}
}
-
不要分發(fā)事件對(duì)象 應(yīng)用邏輯不應(yīng)該依賴 event 對(duì)象來(lái)完成功能(便于測(cè)試,便于函數(shù)復(fù)用)
clas Myapp {
handleClick (event) {
// 事件處理程序是接觸 event 對(duì)象的唯一函數(shù) (一個(gè)函數(shù)只做一件事)
event.preventDefault()
event.stopPropagation()
// 傳入應(yīng)用邏輯
this.showPopup(event.clientX, event.clientY)
},
showPopup (x, y) {
const popup = document.getElementById("popup")
popup.style.left = x
popup.style.top = y
popup.className = "show"
}
}
避免空比較
- 使用 "typeof 變量" 的方式檢測(cè) 字符串,數(shù)字,布爾值,undefined,函數(shù),
- 使用 "變量 instanceof 對(duì)象" 的方式檢測(cè)某個(gè)值的引用類型(不能用于檢測(cè)是否屬于 Object,因?yàn)?js 所有的值原型鏈最終都是 Object )
-
檢測(cè)數(shù)組 (es5已有自帶檢測(cè)方法)
// 關(guān)注對(duì)象能做什么,而不是他是什么
function isArr(value) {
return typeof value.sort === 'function'
}
// 更為優(yōu)雅有效的解決方案 (兼容 IE6 以下版本)
function isArray (value) {
if (typeof Array.isArray === 'function') {
return Array.isArray(value) // 自帶判斷數(shù)組方法
} else {
// 某個(gè)值內(nèi)置的 toString 在所有的瀏覽器中都會(huì)返回標(biāo)準(zhǔn)的字符串結(jié)果
return Object.prototype.toString.call(value) === '[object Array]'
}
}
-
檢測(cè)屬性是否存在
-
不好的寫(xiě)法,通過(guò)給定的名字檢查屬性的值
let myObject = {
count: 0
}
if (myObject['count']) {
// 存在但不執(zhí)行
}
-
好的寫(xiě)法,通過(guò) in 運(yùn)算符或者 hasOwnPrperty()
let myObject = {
count: 0
}
if ('count' in myObject) { // in 只檢查屬性是否存在于對(duì)象實(shí)例或者對(duì)象原型
// 執(zhí)行
}
if (myObject.hasOwnPrperty('count')) { // 只檢查是否存在于對(duì)象實(shí)例
// 執(zhí)行
}
將配置數(shù)據(jù)從代碼中分離出來(lái)
拋出自定義錯(cuò)誤
- 什么是錯(cuò)誤 幫助我們快速定位代碼 bug ,以便于調(diào)試維護(hù)
-
JavaScript 拋出錯(cuò)誤的方法
throw new Error('錯(cuò)誤信息')
-
如何書(shū)寫(xiě)拋出的錯(cuò)誤文本
throw new Error('函數(shù)名: 可能的原因')
-
什么時(shí)候拋出錯(cuò)誤
- 不確定自己的函數(shù)在哪些地方調(diào)用
- 工具函數(shù)
- JavaScript 類庫(kù) (函數(shù)調(diào)用棧應(yīng)該在進(jìn)入庫(kù)代碼接口的時(shí)候就終止;意思是在調(diào)用類庫(kù)時(shí)先要校驗(yàn)然后進(jìn)行相應(yīng)的提示,而不是等到)
- 修復(fù)了一個(gè)很難調(diào)試的錯(cuò)誤,這時(shí)添加一兩個(gè)自定義錯(cuò)誤
- 不想要某種情況發(fā)生,為避免這種情況
-
try-catch 語(yǔ)句 catch 代碼塊不能省略或留空
能在錯(cuò)誤拋出前解析它;
拋出錯(cuò)誤會(huì)中斷 js 進(jìn)程, 使用 try-catch 則不會(huì)中斷 js 進(jìn)程
個(gè)人理解: try-catch 語(yǔ)句可以用在自己知道可能會(huì)出錯(cuò)但是不能明確的知道錯(cuò)誤原因,
或者在報(bào)錯(cuò)后仍需繼續(xù)報(bào)錯(cuò)代碼塊之后語(yǔ)句的情況下
不是自己的對(duì)象不要?jiǎng)?/h2>
-
什么是自己的對(duì)象
- 自己創(chuàng)建了一個(gè)對(duì)象,那么自己擁有這個(gè)對(duì)象
- 自己不是創(chuàng)建對(duì)象的人,但是負(fù)責(zé)維護(hù)代碼,那么也擁有這個(gè)對(duì)象
- 只是使用者,不要修改對(duì)象
-
對(duì)象的使用原則
- 不覆蓋對(duì)象原型上的屬性,方法
- 不在對(duì)象原型新增屬性,方法
- 不刪除對(duì)象原型上的屬性,方法
-
如何使用?
- 繼承
- 設(shè)計(jì)模式之外觀模式(門(mén)面模式 Facade Pattern)
-
防止對(duì)象被修改
- Object.preventExtensions(對(duì)象名) 該方法不能向?qū)ο笾行绿砑訉傩院头椒?,但是可以修改?duì)象中存在的屬性
- Object.seal(對(duì)象名) 密封對(duì)象不能新添加屬性、不能刪除屬性。
- Object.freeze(對(duì)象名) 凍結(jié)對(duì)象,即是不可擴(kuò)展的,也是密封的,而且其屬性值也不能修改
|