ES6初学习总结-读《阮一峰:ECMAScript 6 入门》
es6关键词:
- 块级作用域
- 脱离顶层对象
- 解构
- 箭头函数
- Set和Map
- 异步编程更强大
还没仔细看的:
- Promise
- 正则
- 数值
- Symbol
- Proxy
- Reflect
- Iterator
let命令
let命令类似var,声名变量
-
暂时性死区
let命令只在它所在的代码块内有效,它声明的变量一定要在声明后才能使用(不会发生变量提升问题,即脚本运行前,变量不存在)
for(let i = 0 ; i < 10; i++) { console.log(i); }
var所在文件中有效
es6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭的作用域。凡是在声明之前就使用这些变量,就会报错。
-
不允许重复声明,所以在函数内部也不能重新声明参数
//报错 function(){ let a = 10; var a = 1; } //报错 function(){ let a = 10; let a = 1; } //报错 function func(name){ let name; }
const命令
const 声明一个只读的常量,一旦声明,常量的值就不能改变(意味着一旦声明,必须立即初始化)
-
对于声明对象,const命令只保证变量名指向的地址不变,不会保证该地址的数据不变
const foo = {}; foo.prop = 123; foo.prop // 123 foo = {} // TypeError: "foo" is read-only
Note:
- var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。(顶层对象=全局变量)
变量的解构赋值(提取json数据!!!)
数组的解构赋值
let [a,b,c] = [1,2,3]
-
允许指定默认值
let [a, b = 1] = [2,3]
对象的解构赋值
let {foo, bar} = {foo: 1, bar: 2}-
变量必须与属性同名
let {foo, baa} = {foo: 1, bar: 2}>foo 1 >bar undefined
-
允许指定默认值
字符串的解构赋值
字符串转换类似数组的对象
const [a,b,c,d,e] = 'hello'
>a
'h'
>b
'e'
>c
'l'
>d
'l'
>e
'o'
函数参数解构赋值
function add([x,y]){
return x + y;
}
add([1,2]);//3
函数
基本用法
-
可为参数指定默认值,es5不支持
-
参数变量是默认声明的,不能用let和const再次声明
-
与解构赋值结合使用
参数默认值的位置
定义了默认值的参数,是没法省略的
function f(x=1, y){
return [x,y];
}
console.log(f()) //[1, undefined]
console.log(f(2)) //[1, undefined]
f(,1) // 报错
console.log(f(undefined,1)) //[1, 1]
函数的length属性
函数的length返回没有指定默认值的参数个数,指定了默认值后,使用length将失真
作用域
-
设置参数默认值时,会形成一个单独的作用域
let i = 1 function f(y = i) { let i = 2; console.log(y); } f(); //1
应用
-
利用参数默认值,可以指定某一个参数不能省略
function throwIfMissing() { throw new Error('Missiong Paramter'); } function foo(name = throwIfMissing()) { return name; } foo();
name属性
函数的name属性,返回该函数的函数名
function foo() {}
foo.name // "foo"
箭头函数
var f = () => 5
//等同于
var f = function () { return 5 }
var sum = (n1,n2) => n1 + n2
//等同于
var sum = function(n1, n2) {
return n1 + n2
}
//返回对象
var f = returnObj => ({name : "Tom", age : 20})
//和变量解构结合使用
var f = ({a,b}) => a + b
- 可用于回调函数
-
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; //全局对象 foo.call({ id: 42 }); //函数定义时所在对象 // id: 42
-
尾调用优化,每次执行时,函数调用帧只有一项,大大节省内存
function a() { return b() }
数组
Array.from() : 将两类对象转为真正的数组
let arrayLike = {
'0' : 'Tom',
'1' : 20,
length : 2 //数组长度
}
let arr = Array.from(arrayLike)
console.log(arr);
Array.of() 将一组值转换为数组
Array.of(1,2,3) //[1,2,3]set和map数据结构
1.Set结构
Set类似于数组,但是成员值都是唯一的,没有重复。
> const s1 = new Set([1,2,3,4])> [...s1]
[ 1, 2, 3, 4 ]
> const s2 = new Set([1,2,3,4,5])
> s2.size
5
四个操作方法:
- add(value): 添加某个值
- delete(value): 删除某个值,返回布尔值
- has(value): 返回布尔值
- clear(): 清楚所有成员
遍历操作:
- keys(): 返回键名的遍历器
- values(): 返回键值的遍历器
- entries(): 返回键值对的遍历器
- forEach(): 返回回调函数遍历每个成员
2.Map结构
Object结构提供了”字符串-值”的对应,Map结构提供了”值-值”的对应,是一种更加完善的hash结构实现。
var map = new Map() //初始化map
属性
- size: 返回map结构的成员总数
方法
- set: 设置key所对应的值,返回整个Map结构,如果key已有值,则会更新键值。
- get: 获取key对应的键值,如果找不到key,返回undefined。
- has: 返回布尔值,表示某个键是否在map中。
- delete: 删除某个键,成功返回true。
- clear: 清楚所有成员,无返回值。
遍历方法
- keys(): 返回键名的遍历器
- values(): 返回键值的遍历器
- entries(): 返回成员的遍历器
- forEach(): 返回回调函数遍历每个成员
与其他数据结构转换
- Map => Array 扩展运算符 […map]
- Array => Map 将数组传入map构造函数
-
Map => Object Map的键都是字符串时
function strMapToObj(strMap) { let obj = Object.create(null); for (let [k,v] of strMap) { obj[k] = v; } return obj; } let myMap = new Map().set('yes', true).set('no', false); strMapToObj(myMap) // { yes: true, no: false }
-
对象转换为Map
function objToStrMap(obj) { let strMap = new Map(); for (let k of Object.keys(obj)) { strMap.set(k, obj[k]); } return strMap; } objToStrMap({yes: true, no: false}) // [ [ 'yes', true ], [ 'no', false ] ]
- Map与Json的转换较为复杂,见 http://es6.ruanyifeng.com/#docs/set-map
Promise 异步编程
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,它是一个对象,从它可以获取异步操作的消息。
特点:
- 对象状态不受外界影响
-
一旦状态改变,就不会再变,任何时候都可以得到这个结果
function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, ‘done’); }); }
timeout(1000).then((value) => { console.log(value); });
Class
ES6中引入了Class(类)这个概念,作为对象的模版,通过class关键字,可以定义类。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ',' + this.y + ')';
}
}
var p = new Point();
p.toString(1,2);
Module
export命令
规定模块的对外接口
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。希望外部获取某个变量,就必须使用exports关键字暴露该变量
const firstName = 'Michael';
const lastNmae = 'Jackson';
const year = 2000;
export {firstName, year};
import命令
输入其他模块提供的功能
import {firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
export default 命令
为模块指定默认输出
export default function (){
console.log('foo')
}
ES6模块加载的实质
js引擎对脚本静态分析的时候,遇到模块加载命令import, 就会生成一个只读引用,等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,es6的import有点像unix系统的”符号连接”,原始值变了,import加载的值也会跟着变。因此,es6模块是动态引用,不会缓存值,模块里面的变量绑定其所在的模块。
编程风格
- let 取代 var
- let 和 const 之间,优先使用const
- 静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号
- 对数组成员变量赋值时,优先解构赋值
-
单行定义对象,最后一个成员不以逗号结尾;多行定义对象,最后一个成员以逗号结尾。
const a = { k1: v1, k2: v2 }; const b = { k1: v1, k2: v2, };
-
对象尽量静态化,一旦定义,不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法
-
使用扩展运算符(…)拷贝数组
const itemsCopt = [...items];
-
立即执行的函数可以写成箭头函数的形式
[1,2,3].map(x => x * x)
- 只有模拟现实世界的实体对象时,使用Object,如果只需要key:value,使用map结构
- 用import取代require, export取代module.exports
- 一个模块输出一个函数,函数名首字母小写;输出对象,首字母大写。