[Javascript笔记] ES6的变化与新特性(上篇)
Part1. 变量声明与作用域的变化
ES6有6种姿势声明变量: var let const function class import
其中let关键字,用来替代var声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,即{}内有效.let声明的变量不存在变量提升
var与let的对比
1 | var a = []; |
变量声明的暂时性死区
let变量绑定的代码块不受外部影响,在代码块开始处到声明该变量声明处存在暂时性死区,这将导致该部分使用暂未声明的变量报错,即使全局存在同名变量也报错.const同理.
栗子
1 | if (true) { |
const关键字
const用于声明常量,其值或指向的对象引用不能改变;
const作用域规则同let,不存在变量提升,存在暂时性死区;
const声明的同时必须赋值,’const a;a=1;console.log(a)’这在非严格模式下输出undefined,严格模式报错;
const声明的对象引用不可变,但对象属性可变;
跨模块常量需要用export声明 export const xx = xx;
函数作用域
ES5 : 存在函数提升,在代码块内的函数会提升到整个函数作用域内
ES5 严格模式 : 函数只能在函数内或顶级作用域声明, 不能再if{} for{}等块内声明
ES6 : 函数不存在提升, if{} for{}等块内声明的函数只在块内有效
Part2. 解构
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring).
- 允许不完全解构
- 解构可运用于var let const import
- 对于Set结构,也可以使用数组的解构赋值。eg: let [x, y, z] = new Set(["a", "b", "c"])
- Generator函数也能解构,赋值过程依次调用函数获取值
- 解构允许附带默认值,生效条件是匹配到严格undefined eg: let [a=1,b=3] = [2] //a=2,b=3
- 解构比较过程是严格相等运算 eg: let [a=undefined] = [null] //a=null 因为 undefined!==null
- 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,即属性名称只是作为匹配模式
- 已经声明的对象解构赋值最好加上()以避免解释器当成代码块 eg : var x; {x} = {x: 1}; //如果解构语句在行首则报错
- 解构声明等同于分别声明, let和const关键字声明的同区块不能出现重复
- 对象解构时, 若源为基本类型,会转换为对象类型; 数组解构时, 源必须是可遍历的结构或字符串
- 函数参数也能解构, 形参被解构赋值为实参, eg : function foo([x,y]) {};foo([1,2])
- 解构模式内部不要有括号()
示例
1 | var { bar, foo } = { foo: "aaa", bar: "bbb" }; //这是简写形式. |
用途
- 交换变量 [a,b] = [b,a]
- 提取数据, 从返回值提取或从Json提取等等
- 函数默认参数
- 加载模块指定值 eg: import {A,B} from './xx';
Part3. 内置对象扩展与字符串模板
字符串和正则的扩展
- ES6 unicode: Unicode编码放在大括号内,对于>0xFFFF的字符不会错误解释 \u{xxxxx}
- codePointAt() JS字符以UTF-16的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符,字符长度为2,此方法避免该问题, 返回, 返回字符码点, 扩展charCodeAt方法
- fromCodePoint([...code]) 返回Unicode码的对应字符,扩展fromCharCode方法
- at() 返回指定位置字符, 扩展charAt方法
- normalize() 统一同一个字符的不同Unicode
- includes(), startsWith(), endsWith() 终于有这三个方法了,第一个参数是匹配字符,第二个参数是搜索开始位置
- repeat() 重复字符串,参数是自然数
- 模板字符串 终于出来了,here doc写法
1 | //基本用法, <span style="color: #ff0000;">反引号</span>包含 |
数组扩展
Array.from将任何类数组或实现Iterator的类型转换为真·数组
1 | Array.from(arguments); |
Array.of将从参数构造数组,行为等同于new Array()参数>2时,不存在重载,如Array.of(1,2),返回[1,2]
Array.copyWithin 没卵用..
Array.find()和findIndex(), 接受一个函数,返回执行至第一个返回true时的value或者index,接受的函数参数:value, index, arr 弥补indexOf方法, indexOf方法无法识别数组的NaN成员,但是findIndex方法可以借助Object.is方法做到,
Array.includes, 返回bool, 相当于可以识别NaN的indexOf === -1
Array.fill(), 填充值,不多说
entries(),keys()和values() 返回三种遍历器
函数扩展
ES6允许函数拥有默认值, 并且可以和解构赋值同时使用
1 | function fetch(url, { method = 'GET' } = {}){ |
函数拥有length属性,含义是预期传入参数个数,不包括默认参数和rest参数, name属性也被标准化
扩展运算符(…)
在形参列表作用是将剩余变量加入…variable数组中,避免arguments对象的使用(注:只能在参数列表最后出现);
在实参列表作用是将数组转换为参数序列(相当于apply的第二个参数用法);
另外,扩展运算符也可以合并数组;配合解构生成数组;转换成为数组(相当于Array.from)
1 | function foo(a,...b){ |
Lambda表达式
ES6提供了对lambda表达式支持, 又名箭头函数, 格式为 “(/* 参数 /) => {/ 函数体 */}”, 以下是其注意点,与匿名函数最大的区别是固化this:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
(2)不可以当作构造函数,也就是说,不可以对lambda表达式使用new命令,否则会抛出一个错误
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替
(4)不可以使用yield命令,因此箭头函数不能用作Generator函数
关于尾调用优化和尾递归柯里化等函数式编程概念, 以后详述
对象扩展
对象有简洁写法, 不写属性值时, 属性值为属性名称变量的值
对象声明允许属性名表达式, 代替 obj[expr]的写法
1 | let a=1;b=2; |
Object.is方法, 接受两个参数, 判断两个对象是否相同,这是一种Same-value equality, 相当于可以判断NaN===NaN和+0!==-0的严格等于运算符
Object.assign方法, 与_.extent $.extend作用相同,合并对象(注:采用浅拷贝)
ES7提出扩展运算符’…’引入对象, 这已经在Babel实现
Object.keys , Object.values, Object.entries等等其他语法糖不详述.
ES6中可用的遍历对象的6种姿势
- for...in 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
- Object.keys(obj) 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)
- Object.getOwnPropertyNames(obj) 返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)
- Object.getOwnPropertySymbols(obj) 返回一个数组,包含对象自身的所有Symbol属性
- Reflect.ownKeys(obj) 返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举
- Reflect.enumerate(obj) 返回一个Iterator对象,遍历对象自身的和继承的所有可枚举属性(不含Symbol属性),与for...in循环相同。