兼容 IE 沃呢?不存在的好嗎。
其實(shí)使用新語法配合 babel
的轉(zhuǎn)碼饼酿,已經(jīng)可以解決這一些問題了吭敢。既然如此,那就多使用新語法去探索一下怎么更好的去寫代碼吧缭受。
下面分享個人開發(fā)中常用的 js 寫法技巧胁澳,希望對各位有所幫助。
使用 let / const
var
命令會發(fā)生”變量提升“現(xiàn)象米者,即變量可以在聲明之前使用韭畸,值為 undefined
。這種現(xiàn)象多多少少是有些奇怪的塘雳。
個人認(rèn)為陆盘,對聲明的變量確定后面不會發(fā)生更改時,即使性能上沒有太大提升差異在败明,但使用 const
, 代碼的可讀性也會增強(qiáng)很多隘马。
-
const
實(shí)際上保證的,并不是變量的值不得改動妻顶,而是變量指向的那個內(nèi)存地址所保存的數(shù)據(jù)不得改動酸员。 -
let
變量指向的內(nèi)存地址,保存的只是一個指向?qū)嶋H數(shù)據(jù)的指針
補(bǔ)充 const
定義的變量不是數(shù)據(jù)不可變讳嘱,而是保存的引用地址不能發(fā)生改變幔嗦。例子如下:
const person = { age: 22 }
person.age = 1
console.log(person.age ) // 1
詳情看 let 和 const 命令
解構(gòu)賦值
ES6
允許按照一定模式,從數(shù)組和對象中提取值沥潭,對變量進(jìn)行賦值邀泉,這被稱為解構(gòu)(Destructuring
)。
好處就是:解決了訪問多層嵌套的對象或數(shù)組的命名,減少代碼量
聲明多個變量:
// 聲明變量
let age = 22
let name = 'guodada'
let sex = 1
// better
let [age, name, sex] = [22, 'guodada', 1]
console.log(age, name, sex) // 22, guodada, 1
使用在對象中:
const obj = {
name: {
firstName: 'guo',
lastName: 'dada'
}
}
// 提取變量
const firstName = obj.name.firstName
const lastName = obj.name.lastName
// better
const { firstName, lastName } = obj.name
使用在函數(shù)中:
// 在參數(shù)中結(jié)構(gòu)賦值汇恤,獲取參數(shù), 當(dāng)參數(shù)多的使用時候十分方便
function Destructuring({ name, age }) {
return { name, age } // 相當(dāng)于 { name: name, age: age } , 可以簡寫
}
const params = { name: 'guodada', age: 22 }
Destructuring(params)
更多用法見 變量的解構(gòu)賦值
ES6 允許在對象之中庞钢,直接寫變量。這時因谎,屬性名為變量名, 屬性值為變量的值基括。
function f(x, y) {
return {x: x, y: y};
}
// better
function f(x, y) {
return {x, y};
}
f(1, 2) // Object {x: 1, y: 2}
擴(kuò)展符的運(yùn)用
es6 擴(kuò)展符有很多用法,他可以使你的代碼更加簡潔财岔,易懂风皿。這里就舉例常用的用法
在對象中的用法:
let obj = {
name: 'guodada',
age: 22,
sex: 1
}
// 復(fù)制對象。擴(kuò)展符為淺復(fù)制=宠怠M┛睢!
const copy = { ...obj }
// 修改對象屬性值(生成新對象) 相當(dāng)于 Object.assgin({}, obj, { age: 18 })
const newObj = { ...obj, age: 18 }
// 結(jié)合結(jié)構(gòu)賦值
let { sex, ...z } = obj
z // { name: 'guodada', age: 22 }
在數(shù)組中的用法:
const arr = [1, 2, 3]
const arr2 = [4, 5, 6, 4]
// 復(fù)制數(shù)組患朱。擴(kuò)展符為淺復(fù)制B沉拧!裁厅!
const newArr = [...arr] // ...[1, 2, 3] => 相當(dāng)于展開數(shù)組:1, 2, 3
// 合并數(shù)組
const conbineArr = [...arr, ...arr2]
// 結(jié)合求最大值函數(shù)
Math.max(...arr)
// 結(jié)合 Set 實(shí)現(xiàn)數(shù)組去重。注意:json 等對象數(shù)組不可用
[...new Set(arr2)] // [4, 5, 6]
擴(kuò)展符的其他用法請自行查資料侨艾。
數(shù)組用法
const arr = [1, 2, 3, 4]
Array.isArray(arr) // 判斷是否為數(shù)組
arr.includes(2) // true 判斷數(shù)組中是否包含某項
arr.findIndex(d => d === 3) // 2 找出第一個符合條件的數(shù)組成員并返回數(shù)組下標(biāo), 找不到返回 -1
arr.find(d => d === 3) // 3 找出第一個符合條件的數(shù)組成員并返回, 找不到返回 undefined
// es5 其他還有 filter map forEach 等执虹,這里不做舉例。
arr.every(d => d > 2) // false 每一項都滿足條件則返回 true
arr.some(d => d > 2) // true 只要有一項滿足條件則返回 true
find/findIndex
: 找出第一個符合條件的數(shù)組成員之后不再匹配唠梨,一定程度下優(yōu)化查找袋励。
includes
: 返回 true/false
, 相較于 indexOf
, 實(shí)用多了
-
flat()
: 扁平化數(shù)組,常用于將數(shù)組轉(zhuǎn)化為一維數(shù)組const arr = [1, 2, [3, 4]] arr.flat() // [1, 2, 3, 4] 扁平化數(shù)組, 默認(rèn)展開一層当叭。 const arr2 = [1, 2, [3, 4, [5, 6]]] arr2.flat() // [1, 2, 3, 4, [5, 6]] arr2.flat(2) // [1, 2, 3, 4, 5, 6] flat(3) 也是展開兩層...
-
flatMap()
: 在數(shù)組執(zhí)行map
方法后執(zhí)行flat
, 用的不多茬故,其實(shí)可以寫map
后寫flat
更好懂點(diǎn)。[2, 3, 4].flatMap(x => [x, x * 2]) // [ 2, 4, 3, 6, 4, 8 ] // 1. [2, 3, 4].map(d => [d, d * 2]) => [[2, 4], [3, 6], [4, 8]] // 2. [[2, 4], [3, 6], [4, 8]].flat()
補(bǔ)充常用的對象轉(zhuǎn)數(shù)組的用法:
const obj = { name: 'guodada' }
Object.keys(obj) // ['name']
Object.values(obj) // ['guodada']
Object.entries(obj) // [['name', 'guodada']]
模板字符串
用的挺多的蚁鳖,注意不兼容 IE
!
const name = 'guodada'
const newStr = `welcome ${name}` // welcome guodada
// the same as
const newStr = 'welcome ' + name
使用 async / await
async/await
實(shí)際上就是 generator
的語法糖, 主要用來解決異步問題磺芭,具體網(wǎng)上很多文章都有介紹,這里就不做多的解釋吧醉箕。
async function test() {
const data = await axios.get('https://randomuser.me/api/')
console.log(data)
}
// 等同于
function test() {
axios.get('https://randomuser.me/api/').then(res => console.log(res)) // axios 也是 promise 對象
}
// 結(jié)合try/catch
async function test() {
try {
const data = await axios.get('https://randomuser.me/api/')
console.log(data)
} catch (err) {
console.log(err)
}
}
ps 雖然好用钾腺,但是有時候適用場景不好,比如我們在拉取列表和用戶信息需要同時進(jìn)行時讥裤,await
后才執(zhí)行下一條語句放棒,這不是我們希望看到的。解決方法如下:
// 結(jié)合 Promise.all
const [result1, result2, result3] = await Promise.all([anAsyncCall(), thisIsAlsoAsync(), oneMore()])
傳送門:async 函數(shù)
利用 class 封裝代碼
主要是抽離代碼邏輯己英,使得代復(fù)用性加強(qiáng)间螟。同時,class
的形式會讓結(jié)構(gòu)變得更加清晰,譬如:
class MyForm {
/**
* @func defaultLimit - 默認(rèn)表單輸入限制條件, value 為空時返回 true
* @param {Number} type - 代表表單類型的節(jié)點(diǎn)厢破!
* @param {String} value - 需要被驗證的值
* @return Boolean
*
* 根據(jù) type 屬性對輸出進(jìn)行驗證
* 1 0≤x≤50 整數(shù)
* 2 -1000≤x≤2000 整數(shù)
* 3 1≤x 整數(shù)
* 4 0≤x≤10
*/
static defaultLimit(type, value) {
const typeLimitMap = {
1: /^(\d|[1-4]\d|50)$/g,
2: /^-?(\d{1,3}|1000)$|^(-|1\d{3}|2000)$/,
3: /^[1-9]\d*$/,
4: value => value <= 10 && value >= 0 // 0≤ x ≤ 10 可以為小數(shù)
}
if (!typeLimitMap[type] || !value) return true
if (typeof typeLimitMap[type] === 'function') return typeLimitMap[type](value)
else return typeLimitMap[type].test(value)
}
/**
* @func translateLimit - 轉(zhuǎn)換操作符
* @param {String} operator - 運(yùn)算符
* @param {*} value - 被匹配的值
* @param {*} compareValue - 匹配的值
* @return Boolean
* 'eq': '='
* 'ne': '≠'
* 'gt': '>'
* 'lt': '<'
* 'ge': '≥'
* 'le': '≤'
*/
static translateLimit(operator, value, compareValue) {
const type = {
eq: value === compareValue,
ne: value !== compareValue,
gt: value > compareValue,
lt: value < compareValue,
ge: value >= compareValue,
le: value <= compareValue
}
if (!Object.keys(type).includes(operator) || !value || value === '-') return true
return type[operator]
}
// ...
}
export default MyForm
使用:
import MyForm from './MyForm'
MyForm.defaultLimit(1, 20)
-
static
:靜態(tài)屬性邮府,類可以直接調(diào)用 -
constructor
: 實(shí)例化類的時候調(diào)用,即new MyForm()
, 這里沒用到
更多知識請閱 Class 的基本語法
優(yōu)化 if/else 語句
當(dāng)邏輯或
||
時溉奕,找到為true
的分項就停止處理褂傀,并返回該分項的值,否則執(zhí)行完加勤,并返回最后分項的值仙辟。當(dāng)邏輯與
&&
時,找到為false
的分項就停止處理鳄梅,并返回該分項的值叠国。
const a = 0 || null || 3 || 4
console.log(a) // 3
const b = 3 && 4 && null && 0
console.log(b) // null
減少 if / else
地獄般的調(diào)用
const [age, name, sex] = [22, 'guodada', 1]
if (age > 10) {
if (name === 'guodada') {
if (sex > 0) {
console.log('all right')
}
}
}
// better 使用 &&
if (age > 10 && name === 'guodada' && sex > 0) {
console.log('all right')
}
// 或者(太長了不推薦)
age > 10 && name === 'guodada' && sex > 0 && console.log('all right')
提一下 react
的坑點(diǎn), 在 render
中
render(){
const arr = []
return arr.length && null
}
// 渲染出 0 !
// Boolean / undefind / null / NaN 等才不會渲染戴尸。我們可以使用 !! 強(qiáng)制轉(zhuǎn)化為 boolean 解決這個問題
return !!arr.length && null
// 使用 && 控制組件的渲染
this.state.visible && <Modal />
使用 Array.includes
來處理多重條件:
const ages = [18, 20, 12]
if (age === 18 || age === 12) {
console.log('match')
}
// better
if ([18, 12].includes(age)) {
console.log('match')
}
如果是較少的判斷邏輯則可以使用三元運(yùn)算符:
const age = 22
const isAdult = age >= 18 ? true : false // 這里可以寫為 const isAdult = age > 18
const type = age >= 18 ? 'adult' : 'child'
優(yōu)化 switch/case 語句
switch/case
比 if/else
代碼結(jié)構(gòu)好點(diǎn)粟焊,但也和它一樣有時十分冗長。
這里以自己實(shí)際項目中代碼舉例:
有時我們可能需要對不同類型的字段進(jìn)行不一樣的正則驗證孙蒙,防止用戶錯誤地輸入项棠。譬如
const [type, value] = [1, '20']
/**
* 根據(jù) type 屬性對輸出進(jìn)行驗證
* 1 0≤x≤50 整數(shù)
* 2 -1000≤x≤2000 整數(shù)
* 3 1≤x 整數(shù)
*/
function func1(type, value) {
if (type === 1) {
return /^(\d|[1-4]\d|50)$/.test(value)
} else if (type === 2) {
return /^-?(\d{1,3}|1000)$|^(-|1\d{3}|2000)$/.test(value)
} else if (type === 3) {
return /^[1-9]\d*$/.test(value)
} else {
return true
}
}
func1(type, value)
// 使用 switch/case
function fun2(type, value) {
switch (type) {
case 1:
return /^(\d|[1-4]\d|50)$/.test(value)
case 2:
return /^-?(\d{1,3}|1000)$|^(-|1\d{3}|2000)$/.test(value)
case 3:
return /^[1-9]\d*$/.test(value)
default:
return true
}
}
func2(type, value)
我們?nèi)绾吻擅畹慕鉀Q這個代碼冗長的問題呢,如下:
function func3(type, value) {
const limitMap = {
1: /^(\d|[1-4]\d|50)$/g,
2: /^-?(\d{1,3}|1000)$|^(-|1\d{3}|2000)$/,
3: /^[1-9]\d*$/
}
return limitMap[type].test(value)
}
利用對象去匹配屬性值挎峦,可以減少你的代碼量香追,也使你的代碼看起來更加簡潔。你也可以使用 Map
對象去匹配坦胶。
function func4(type, value) {
const mapArr = [
[1, /^(\d|[1-4]\d|50)$/g],
[2, /^-?(\d{1,3}|1000)$|^(-|1\d{3}|2000)$/],
[3, /^[1-9]\d*$/]
]
const limitMap = new Map(mapArr)
return limitMap.get(type).test(value)
}
Map
是一種鍵值對的數(shù)據(jù)結(jié)構(gòu)對象透典,它的匹配更加嚴(yán)格。它會區(qū)分開你傳遞的是字符串還是數(shù)字顿苇,譬如:
limitMap.get(1) // /^(\d|[1-4]\d|50)$/g
limitMap.get('1') // undefined
更多詳見 Set 和 Map 數(shù)據(jù)結(jié)構(gòu)
其他
- 函數(shù)參數(shù)默認(rèn)值
function func(name, age = 22) {} // 等同于 function func(name, age) { age = age || 22 }
- 使用
===
代替==
峭咒。其實(shí)大家都懂這個的。纪岁。凑队。 - 箭頭函數(shù),es6 最常用的語法蜂科。
- return boolean
const a = 1 return a === 1 ? true : false // 多此一舉了顽决,其實(shí)就等于 return a === 1
敬請各位補(bǔ)充。交流才能進(jìn)步导匣,相視一笑才菠,嘿嘿。