自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何寫出優(yōu)雅耐看的JavaScript代碼

開發(fā) 前端
在我們平時(shí)的工作開發(fā)中,大多數(shù)都是大人協(xié)同開發(fā)的公共項(xiàng)目;在我們平時(shí)開發(fā)中代碼codeing的時(shí)候我們考慮代碼的可讀性、復(fù)用性和擴(kuò)展性。干凈的代碼,既在質(zhì)量上較為可靠,也為后期維護(hù)、升級奠定了良好基礎(chǔ)。

前言

在我們平時(shí)的工作開發(fā)中,大多數(shù)都是大人協(xié)同開發(fā)的公共項(xiàng)目;在我們平時(shí)開發(fā)中代碼codeing的時(shí)候我們考慮代碼的可讀性、復(fù)用性和擴(kuò)展性。

干凈的代碼,既在質(zhì)量上較為可靠,也為后期維護(hù)、升級奠定了良好基礎(chǔ)。

[[277405]]

我們從以下幾個(gè)方面進(jìn)行探討:

變量

1、變量命名

一般我們在定義變量是要使用有意義的詞匯命令,要做到見面知義

 

  1. //bad code 
  2. const yyyymmdstr = moment().format('YYYY/MM/DD'); 
  3. //better code 
  4. const currentDate = moment().format('YYYY/MM/DD'); 

2、可描述

通過一個(gè)變量生成了一個(gè)新變量,也需要為這個(gè)新變量命名,也就是說每個(gè)變量當(dāng)你看到他第一眼你就知道他是干什么的。

 

  1. //bad code 
  2. const ADDRESS = 'One Infinite Loop, Cupertino 95014'
  3. const CITY_ZIP_CODE_REGEX = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; 
  4. saveCityZipCode(ADDRESS.match(CITY_ZIP_CODE_REGEX)[1], ADDRESS.match(CITY_ZIP_CODE_REGEX)[2]); 
  5.  
  6. //better code 
  7. const ADDRESS = 'One Infinite Loop, Cupertino 95014'
  8. const CITY_ZIP_CODE_REGEX = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; 
  9. const [, city, zipCode] = ADDRESS.match(CITY_ZIP_CODE_REGEX) || []; 
  10. saveCityZipCode(city, zipCode); 

3、形參命名

在for、forEach、map的循環(huán)中我們在命名時(shí)要直接

 

  1. //bad code 
  2. const locations = ['Austin''New York''San Francisco']; 
  3. locations.map((l) => { 
  4.   doStuff(); 
  5.   doSomeOtherStuff(); 
  6.   // ... 
  7.   // ... 
  8.   // ... 
  9.   // 需要看其他代碼才能確定 'l' 是干什么的。 
  10.   dispatch(l); 
  11. }); 
  12.  
  13. //better code 
  14. const locations = ['Austin''New York''San Francisco']; 
  15. locations.forEach((location) => { 
  16.   doStuff(); 
  17.   doSomeOtherStuff(); 
  18.   // ... 
  19.   // ... 
  20.   // ... 
  21.   dispatch(location); 
  22. }); 

4、避免無意義的前綴

