学习过 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.jianshu.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
未完待续……