ES6备忘
花了一个礼拜时间学习了ES6,本文记录了一些常用关键语法备忘。这篇内容比较简单,对于Promise及异步操作之类的本文暂且略过,将在后续实践中展开。
let
- 块级作用域(构成块级的大括号不能少)有效,声明后不管全局中有没有,都会形成一个封闭作用域
- 不存在变量提升,使用前需要先声明(注意函数声明,在块级作用域中声明的函数只有在此块级中可以使用)
- 不允许在相同作用域内,重复声明同一个变量
const
- 声明的是常量(声明时必须初始化)
- 块级作用域有效
- 复合类型时指向数据所在地址(注意将对象设置为const时不能改变其属性的值;将数组设置为const时不能将另一个数组赋值给它,可以在当前数组中对数组元素作操作)
- 跨模块常量
1
2
3
4
5
6
7
8
9
10//moduleA.js
exports const AA = 123;
exports const BB = 456;
//main.js
import * as moduleA form './moduleA';
console.log(moduleA.AA);//123
//another way
import {AA} from './moduleA';
console.log(AA);//123ES6中,有6种声明变量的方法;
var、function声明的全局变量是全局对象的属性;
let、const、class声明的全局变量不属于全局对象的属性
Symbol
- 新的(Boolean,String,Number,Object,null,undefined之外的第七种)原始数据类型,表示独一无二的值
- 不是对象,不能添加属性,不能new,可以加参数,可以显示转为字符串,布尔值,但是不能转为数值
1
2
3var s = Symbol('foo');
s //Symbol(foo)
s.toString //"Symbol(foo)" - 每一个Symbol值都是不相等的,可以作为标志符,用于对象的属性名(不能用点运算符),能保证不会出现同名的属性
1
2
3
4let test = {
[Symbol()]:'test'
}
test[Symbol()] //test - 通过Object.getOwnPropertySymbols()获取,返回一个数组
- Symbol.for()为Symbol值登记的名字。使用同一个Symbol值
解构赋值
从数组或对象中提取值(解构),然后按照层级对应位置进行赋值。
1 |
|
等号右边必须是可遍历的结构;
undefined !== null,只有===undefined的变量为undefined,其余情况均为其值;
对象结构的内部机制,先找到同名属性,再复制给对应的变量,对应的变量获得赋值的结果,同名属性(理解为模式,非变量)并没有获得赋值;
可以将现有对象的方法赋值到某个变量;
若等号右边为Number和Boolean,则先转为对象;
字符串的扩展
模板字符串(运行效率较慢)
模板字符串表示多行字符串,空格和tab保留
静态字符串一律使用单引号或反引号,不使用双引号
动态字符串使用反引号。
1 |
|
正则的扩展
- RegExp构造函数参数改变
1
var reg = new RegExp(/abc/ig,'i');//等同于new RegExp('abc','i')
- 字符串对象的正则方法(match、replace、search、split)全部调用RegExp的实力方法
- u修饰符代表Unicode模式
- /\u{BBB30}/u,{}表示Unicode字符
- y修饰符表示全局模式(区别于g修饰符,y只能从剩余的第一个位置开始)
数值的扩展
- 减少全局性方法,使语言逐步模块化
- Number.isFinite(),是否非正无穷
- Number.isNaN()
- Number.parseInt(),Number.parseFloat()
- Number.isInteger(),是否为整数(整数浮点数存储方法相同)
数组的扩展
- Array.from(arr,item => item*item)将类数组对象(有length属性)和可遍历的对象转为真正的数组,第二个参数用法类似于map
- […arguments]将一些数据结构转为数组
- Array.of(arg0,arg1)将一组值转换为数组
- 空位转为undefined
函数的扩展
- 参数声明变量默认值之后,不能用let,const再次声明
- 解构赋值时,传参数据类型相对应
- 参数先对应默认值(运行时执行,默认值设置为undefined表明可以省略),然后解构赋值生效
- rest参数将多余参数放入数组中,之后不能有其他参数。
- 有iterator接口的类数组对象可以使用扩展运算符,没有此接口使用Array.from转为真正的数组
- 箭头函数,this指向定义时的对象(外层代码块this),不可以作为构造函数(本身没有this),不可以使用arguments(用rest),不能作为Generator函数。
1
2var f = param => returnParam
var sum = (num1,num2) => {return num1+num2;} - 使用尾递归(严格模式),防止栈溢出
对象的扩展
- 属性、方法简写(Generator函数加*)
- name作为对象名、方法名(get、set、bound、anonymous、Symbol的描述)
- Object.is(),同值相等(针对+1-1,NaN)
- Object.assign(target,source1,source2)浅拷贝,只拷贝源对象的自身属性(不拷贝继承属性和不可枚举属性),遇到同名属性替换
1
2
3
4
5
6
7
8
9//浅克隆
function clone(origin) {
return Object.assign({},origin);
}
//深克隆
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto),origin);
} - Object.setPrototypeOf(target,origin)设置原型对象
Iterator
- 为不同的数据结构提供统一的访问机制,有Iterator接口(数组、类数组对象String etc..、Set、Map原生具有)就能完成遍历操作。
1
2
3
4
5
6
7
8class NewIterator {
constructor(){}
[Symbol.iterator]() {
return this;
}
}
//类数组对象调用数组的Iterator方法
ArrLike.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; - 具有Iterator接口的数据结构,通过[…arg]或者Array.from(arrayLike)转为数组
Generator
- Generator函数封装了多个内部的状态
- 函数返回一个迭代器对象,可以依次遍历Generator函数内部的每一个状态。也是一个iterator对象生成函数
- 只有调用next方法才会执行
1
2
3
4
5function* GenDemo() {
yield "firstState";
yield "secondState";
yield* "divideStr"; //相当于for(var value of "divideStr")
} - 遇到yield暂停执行后面的操作,返回紧跟语句后表达式的值
- next()继续执行,return()返回给定的值并终结函数执行,若有finally,return推迟到finally代码块执行完再执行
class
- 等同于构造函数,类内部定义的方法不可枚举
1
2
3
4
5
6
7
8
9
10
11
12class Parent {
constructor(x,y) {
this.x = x;
this.y = y;
}
toString() {}
toValue() {}
[methodName](){}
state = {//实例属性
count:0
}
} - 可以立刻执行
1
2
3
4
5
6
7
8let a = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('立刻执行参数');1
a.sayName();//立刻执行参数
- 不存在变量提升
- 类和模块的内部,默认就是严格模式
- 类的继承(先创造父类的实例对象this,然后再通过调用super方法,用子类的构造函数修改this)
1
2
3
4
5
6
7
8
9
10
11
12class Child extends Parent {
constructor(x,y,color) {
super(x,y);//父类的构造函数,用来新建父类的this对象,子类继承父类的this对象
this.color = color;
}
toString() {
return this.color+''+super.toString();//通过super可以引用父类实例的属性和方法,也可以引用父类的静态方法
}
}
Child._proto === parent;//true
Child.prototype._proto_ === Parent.prototype;//true
Object.getPrototypeOf(Child) === Parent;//true - class内部只有静态方法,没有静态属性(babel已经支持,可用)
- new.target查看构造函数(子类继承父类时返回子类)
在继承这块ES6与ES5区别
ES6通过引入class,让javascript引擎去实现原来需要我们自己编写的代码
ES5中需要通过中间对象继承,ES6中直接通过extents实现
ES5通过在原型链上添加方法,代码比较分散。ES6直接将方法写在类中
ES5原生构造函数无法继承(子类无法获得构造函数的内部属性),ES6允许继承构造函数定义子类-
ES5先创造子类的实例对象this,再将父类的方法添加到this上面,ES6先创建父类的实例对象this(必须先调用super方法),然后再用子类的构造函数修改this
Module
- 解决模块化问题,import加载,{}中的变量名必须与被导入模块对外接口的名称相同,import命令具有提升效果。
- exports输出(必须是对外的接口,可以通过该接口取到模块内部实时的值),as重命名输出,可以用不同的名字输出多次。
1
2
3
4
5
6
7
8
9import {stat,exists,readFile} from 'fs';//编译时加载
import {originName as newName} form './test'
function v1(){}
function v2(){}
export {
v1 as mod1,
v2 as mod2,
v2 as mod22
} - 通过指定默认输出,黑盒模块名(一个模块只能有一个默认输出)
1
2
3
4
5//A.js
export default function() {}
//main.js
import aaa from './A.js'
aaa(); - 模块输出实质是输出值的引用(commonjs输出值的拷贝),运用时访问模块取值,不会缓存。export接口输出对象实例时,任意import都是针对同一个对象实例操作。
- es6 module transpiler(转成CommonJS或者AMD)
1
2
3npm install -g es6-module-transpiler
compile-modules convert file1.js file2.js
compile-modules convert -o newName.js originName.js
ESLint与Airbnb语法规则
1 |
|
1 |
|
1 |
|
附录一
学习资料
阮老师的ECMAScript入门
airbnb编码规范
ECMAScript6 开发体系实践
廖雪峰的官方网站-原型继承、class继承
babel
附录二
现有选型
1 |
|
附录三
环境配置
npm安装
1
2npm install --save-dev babel-cli
npm install --save-dev babel-polyfill创建一个.babelrc
1
2
3
4
5{
presets:[
"es2015",
]
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!