ES6 ES2015
所有属性
详情见 简书 ES6
ES6
- let const
- =>箭头函数
没有 arguments,可以使用扩展运算符(…)传递不定参数
不能作为构造函数
适应于那些本来就需要匿名函数的地方 - Set,Map
- …
- 解构赋值
- for of 遍历数组、Set、Map 结构、类数组,字符串
- es6 Module
- 扩展操作符
- class,extends
- Symbol
Proxy 代理,第一代理监听对象的操作
用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)Reflect
是一个内置对象,提供拦截 JS 操作的方法。这些方法与Proxy
的方法相同。Reflect
不是一个函数对象,因此它是不可构造的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21const observe = (data, callback) => {
return new Proxy(data, {
get(target, key) {
return Reflect.get(target, key)
},
set(target, key, value, proxy) {
callback(key, value);
target[key] = value;
return Reflect.set(target, key, value, proxy)
}
})
}
const FooBar = {
open: false
};
const FooBarObserver = observe(FooBar, (property, value) => {
property === 'open' && value ? console.log('FooBar is open!!!') : console.log('keep waiting');
})
console.log(FooBarObserver.open) //false
FooBarObserver.open = true; //FooBar is open!!!
console.log(FooBarObserver.open) //true如果对象带有
configurable: false
跟writable: false
属性,则代理失效。Promise 见JS-Promise
- 函数参数默认值
- 模板字符串
- 对象属性简写
- 迭代器、生成器
1 | function* makeRangeIterator(start = 0, end = Infinity, step = 1) { |
Set/WeakSet
Set
对象允许存储任何类型的惟一值,无论是原始值还是对象引用。可以使用Set
去重。WeakSet
和Set
的区别:WeakSet
对象只存放对象的引用,不存放值。WeakSet
对象中存储的对象值都是被弱引用的, 如果没有其他的变量或属性引用这个对象值, 则这个对象值会被当成垃圾回收掉. 正因为这样,WeakSet
对象是无法被枚举的, 没有办法拿到它包含的所有元素。
1
2
3
4
5
6
7
8
9
10let ws = new WeakSet();
let obj = {};
let foo = {};
ws.add(window);
ws.add(obj);
console.log(ws.has(window)); //true 是否含有对象
console.log(ws.has(foo)); //false
ws.delete(window); //删除
console.log(ws.has(window));
ws.clear() // 清空整个 WeakSet 对象Map/WeakMap
Map
对象保存键值对。任何职(对象或原始值)都可以作为一个键或一个值。1
2
3
4
5var myMap = new Map();
myMap.set(NaN, 'Not a number');
console.log(myMap.get(NaN)); //'not a number'
let otherNaN = Number('foo');
console.log(myMap.get(otherNaN)) //'not a number'WeakMap
对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17let wm1 = new WeakMap();
let wm2 = new WeakMap();
let o1 = {},
o2 = function () {},
o3 = window;
wm1.set(o1, 37);
wm1.set(o2, 'aaa');
wm2.set(o1, o2); //value 可以是任意值,包括对象
wm2.set(o3, undefined);
console.log(wm1.get(o1));
console.log(wm1.get(o2));
console.log(wm2.get(o2));
console.log(wm2.get(o3));
console.log(wm1.has(o2)); // true
console.log(wm2.has(o2)); // false
wm1.delete(o1);
console.log(wm1.get(o1)); //undefinedMath
对象的扩展Number.EPSILON
:数值最小精度Number.isFinite()
: 是否为有限数值Number.isNaN()
: 是否为 NaNNumber.isInteger()
: 是否为整数Number.isSafeInteger()
: 是否在数值安全范围内
Array
对象的扩展Array.from()
转换具有Interator
接口的数据结构为真正的数组,返回新数组。Array.of()
将参数转换为数组,返回新数组1
2
3
4Array.of(7) // [7]
Array.of(1, 2, 3) // [1, 2, 3]
Array(7) // [empty, empty, empty, empty, empty, empty]
Array(1, 2, 3) // [1, 2, 3]Array.prototype.copyWithin(target,start[,end])
把指定位置的成员复制到其他位置,返回新数组1
2
3const array1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
console.log(array1.copyWithin(0, 3, 4));//["d", "b", "c", "d", "e", "f", "g"]
console.log(array1.copyWithin(1, 3));//["d", "d", "e", "f", "g", "f", "g"]Array.prototype.find()
:返回第一个符合条件的成员Array.prototype.findIndex()
:返回第一个符合条件的成员索引值Array.prototype.fill(value, start,end)
:根据指定值填充整个数组,修改并返回原数组- value,数组的填充值
- start, 开始下标,默认 0
- end,结束下标,默认数组长度,缺省或者结束下标大于数组长度-开始坐标时填充到数组最后一个元素
1
2
3
4
5
6
7const array1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
array1.fill(0, 2, 4);
console.log(array1); //["a", "b", 0, 0, "e", "f", "g"]
array1.fill(5, 4);
console.log(array1);//["a", "b", 0, 0, 5, 5, 5]
array1.fill(7, 4, 10);
console.log(array1);// ["a", "b", 0, 0, 7, 7, 7]
面试题
1. let、const、var
的区别
var
声明的变量存着变量提升,let
和const
声明的变量存在暂时性死区不会提升。var
声明的变量只有全局作用域和函数作用域,没有块级作用域,但是let
和const
声明的变量存着块级作用域(一对{}
之间);- 全局作用域下
let
和const
什么的变量不会被挂载到 window 上,但是var
声明的全局变量会挂载到 window 上 var
可以重复声明相同变量,let
和const
会报错const
声明后必须赋值,否则报错。改变const
变量也会报错
2. 暂存性死区
在变量初始化前访问该变量会导致 ReferenceError。该变量处在一个自块顶部到初始化处理的“暂存死区”中。
1 | function test(){ |
3. 模块化
为什么要模块化?好处
- 解决命名冲突
- 提供复用性
- 提供代码可维护性
立即执行函数
1 | (function(globalVariable){ |
AMD 和 CMD
1 | //AMD |
CommonJS
1 | //a.js |
详见《JS-CommonJS》
ES Module
ES Module 是原生实现的模块化方案,与 CommonJS 有以下几个区别:
CommonJS
支持动态导入,就是require(${path}/xx.js)
,ES Module
不支持,但是已有提案。CommonJS
是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不是很大。ES Module
是异步导入,因为浏览器需要下载文件,如果也采用同步导入就会对渲染有很大影响。CommomnJS
在导出时是值拷贝,导入之后就跟脚本的变化无关,如果需要更新就要清除缓存,重新导入。ES Module
采用实时绑定的方式,导入导出的值指向同一内存地址,,所以导入值会跟随导出值变化。
1 | // 引入模块 API |
注意:
- 重命名使用
as
- import 命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面改写接口,报错。
- import 命令具有提升效果,会提升到整个模块的头部,首先执行。
- import 是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
4.使用箭头函数应该注意什么
- 箭头函数里面的
this
不在指向window
,而是父级 - 不可以作为构造函数,不能使用
new
命令 - 不可以使用
arguments
对象,不存在,可以使用rest
代替 - 不可以使用
yield
命令,因此箭头函数不能用作Generator
函数
5.ES6 模板字符串有哪些新特性?并实现一个类模板字符串的功能
- 基本的字符串格式化。
- 字符串拼接
1 | let name = 'web'; |
6.Set 和 Map 的区别
- Set
- 成员不能重复
- 键名和键值相同,类似数组
- 可以遍历
- 所有值按照设置顺序排列
- 无法通过迭代器直接改变值(因为键值就是键名)
- Map:
- 本质上是健值对的集合,类似集合
- 键名不允许重复
- 可以遍历,可以跟各种数据格式转换
- 键是不能修改的,但是其键对应的值是可以修改的
7.使用结构赋值,实现两个变量的值的交换
1 | let a=1,b=2; |
8.设计一个对象,键名的类型至少包含一个 symbol 类型,并且实现遍历所有 key
1 | let obj={ |
9.set
1 | let s = new Set(); |
注意:数组(对象)是引用类型,所以两个是不相等的。另外在 Set 内部,两个 NaN 是相等
10.理解 async/await 以及对 Generator 的优势
async 函数是 Generator 函数的语法糖。
当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。可以理解,await 后面的语句是放到 Promise.then()去执行的。
async 较 Generator 的优势:
(1)内置执行器。Generator 函数的执行必须依靠执行器,而 Aysnc 函数自带执行器,调用方式跟普通函数的调用一样
(2)更好的语义。async 和 await 相较于 * 和 yield 更加语义化
(3)更广的适用性。yield 命令后面只能是 Thunk 函数或 Promise 对象,async 函数的 await 后面可以是 Promise 也可以是原始类型的值
(4)返回值是 Promise。async 函数返回的是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用
11. forEach、for in、for of 三者区别
forEach
更多的用来遍历数组for key in
一般常用来遍历对象或 jsonfor of
数组,可以通过 Object.keys()获取对象 key 遍历对象
12. Proxy 来实现一个数据响应式
1 | let onWatch = (obj, setBind, getLogger) => { |
搭建环境
利用 gulp 将 es6 转为 es5
目录结构
全局模块安装
1 | sudo npm install babel-cli -g |
package.json
1 | { |
babel 配置
1 | { |
gulp 配置
1 | var gulp = require('gulp'); |