目的
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供西安網(wǎng)站建設(shè)、西安做網(wǎng)站、西安網(wǎng)站設(shè)計、西安網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、西安企業(yè)網(wǎng)站模板建站服務(wù),10年西安做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
在我們平時的工作開發(fā)中,大多數(shù)都是大人協(xié)同開發(fā)的公共項目;在我們平時開發(fā)中代碼codeing的時候我們考慮代碼的可讀性、復(fù)用性和擴(kuò)展性。
干凈的代碼,既在質(zhì)量上較為可靠,也為后期維護(hù)、升級奠定了良好基礎(chǔ)。
我們從以下幾個方面進(jìn)行探討:
變量
1、變量命名
一般我們在定義變量是要使用有意義的詞匯命令,要做到見面知義
//bad code const yyyymmdstr = moment().format('YYYY/MM/DD'); //better code const currentDate = moment().format('YYYY/MM/DD');
2、可描述
通過一個變量生成了一個新變量,也需要為這個新變量命名,也就是說每個變量當(dāng)你看到他第一眼你就知道他是干什么的。
//bad code const ADDRESS = 'One Infinite Loop, Cupertino 95014'; const CITY_ZIP_CODE_REGEX = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; saveCityZipCode(ADDRESS.match(CITY_ZIP_CODE_REGEX)[1], ADDRESS.match(CITY_ZIP_CODE_REGEX)[2]); //better code const ADDRESS = 'One Infinite Loop, Cupertino 95014'; const CITY_ZIP_CODE_REGEX = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; const [, city, zipCode] = ADDRESS.match(CITY_ZIP_CODE_REGEX) || []; saveCityZipCode(city, zipCode);
3、形參命名
在for、forEach、map的循環(huán)中我們在命名時要直接
//bad code const locations = ['Austin', 'New York', 'San Francisco']; locations.map((l) => { doStuff(); doSomeOtherStuff(); // ... // ... // ... // 需要看其他代碼才能確定 'l' 是干什么的。 dispatch(l); }); //better code const locations = ['Austin', 'New York', 'San Francisco']; locations.forEach((location) => { doStuff(); doSomeOtherStuff(); // ... // ... // ... dispatch(location); });
4、避免無意義的前綴
例如我們只創(chuàng)建一個對象是,沒有必要再把每個對象的屬性上再加上對象名
//bad code const car = { carMake: 'Honda', carModel: 'Accord', carColor: 'Blue' }; function paintCar(car) { car.carColor = 'Red'; } //better code const car = { make: 'Honda', model: 'Accord', color: 'Blue' }; function paintCar(car) { car.color = 'Red'; }
5、默認(rèn)值
//bad code function createMicrobrewery(name) { const breweryName = name || 'Hipster Brew Co.'; // ... } //better code function createMicrobrewery(name = 'Hipster Brew Co.') { // ... }
函數(shù)
1、參數(shù)
一般參數(shù)多的話要使用ES6的解構(gòu)傳參的方式
//bad code function createMenu(title, body, buttonText, cancellable) { // ... } //better code function createMenu({ title, body, buttonText, cancellable }) { // ... } //better code createMenu({ title: 'Foo', body: 'Bar', buttonText: 'Baz', cancellable: true });
2、單一化處理
一個方法里面最好只做一件事,不要過多的處理,這樣代碼的可讀性非常高
//bad code function emailClients(clients) { clients.forEach((client) => { const clientRecord = database.lookup(client); if (clientRecord.isActive()) { email(client); } }); } //better code function emailActiveClients(clients) { clients .filter(isActiveClient) .forEach(email); } function isActiveClient(client) { const clientRecord = database.lookup(client); return clientRecord.isActive(); }
3、對象設(shè)置默認(rèn)屬性
//bad code const menuConfig = { title: null, body: 'Bar', buttonText: null, cancellable: true }; function createMenu(config) { config.title = config.title || 'Foo'; config.body = config.body || 'Bar'; config.buttonText = config.buttonText || 'Baz'; config.cancellable = config.cancellable !== undefined ? config.cancellable : true; } createMenu(menuConfig); //better code const menuConfig = { title: 'Order', // 'body' key 缺失 buttonText: 'Send', cancellable: true }; function createMenu(config) { config = Object.assign({ title: 'Foo', body: 'Bar', buttonText: 'Baz', cancellable: true }, config); // config 就變成了: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true} // ... } createMenu(menuConfig);
4、避免副作用
函數(shù)接收一個值返回一個新值,除此之外的行為我們都稱之為副作用,比如修改全局變量、對文件進(jìn)行 IO 操作等。
當(dāng)函數(shù)確實需要副作用時,比如對文件進(jìn)行 IO 操作時,請不要用多個函數(shù)/類進(jìn)行文件操作,有且僅用一個函數(shù)/類來處理。也就是說副作用需要在唯一的地方處理。
副作用的三大天坑:隨意修改可變數(shù)據(jù)類型、隨意分享沒有數(shù)據(jù)結(jié)構(gòu)的狀態(tài)、沒有在統(tǒng)一地方處理副作用。
//bad code // 全局變量被一個函數(shù)引用 // 現(xiàn)在這個變量從字符串變成了數(shù)組,如果有其他的函數(shù)引用,會發(fā)生無法預(yù)見的錯誤。 var name = 'Ryan McDermott'; function splitIntoFirstAndLastName() { name = name.split(' '); } splitIntoFirstAndLastName(); console.log(name); // ['Ryan', 'McDermott']; //better code var name = 'Ryan McDermott'; var newName = splitIntoFirstAndLastName(name) function splitIntoFirstAndLastName(name) { return name.split(' '); } console.log(name); // 'Ryan McDermott'; console.log(newName); // ['Ryan', 'McDermott'];
在 JavaScript 中,基本類型通過賦值傳遞,對象和數(shù)組通過引用傳遞。以引用傳遞為例:
假如我們寫一個購物車,通過 addItemToCart()
方法添加商品到購物車,修改 購物車數(shù)組
。此時調(diào)用 purchase()
方法購買,由于引用傳遞,獲取的 購物車數(shù)組
正好是最新的數(shù)據(jù)。
看起來沒問題對不對?
如果當(dāng)用戶點擊購買時,網(wǎng)絡(luò)出現(xiàn)故障, purchase()方法一直在重復(fù)調(diào)用,與此同時用戶又添加了新的商品,這時網(wǎng)絡(luò)又恢復(fù)了。那么 purchase()方法獲取到 購物車數(shù)組就是錯誤的。
為了避免這種問題,我們需要在每次新增商品時,克隆 購物車數(shù)組并返回新的數(shù)組。
//bad code const addItemToCart = (cart, item) => { cart.push({ item, date: Date.now() }); }; //better code const addItemToCart = (cart, item) => { return [...cart, {item, date: Date.now()}] };
5、全局方法
在 JavaScript 中,永遠(yuǎn)不要污染全局,會在生產(chǎn)環(huán)境中產(chǎn)生難以預(yù)料的 bug。舉個例子,比如你在 Array.prototype
上新增一個 diff
方法來判斷兩個數(shù)組的不同。而你同事也打算做類似的事情,不過他的 diff
方法是用來判斷兩個數(shù)組首位元素的不同。很明顯你們方法會產(chǎn)生沖突,遇到這類問題我們可以用 ES2015/ES6 的語法來對 Array
進(jìn)行擴(kuò)展。
//bad code Array.prototype.diff = function diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); }; //better code class SuperArray extends Array { diff(comparisonArray) { const hash = new Set(comparisonArray); return this.filter(elem => !hash.has(elem)); } }
6、避免類型檢查
JavaScript 是無類型的,意味著你可以傳任意類型參數(shù),這種自由度很容易讓人困擾,不自覺的就會去檢查類型。仔細(xì)想想是你真的需要檢查類型還是你的 API 設(shè)計有問題?
//bad code function travelToTexas(vehicle) { if (vehicle instanceof Bicycle) { vehicle.pedal(this.currentLocation, new Location('texas')); } else if (vehicle instanceof Car) { vehicle.drive(this.currentLocation, new Location('texas')); } } //better code function travelToTexas(vehicle) { vehicle.move(this.currentLocation, new Location('texas')); }
如果你需要做靜態(tài)類型檢查,比如字符串、整數(shù)等,推薦使用 TypeScript,不然你的代碼會變得又臭又長。
//bad code function combine(val1, val2) { if (typeof val1 === 'number' && typeof val2 === 'number' || typeof val1 === 'string' && typeof val2 === 'string') { return val1 + val2; } throw new Error('Must be of type String or Number'); } //better code function combine(val1, val2) { return val1 + val2; }
復(fù)雜條件判斷
我們編寫js代碼時經(jīng)常遇到復(fù)雜邏輯判斷的情況,通常大家可以用if/else或者switch來實現(xiàn)多個條件判斷,但這樣會有個問題,隨著邏輯復(fù)雜度的增加,代碼中的if/else/switch會變得越來越臃腫,越來越看不懂,那么如何更優(yōu)雅的寫判斷邏輯
1、if/else
點擊列表按鈕事件
/** * 按鈕點擊事件 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 */ const onButtonClick = (status)=>{ if(status == 1){ sendLog('processing') jumpTo('IndexPage') }else if(status == 2){ sendLog('fail') jumpTo('FailPage') }else if(status == 3){ sendLog('fail') jumpTo('FailPage') }else if(status == 4){ sendLog('success') jumpTo('SuccessPage') }else if(status == 5){ sendLog('cancel') jumpTo('CancelPage') }else { sendLog('other') jumpTo('Index') } }
從上面我們可以看到的是通過不同的狀態(tài)來做不同的事情,代碼看起來非常不好看,大家可以很輕易的提出這段代碼的改寫方案,switch出場:
2、switch/case
/** * 按鈕點擊事件 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 */ const onButtonClick = (status)=>{ switch (status){ case 1: sendLog('processing') jumpTo('IndexPage') break case 2: case 3: sendLog('fail') jumpTo('FailPage') break case 4: sendLog('success') jumpTo('SuccessPage') break case 5: sendLog('cancel') jumpTo('CancelPage') break default: sendLog('other') jumpTo('Index') break } }
這樣看起來比if/else清晰多了,細(xì)心的同學(xué)也發(fā)現(xiàn)了小技巧,case 2和case 3邏輯一樣的時候,可以省去執(zhí)行語句和break,則case 2的情況自動執(zhí)行case 3的邏輯。
3、存放到Object
將判斷條件作為對象的屬性名,將處理邏輯作為對象的屬性值,在按鈕點擊的時候,通過對象屬性查找的方式來進(jìn)行邏輯判斷,這種寫法特別適合一元條件判斷的情況。
const actions = { '1': ['processing','IndexPage'], '2': ['fail','FailPage'], '3': ['fail','FailPage'], '4': ['success','SuccessPage'], '5': ['cancel','CancelPage'], 'default': ['other','Index'], } /** * 按鈕點擊事件 * @param {number} status 活動狀態(tài):1開團(tuán)進(jìn)行中 2開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 */ const onButtonClick = (status)=>{ let action = actions[status] || actions['default'], logName = action[0], pageName = action[1] sendLog(logName) jumpTo(pageName) }
4、存放到Map
const actions = new Map([ [1, ['processing','IndexPage']], [2, ['fail','FailPage']], [3, ['fail','FailPage']], [4, ['success','SuccessPage']], [5, ['cancel','CancelPage']], ['default', ['other','Index']] ]) /** * 按鈕點擊事件 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消 */ const onButtonClick = (status)=>{ let action = actions.get(status) || actions.get('default') sendLog(action[0]) jumpTo(action[1]) }
這樣寫用到了es6里的Map對象,是不是更爽了?Map對象和Object對象有什么區(qū)別呢?
一個對象通常都有自己的原型,所以一個對象總有一個"prototype"鍵。
一個對象的鍵只能是字符串或者Symbols,但一個Map的鍵可以是任意值。
你可以通過size屬性很容易地得到一個Map的鍵值對個數(shù),而對象的鍵值對個數(shù)只能手動確認(rèn)。
代碼風(fēng)格
常量大寫
//bad code const DAYS_IN_WEEK = 7; const daysInMonth = 30; const songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude']; const Artists = ['ACDC', 'Led Zeppelin', 'The Beatles']; function eraseDatabase() {} function restore_database() {} class animal {} class Alpaca {} //better code const DAYS_IN_WEEK = 7; const DAYS_IN_MONTH = 30; const SONGS = ['Back In Black', 'Stairway to Heaven', 'Hey Jude']; const ARTISTS = ['ACDC', 'Led Zeppelin', 'The Beatles']; function eraseDatabase() {} function restoreDatabase() {} class Animal {} class Alpaca {}
先聲明后調(diào)用
//bad code class PerformanceReview { constructor(employee) { this.employee = employee; } lookupPeers() { return db.lookup(this.employee, 'peers'); } lookupManager() { return db.lookup(this.employee, 'manager'); } getPeerReviews() { const peers = this.lookupPeers(); // ... } perfReview() { this.getPeerReviews(); this.getManagerReview(); this.getSelfReview(); } getManagerReview() { const manager = this.lookupManager(); } getSelfReview() { // ... } } const review = new PerformanceReview(employee); review.perfReview(); //better code class PerformanceReview { constructor(employee) { this.employee = employee; } perfReview() { this.getPeerReviews(); this.getManagerReview(); this.getSelfReview(); } getPeerReviews() { const peers = this.lookupPeers(); // ... } lookupPeers() { return db.lookup(this.employee, 'peers'); } getManagerReview() { const manager = this.lookupManager(); } lookupManager() { return db.lookup(this.employee, 'manager'); } getSelfReview() { // ... } } const review = new PerformanceReview(employee); review.perfReview();
以上就是淺談寫出優(yōu)雅耐看 JS代碼 的方法的詳細(xì)內(nèi)容,更多請關(guān)注創(chuàng)新互聯(lián)其它相關(guān)文章!
網(wǎng)頁名稱:如何寫出高質(zhì)量的javascript代碼
網(wǎng)站鏈接:http://www.rwnh.cn/article32/gcgpsc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、App設(shè)計、網(wǎng)站策劃、定制網(wǎng)站、網(wǎng)站營銷、網(wǎng)站維護(hù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)