學習過 ES 6 有一段時間了,也在現有的項目中投入了使用,新的語法讓代碼的可讀性大大提高,這對項目的可維護性是至關重要的,在這里記錄下一些在實戰項目中比較常用的語法,以及新語法對舊語法的對比。
干凈的作用域 let, const 和 {}
以往寫 JS 最怕的就是變量污染了,當項目太大,var
聲明的變量到處都是,重復聲明 console 沒有報錯,很不好調試,有了let
和const
,當你變量重復聲明或者犯了其他錯誤時,console 都會報錯,讓代碼更加規范:
1. 用const
聲明一個常量
const URL = 'http://www.google.com'; // 不再變化,嘗試修改它會報錯
// 舊的寫法
var URL = 'http://www.google.com'; // 修改不會報錯
2. 用 let
解決 for
循環索引變化的問題
// 循環結束`i`被垃圾回收,`i`只在循環體中生效
for (let i = 0; i < 6; i++) {
// do something
}
console.log(i); // undefined
// 舊的寫法,循環結束后`i`的值為 5,這并不是我們期望的
for (var i = 0; i < 6; i++) {
// do something
}
console.log(i); // 5
3. 用{}
替換難以理解的閉包作用域
{
// do someting
}
// 舊的寫法(IIFE寫法),對新手來說這個語法很不友好
(function() {
// do someting
}());
注意:大部分場景使用的還是const
,而不是let
JS 的 const
和其他語言有點小區別,當我們定義的變量后續不會再改變的時候,我們就應該使用const
,只有明確了變量會改變,才會使用let
:
// 定義一個常量
const URL = 'http://www.lxweimin.com/api/posts/id';
// 獲取一個 dom 元素
const $modal = $('.modal');
// 定義一個書的實體,即使你修改了書的屬性,也是用 const
const book = {};
book.title = '圍城';
book.author = '錢鐘書';
// webpack 引入一個模塊
const vue = require('vue');
快速提取參數,變量解構賦值
解構可以理解為從指定的數組或者對象中提取數組元素或者對象屬性的值,然后賦值到指定變量中:
1. 快速交換變量
// 交換`x`, `y`和`z`的值
let x = 1, y = 2, z = 3;
[x, y, z] = [z, x, y];
console.log(x, y, z); // 3 1 2
// 舊的寫法
var x = 1, y = 2, z = 3;
var temp = x; // 臨時變量
x = z;
z = y;
y = temp;
console.log(x, y, z); // 3 1 2
2. 定義函數默認值
let fn = function({
foo = 1,
bar = 'foo',
hello = false
}) {
console.log(foo, bar, hello);
};
fn(); // 1, foo, false
// 舊的寫法
let fn = function(foo, bar, hello) {
var foo = foo || 1;
var bar = bar || 'foo';
var hello = hello || false;
console.log(foo, bar, hello);
};
fn(); // 1, foo, false
3. 快速提取模塊中的子模塊
// ES 6 的模塊語法
import {selector, spinner} from 'Bootstrap.js'
// require.js
const { SourceMapConsumer, SourceNode } = require("source-map");
4. 遍歷時快速提取變量
const books = [{
title: '圍城',
author: '錢鐘書',
}, {
title: '三國演義',
author: '羅貫中'
}];
{ title, author } 相當于一個 `book` 變量
books.map(({ title, author }) => console.log(title, author));
// 舊的寫法
books.map(function(book) {
console.log(book.title, book.author);
});
很有用的字符串擴展
JS 的字符串函數一直都是殘缺不齊的,一個indexOf
用來做了太多的功能,而 ES 6 提供了很多語義化的函數來方便開發:
1. 便捷函數includes()
, startsWith()
, endsWith()
// 這三個函數都返回布爾值,不需要再去繁瑣的判斷`indexOf`返回的數值了
'hello world'.includes('wor'); // true
'hello world'.startsWith('he'); // true
'hello world'.endsWith('he'); // false
// 舊的寫法,代替語意不明確的indexOf
'hello world'.indexOf('wor') !== -1;
2. 模板字符串,漂亮的寫法
新的模板字符串``
可以使 html 片段的引入更加美觀與規范,嵌入的變量名的形式為${var}
,大括號中支持js的語法,非常實用:
const basket = { count: 1, onSale: 'iPhone' };
// 模板字符串,空格和縮進都會留著,即保留格式
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em> // 這里替換為變量的值
are on sale!
<p>${basket.count + basket.add}</p>
`);
// 舊的寫法
$('#result').append(
'There are <b>' + basket.count + '</b> ' +
'items in your basket, ' +
'<em>' + basket.onSale +
'</em> are on sale!'
);
在模板字符串中使用函數
const books = [{
title: '圍城',
author: '錢鐘書',
}, {
title: '三國演義',
author: '羅貫中'
}];
const html = `
<ul>
${ books.map(book =>
`<li>
<div>${ book.title }</div>
<div>${ book.author }</div>
</li>`
).join('') }
</ul>
`
console.log(html)
/**
<ul>
<li>
<div>圍城</div>
<div>錢鐘書</div>
</li><li>
<div>三國演義</div>
<div>羅貫中</div>
</li>
</ul>
*/
注意:使用模板字符串要注意防止 XSS 攻擊
function escapeHtml(text) {
var map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
const html = `${escapeHtml(user_input)}`;
告別不嚴謹的 Number 類型判斷
1. Number.isFinite()
, Number.isNaN()
, Number.isInteger()
JS 一直有個讓人詬病的地方,就是類型不夠嚴謹,就連在類型判斷上都太過于靈活,新的幾個函數輕松解決這些問題,再也不用覺得 Number
類型不夠好了:
// 判斷是否為有限數值
Number.isFinite(7); // true
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
// 判斷是否為 NaN 類型
Number.isNaN(NaN) // true
// 判斷是否為整數
Number.isInteger(25) // true
2. 常用的數學函數,取整,判斷正負
// 去除小數部分,返回整數部分
Math.trunc(5.333); // 5
// 判斷是否為正數,負數,0
// 參數為正數,返回+1;
// 參數為負數,返回-1;
// 參數為0,返回0;
// 參數為-0,返回-0;
// 其他值,返回NaN。
Math.sign(-5) // -1
對不好用的數組說再見
1. 用Array.from()
將類似數組的對象轉換為數組
// 轉換arguments
const fn = function() {
const args = Array.from(arguments);
args.forEach((arg) => console.log(arg)); // 數組才能用 forEach 等方法
}
// 轉換 原生 dom 返回的 NodeList
const lis = document.querySelectorAll('li');
const arrLis = Array.from(lis);
arrLis.forEach((li) => console.log(li)); // 數組才能用 forEach 等方法
// 使用拓展符也可以達到這種效果
const fn = function() {
const args = [...arguments];
args.forEach((arg) => console.log(arg)); // 數組才能用 forEach 等方法
}
// 轉換NodeList
const arrLis = [...document.querySelectorAll('li')];
arrLis.forEach((li) => console.log(li)); // 數組才能用 forEach 等方法
2. Array.of()
快速組合數組
const x = 'wynne', y = 'zheng';
console.log(Array.of(x, y)); // ['wynne', 'zheng']
// 舊的寫法
const x = 'wynne', y = 'zheng';
const arr = [x, y]; // ['wynne', 'zheng']
3. 超級實用的查找功能 find()
& findIndex()
,includes()
1.find()
可以通過回調函數進行數組篩選,返回該成員,而findIndex()
返回索引
const books = [{
title: '圍城',
author: '錢鐘書',
}, {
title: '三國演義',
author: '羅貫中'
}];
const item = books.find(({ title, author }) => title === '圍城');
console.log(item); // { title: '圍城', author: '錢鐘書' }
// 舊的寫法
var books = [{
title: '圍城',
author: '錢鐘書',
}, {
title: '三國演義',
author: '羅貫中'
}];
var item = null;
books.forEach(function() {
if (value > 3) {
item = value;
return;
}
});
console.log(item); // { title: '圍城', author: '錢鐘書' }
2. 判斷是否存在于數組中,用includes()
代替語意差的indexOf
const books = [{
title: '圍城',
author: '錢鐘書',
}, {
title: '三國演義',
author: '羅貫中'
}];
console.log(arr.includes( { title: '圍城', author: '錢鐘書' } ); // true
未完待續……