例如我們只創(chuàng)建一個(gè)對象是,沒有必要再把每個(gè)對象的屬性上再加上對象名

 

  1. //bad code 
  2. const car = { 
  3.   carMake: 'Honda'
  4.   carModel: 'Accord'
  5.   carColor: 'Blue' 
  6. }; 
  7.  
  8. function paintCar(car) { 
  9.   car.carColor = 'Red'
  10.  
  11. //better code 
  12. const car = { 
  13.   make: 'Honda'
  14.   model: 'Accord'
  15.   color: 'Blue' 
  16. }; 
  17.  
  18. function paintCar(car) { 
  19.   car.color = 'Red'

5、默認(rèn)值

 

  1. //bad code 
  2. function createMicrobrewery(name) { 
  3.   const breweryName = name || 'Hipster Brew Co.'
  4.   // ... 
  5.  
  6. //better code 
  7. function createMicrobrewery(name = 'Hipster Brew Co.') { 
  8.   // ... 

函數(shù)

1、參數(shù)

一般參數(shù)多的話要使用ES6的解構(gòu)傳參的方式

 

  1. //bad code 
  2. function createMenu(title, body, buttonText, cancellable) { 
  3.   // ... 
  4.  
  5. //better code 
  6. function createMenu({ title, body, buttonText, cancellable }) { 
  7.   // ... 
  8.  
  9. //better code 
  10. createMenu({ 
  11.   title: 'Foo'
  12.   body: 'Bar'
  13.   buttonText: 'Baz'
  14.   cancellable: true 
  15. }); 

2、單一化處理

一個(gè)方法里面最好只做一件事,不要過多的處理,這樣代碼的可讀性非常高

 

  1. //bad code 
  2. function emailClients(clients) { 
  3.   clients.forEach((client) => { 
  4.     const clientRecord = database.lookup(client); 
  5.     if (clientRecord.isActive()) { 
  6.       email(client); 
  7.     } 
  8.   }); 
  9.  
  10. //better code 
  11. function emailActiveClients(clients) { 
  12.   clients 
  13.     .filter(isActiveClient) 
  14.     .forEach(email); 
  15. function isActiveClient(client) { 
  16.   const clientRecord = database.lookup(client);     
  17.   return clientRecord.isActive(); 

3、對象設(shè)置默認(rèn)屬性

 

  1. //bad code 
  2. const menuConfig = { 
  3.   title: null
  4.   body: 'Bar'
  5.   buttonText: null
  6.   cancellable: true 
  7. }; 
  8. function createMenu(config) { 
  9.   config.title = config.title || 'Foo'
  10.   config.body = config.body || 'Bar'
  11.   config.buttonText = config.buttonText || 'Baz'
  12.   config.cancellable = config.cancellable !== undefined ? config.cancellable : true
  13. createMenu(menuConfig); 
  14.  
  15.  
  16. //better code 
  17. const menuConfig = { 
  18.   title: 'Order'
  19.   // 'body' key 缺失 
  20.   buttonText: 'Send'
  21.   cancellable: true 
  22. }; 

4、避免副作用

函數(shù)接收一個(gè)值返回一個(gè)新值,除此之外的行為我們都稱之為副作用,比如修改全局變量、對文件進(jìn)行 IO 操作等。

當(dāng)函數(shù)確實(shí)需要副作用時(shí),比如對文件進(jìn)行 IO 操作時(shí),請不要用多個(gè)函數(shù)/類進(jìn)行文件操作,有且僅用一個(gè)函數(shù)/類來處理。也就是說副作用需要在唯一的地方處理。

副作用的三大天坑:隨意修改可變數(shù)據(jù)類型、隨意分享沒有數(shù)據(jù)結(jié)構(gòu)的狀態(tài)、沒有在統(tǒng)一地方處理副作用。

 

  1. //bad code 
  2. // 全局變量被一個(gè)函數(shù)引用 
  3. // 現(xiàn)在這個(gè)變量從字符串變成了數(shù)組,如果有其他的函數(shù)引用,會(huì)發(fā)生無法預(yù)見的錯(cuò)誤。 
  4. var name = 'Ryan McDermott'
  5. function splitIntoFirstAndLastName() { 
  6.   name = name.split(' '); 
  7. splitIntoFirstAndLastName(); 
  8. console.log(name); // ['Ryan''McDermott']; 
  9.  
  10.  
  11. //better code 
  12. var name = 'Ryan McDermott'
  13. var newName = splitIntoFirstAndLastName(name
  14.  
  15. function splitIntoFirstAndLastName(name) { 
  16.   return name.split(' '); 
  17.  
  18. console.log(name); // 'Ryan McDermott'
  19. console.log(newName); // ['Ryan''McDermott']; 

在 JavaScript 中,基本類型通過賦值傳遞,對象和數(shù)組通過引用傳遞。以引用傳遞為例:

假如我們寫一個(gè)購物車,通過 addItemToCart()方法添加商品到購物車,修改 購物車數(shù)組。此時(shí)調(diào)用 purchase()方法購買,由于引用傳遞,獲取的 購物車數(shù)組正好是最新的數(shù)據(jù)。

看起來沒問題對不對?

如果當(dāng)用戶點(diǎn)擊購買時(shí),網(wǎng)絡(luò)出現(xiàn)故障, purchase()方法一直在重復(fù)調(diào)用,與此同時(shí)用戶又添加了新的商品,這時(shí)網(wǎng)絡(luò)又恢復(fù)了。那么 purchase()方法獲取到 購物車數(shù)組就是錯(cuò)誤的。

為了避免這種問題,我們需要在每次新增商品時(shí),克隆 購物車數(shù)組并返回新的數(shù)組。

 

  1. //bad code 
  2. const addItemToCart = (cart, item) => { 
  3.   cart.push({ item, dateDate.now() }); 
  4. }; 
  5.  
  6. //better code 
  7. const addItemToCart = (cart, item) => { 
  8.   return [...cart, {item, dateDate.now()}] 
  9. }; 

5、全局方法

在 JavaScript 中,永遠(yuǎn)不要污染全局,會(huì)在生產(chǎn)環(huán)境中產(chǎn)生難以預(yù)料的 bug。舉個(gè)例子,比如你在 Array.prototype上新增一個(gè) diff方法來判斷兩個(gè)數(shù)組的不同。而你同事也打算做類似的事情,不過他的 diff方法是用來判斷兩個(gè)數(shù)組首位元素的不同。很明顯你們方法會(huì)產(chǎn)生沖突,遇到這類問題我們可以用 ES2015/ES6 的語法來對 Array進(jìn)行擴(kuò)展。

 

  1. //bad code 
  2. Array.prototype.diff = function diff(comparisonArray) { 
  3.   const hash = new Set(comparisonArray); 
  4.   return this.filter(elem => !hash.has(elem)); 
  5. }; 
  6.  
  7. //better code 
  8. class SuperArray extends Array { 
  9.   diff(comparisonArray) { 
  10.     const hash = new Set(comparisonArray); 
  11.     return this.filter(elem => !hash.has(elem));         
  12.   } 

6、避免類型檢查

JavaScript 是無類型的,意味著你可以傳任意類型參數(shù),這種自由度很容易讓人困擾,不自覺的就會(huì)去檢查類型。仔細(xì)想想是你真的需要檢查類型還是你的 API 設(shè)計(jì)有問題?

 

  1. //bad code 
  2. function travelToTexas(vehicle) { 
  3.   if (vehicle instanceof Bicycle) { 
  4.     vehicle.pedal(this.currentLocation, new Location('texas')); 
  5.   } else if (vehicle instanceof Car) { 
  6.     vehicle.drive(this.currentLocation, new Location('texas')); 
  7.   } 
  8.  
  9. //better code 
  10. function travelToTexas(vehicle) { 
  11.   vehicle.move(this.currentLocation, new Location('texas')); 

如果你需要做靜態(tài)類型檢查,比如字符串、整數(shù)等,推薦使用 TypeScript,不然你的代碼會(huì)變得又臭又長。

 

  1. //bad code 
  2. function combine(val1, val2) { 
  3.   if (typeof val1 === 'number' && typeof val2 === 'number' || 
  4.       typeof val1 === 'string' && typeof val2 === 'string') { 
  5.     return val1 + val2; 
  6.   } 
  7.  
  8.   throw new Error('Must be of type String or Number'); 
  9.  
  10. //better code 
  11. function combine(val1, val2) { 
  12.   return val1 + val2; 

復(fù)雜條件判斷

我們編寫js代碼時(shí)經(jīng)常遇到復(fù)雜邏輯判斷的情況,通常大家可以用if/else或者switch來實(shí)現(xiàn)多個(gè)條件判斷,但這樣會(huì)有個(gè)問題,隨著邏輯復(fù)雜度的增加,代碼中的if/else/switch會(huì)變得越來越臃腫,越來越看不懂,那么如何更優(yōu)雅的寫判斷邏輯

1、if/else

點(diǎn)擊列表按鈕事件

 

  1. /** 
  2.  * 按鈕點(diǎn)擊事件 
  3.  * @param {number} status 活動(dòng)狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 
  4.  */ 
  5. const onButtonClick = (status)=>{ 
  6.   if(status == 1){ 
  7.     sendLog('processing'
  8.     jumpTo('IndexPage'
  9.   }else if(status == 2){ 
  10.     sendLog('fail'
  11.     jumpTo('FailPage'
  12.   }else if(status == 3){ 
  13.     sendLog('fail'
  14.     jumpTo('FailPage'
  15.   }else if(status == 4){ 
  16.     sendLog('success'
  17.     jumpTo('SuccessPage'
  18.   }else if(status == 5){ 
  19.     sendLog('cancel'
  20.     jumpTo('CancelPage'
  21.   }else { 
  22.     sendLog('other'
  23.     jumpTo('Index'
  24.   } 

從上面我們可以看到的是通過不同的狀態(tài)來做不同的事情,代碼看起來非常不好看,大家可以很輕易的提出這段代碼的改寫方案,switch出場:

2、switch/case

 

  1. /** 
  2.  * 按鈕點(diǎn)擊事件 
  3.  * @param {number} status 活動(dòng)狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 
  4.  */ 
  5. const onButtonClick = (status)=>{ 
  6.   switch (status){ 
  7.     case 1: 
  8.       sendLog('processing'
  9.       jumpTo('IndexPage'
  10.       break 
  11.     case 2: 
  12.     case 3: 
  13.       sendLog('fail'
  14.       jumpTo('FailPage'
  15.       break   
  16.     case 4: 
  17.       sendLog('success'
  18.       jumpTo('SuccessPage'
  19.       break 
  20.     case 5: 
  21.       sendLog('cancel'
  22.       jumpTo('CancelPage'
  23.       break 
  24.     default
  25.       sendLog('other'
  26.       jumpTo('Index'
  27.       break 
  28.   } 

這樣看起來比if/else清晰多了,細(xì)心的同學(xué)也發(fā)現(xiàn)了小技巧,case 2和case 3邏輯一樣的時(shí)候,可以省去執(zhí)行語句和break,則case 2的情況自動(dòng)執(zhí)行case 3的邏輯。

3、存放到Object

將判斷條件作為對象的屬性名,將處理邏輯作為對象的屬性值,在按鈕點(diǎn)擊的時(shí)候,通過對象屬性查找的方式來進(jìn)行邏輯判斷,這種寫法特別適合一元條件判斷的情況。

 

  1. const actions = { 
  2.   '1': ['processing','IndexPage'], 
  3.   '2': ['fail','FailPage'], 
  4.   '3': ['fail','FailPage'], 
  5.   '4': ['success','SuccessPage'], 
  6.   '5': ['cancel','CancelPage'], 
  7.   'default': ['other','Index'], 
  8. /** 
  9.  * 按鈕點(diǎn)擊事件 
  10.  * @param {number} status 活動(dòng)狀態(tài):1開團(tuán)進(jìn)行中 2開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 
  11.  */ 
  12. const onButtonClick = (status)=>{ 
  13.   let action = actions[status] || actions['default'], 
  14.       logName = action[0], 
  15.       pageName = action[1] 
  16.   sendLog(logName) 
  17.   jumpTo(pageName) 

4、存放到Map

 

  1. const actions = new Map([ 
  2.   [1, ['processing','IndexPage']], 
  3.   [2, ['fail','FailPage']], 
  4.   [3, ['fail','FailPage']], 
  5.   [4, ['success','SuccessPage']], 
  6.   [5, ['cancel','CancelPage']], 
  7.   ['default', ['other','Index']] 
  8. ]) 
  9. /** 
  10.  * 按鈕點(diǎn)擊事件 
  11.  * @param {number} status 活動(dòng)狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 
  12.  */ 
  13. const onButtonClick = (status)=>{ 
  14.   let action = actions.get(status) || actions.get('default'
  15.   sendLog(action[0]) 
  16.   jumpTo(action[1]) 

這樣寫用到了es6里的Map對象,是不是更爽了?Map對象和Object對象有什么區(qū)別呢?

  • 一個(gè)對象通常都有自己的原型,所以一個(gè)對象總有一個(gè)"prototype"鍵。
  • 一個(gè)對象的鍵只能是字符串或者Symbols,但一個(gè)Map的鍵可以是任意值。

你可以通過size屬性很容易地得到一個(gè)Map的鍵值對個(gè)數(shù),而對象的鍵值對個(gè)數(shù)只能手動(dòng)確認(rèn)。

代碼風(fēng)格

常量大寫

  1. //bad code 
  2. const DAYS_IN_WEEK = 7; 
  3. const daysInMonth = 30; 
  4.  
  5. const songs = ['Back In Black''Stairway to Heaven''Hey Jude']; 
  6. const Artists = ['ACDC''Led Zeppelin''The Beatles']; 
  7.  
  8. function eraseDatabase() {} 
  9. function restore_database() {} 
  10.  
  11. class animal {} 
  12. class Alpaca {} 
  13.  
  14. //better code 
  15. const DAYS_IN_WEEK = 7; 
  16. const DAYS_IN_MONTH = 30; 
  17.  
  18. const SONGS = ['Back In Black''Stairway to Heaven''Hey Jude']; 
  19. const ARTISTS = ['ACDC''Led Zeppelin''The Beatles']; 
  20.  
  21. function eraseDatabase() {} 
  22. function restoreDatabase() {} 
  23.  
  24. class Animal {} 
  25. class Alpaca {} 

先聲明后調(diào)用

 

  1. //bad code 
  2. class PerformanceReview { 
  3.   constructor(employee) { 
  4.     this.employee = employee; 
  5.   } 
  6.  
  7.   lookupPeers() { 
  8.     return db.lookup(this.employee, 'peers'); 
  9.   } 
  10.  
  11.   lookupManager() { 
  12.     return db.lookup(this.employee, 'manager'); 
  13.   } 
  14.  
  15.   getPeerReviews() { 
  16.     const peers = this.lookupPeers(); 
  17.     // ... 
  18.   } 
  19.  
  20.   perfReview() { 
  21.     this.getPeerReviews(); 
  22.     this.getManagerReview(); 
  23.     this.getSelfReview(); 
  24.   } 
  25.  
  26.   getManagerReview() { 
  27.     const manager = this.lookupManager(); 
  28.   } 
  29.  
  30.   getSelfReview() { 
  31.     // ... 
  32.   } 
  33.  
  34. const review = new PerformanceReview(employee); 
  35. review.perfReview(); 
  36.  
  37. //better code 
  38. class PerformanceReview { 
  39.   constructor(employee) { 
  40.     this.employee = employee; 
  41.   } 
  42.  
  43.   perfReview() { 
  44.     this.getPeerReviews(); 
  45.     this.getManagerReview(); 
  46.     this.getSelfReview(); 
  47.   } 
  48.  
  49.   getPeerReviews() { 
  50.     const peers = this.lookupPeers(); 
  51.     // ... 
  52.   } 
  53.  
  54.   lookupPeers() { 
  55.     return db.lookup(this.employee, 'peers'); 
  56.   } 
  57.  
  58.   getManagerReview() { 
  59.     const manager = this.lookupManager(); 
  60.   } 
  61.  
  62.   lookupManager() { 
  63.     return db.lookup(this.employee, 'manager'); 
  64.   } 
  65.  
  66.   getSelfReview() { 
  67.     // ... 
  68.   } 
  69.  
  70. const review = new PerformanceReview(employee); 
  71. review.perfReview(); 

 

責(zé)任編輯:未麗燕 來源: SegmentFault.com
相關(guān)推薦

2021-01-04 07:57:07

C++工具代碼

2022-03-11 12:14:43

CSS代碼前端

2021-09-01 08:55:20

JavaScript代碼開發(fā)

2021-11-30 10:20:24

JavaScript代碼前端

2020-05-14 09:15:52

設(shè)計(jì)模式SOLID 原則JS

2021-12-07 08:16:34

React 前端 組件

2020-07-15 08:17:16

代碼

2020-05-08 14:45:00

JS代碼變量

2020-05-11 15:23:58

CQRS代碼命令

2013-06-07 14:00:23

代碼維護(hù)

2024-03-28 14:29:46

JavaScript編程

2024-12-04 15:10:21

2022-02-08 19:33:13

技巧代碼格式

2022-02-17 10:05:21

CSS代碼前端

2020-12-19 10:45:08

Python代碼開發(fā)

2020-05-19 15:00:26

Bug代碼語言

2021-12-13 14:37:37

React組件前端

2022-10-24 08:10:21

SQL代碼業(yè)務(wù)

2015-09-28 10:49:59

代碼程序員

2019-06-24 10:26:15

代碼程序注釋
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號