json

1年前
  • 3445

    浏览
  • 2

    评论
  • 1

    收藏

ECMAScript 6 学习笔记

本文作者:imweb json 原文出处:imweb社区 未经同意,禁止转载

作用域不同

  • ES6中,let和const实际上为JavaScript新增了块级作用域,函数本身的作用域,在其所在的块级作用域之内。
  • let和const的用法

    相同点:(1)用来声明变量 (2) 声明的变量只在它所在的代码块有效 (3) 不像var那样,会发生“变量提升”现象,只要块级作用域内存在let或const命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。 (4)不允许在相同作用域内,重复声明同一个变量

不同点:const也用来声明变量,但是声明的是常量。一旦声明,常量的值就不能改变。let声明的变量可以改变。

  • 全局对象。 ES6规定,var命令和function命令声明的全局变量,属于全局对象的属性;let命令、const命令、class命令声明的全局变量,不属于全局对象的属性,无法通过window/global获取。

变量的解构赋值

  • 定义:ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。

    eg: var [a, b, c] = [1, 2, 3]; 相当于 var a = 1;var b = 2;var c = 3;

  • 解构只能用于数组或对象,其他原始类型的值都可以转为相应的对象。
  • 解构赋值允许指定默认值。

    eg :[x, y='b'] = ['a'] // x='a', y='b'

  • 对象解构可以与函数参数的默认值一起使用。

    eg :function move({x=0, y=0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0]

  • 用途:(1)交换变量的值 (2) 从函数返回多个值 (3) 函数参数的定义 (4) 提取JSON数据 (5) 函数参数的默认值 (6) 遍历Map结构 (7) 输入模块的指定方法

字符串的扩展

  • 新增加codePointAt()、String.fromCodePoint()、at()处理需要4个字节储存的字符(Unicode码点大于0xFFFF的字符)
  • ES6对正则表达式添加了u修饰符,用来正确处理大于\uFFFF的Unicode字符;
    • (1) 点(.)字符在正则表达式中,对于码点大于0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符。
    • (2) Unicode字符表示法:ES6新增了使用大括号表示Unicode字符,这种表示法在正则表达式中必须加上u修饰符,才能识别。
    • (3) 使用u修饰符后,所有量词都会正确识别大于码点大于0xFFFF的Unicode字符。
    • (4) u修饰符也影响到预定义模式,能否正确识别码点大于0xFFFF的Unicode字符。
    • (5) i修饰符/[a-z]/i.test('\u212A') // false /[a-z]/iu.test('\u212A') // true 上面代码中,不加u修饰符,就无法识别非规范的K字符。
  • ES6又提供了三种新方法,用来确定一个字符串是否包含在另一个字符串中。

    includes():返回布尔值,表示是否找到了参数字符串。 startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。 endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。

  • 正则表达式的y修饰符:它的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始,不同之处在于,g修饰符只确保剩余位置中存在匹配,而y修饰符确保匹配必须从剩余的第一个位置开始
  • 模板字符串:用反引号( ` )标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。如果在模板字符串中嵌入变量,需要将变量名写在${}之中。

    注意:(1)如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。 (2) 大括号内部可以进行运算,以及引用对象属性。 (3)模板字符串之中还能调用函数 (4) 如果模板字符串中的变量没有声明,将报错。

  • String.raw方法,往往用来充当模板字符串的处理函数,返回字符串被转义前的原始格式。

    eg :String.raw({ raw: 'test' }, 0, 1, 2);// 't0e1s2t'
    等同于String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);

    数值的扩展

  • ES6提供了二进制和八进制数值的新的写法,分别用前缀0b和0o表示

    eg: 0b111110111 === 503 // true
    0o767 === 503 // true

  • ES6在Number对象上,新提供了Number.isFinite()和Number.isNaN()两个方法,用来检查Infinite和NaN这两个特殊值。 它们与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,非数值一律返回false。
  • ES6将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
  • Number.isInteger()用来判断一个值是否为整数;
  • (1)Math.trunc方法用于去除一个数的小数部分,返回整数部分
    (2)Math.sign方法用来判断一个数到底是正数、负数、还是零。如果参数为正数,返回+1;参数为负数,返回-1;参数为0,返回0;参数为NaN,返回NaN。
  • ES6在Math对象上还提供了许多新的数学方法。包括Math.acosh(x)、Math.asinh(x)等

数组的扩展

  • (1) Array.from()用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象,其中包括ES6新增的Set和Map结构。
    (2) Array.of()方法用于将一组值,转换为数组。
  • (1) 数组实例的find()用于找出第一个符合条件的数组元素。它的参数是一个回调函数,所有数组元素依次遍历该回调函数,直到找出第一个返回值为true的元素,然后返回该元素,否则返回undefined。
    (2)数组实例的findIndex()的用法与find()非常类似,返回第一个符合条件的数组元素的位置,如果所有元素都不符合条件,则返回-1。
  • fill()使用给定值,填充一个数组
  • ES6提供三个新的方法——entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
  • ES7新增 includes() 方法返回一个布尔值,表示某个数组是否包含给定的值
  • ES6提供简洁写法,允许直接通过现有数组生成新数组,这被称为数组推导
  • Array.observe(),Array.unobserve() 这两个方法用于监听(取消监听)数组的变化,指定回调函数。数组可监听的变化一共有四种:add、update、delete、splice(数组的length属性发生变化)。

对象的扩展

  • 属性的简洁表示法
  • 属性名表达式 obj['a'+'bc'] = 123;
  • Object.is()用来比较两个值是否严格相等。它与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
  • Object.assign方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。
  • ES6引入了一种新的原始数据类型Symbol,表示独一无二的ID。它通过Symbol函数生成。

    a) Symbol.for方法在全局环境中搜索指定key的Symbol值,如果存在就返回这个Symbol值,否则就新建一个指定key的Symbol值并返回。
    b) Symbol.keyFor方法返回一个已登记的Symbol类型值的key。

  • ES6新增加Proxy用于修改某些操作的默认行为
  • (1)Object.observe方法用来监听对象(以及数组)的变化。一旦监听对象发生变化,就会触发回调函数。 Object.observe方法目前共支持监听六种变化。

add:添加属性
update:属性值的变化
delete:删除属性
setPrototype:设置原型
reconfigure:属性的attributes对象发生变化
preventExtensions:对象被禁止扩展(当一个对象变得不可扩展时,也就不必再监听了)

(2) Object.unobserve方法用来取消监听。

函数的扩展

  • ES6允许为函数的参数设置默认值 。 注意定义了默认值的参数,必须是函数的尾部参数,其后不能再有其他无默认值的参数。指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。
  • ES6引入rest参数(...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。 注意,rest参数之后不能再有其他参数,否则会报错。
  • 扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。该运算符主要用于函数调用。
  • ES6允许使用“箭头”(=>)定义函数。

    eg:var f = v => v;

箭头函数有几个使用注意点:
(1) 函数体内的this对象,绑定定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。 (3)不可以使用arguments对象,该对象在函数体内不存在。

Set和Map数据结构

  • ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

    a) Set结构有以下属性:(1)Set.prototype.constructor:构造函数,默认就是Set函数。 (2)Set.prototype.size:返回Set的成员总数。
    b) Set数据结构有以下方法:(1) add(value):添加某个值,返回Set结构本身。 (2) delete(value):删除某个值,返回一个布尔值,表示删除是否成功。 (3) has(value):返回一个布尔值,表示该值是否为Set的成员。 (4) clear():清除所有成员,没有返回值
    c) Array.from方法可以将Set结构转为数组。
    d) 支持数组遍历方式。

  • WeakSet结构与Set类似,也是不重复的值的集合。但是,它与Set有两个区别。 首先,WeakSet的成员只能是对象,而不能是其他类型的值。其次,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。
  • ES6提供了map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应。

a) Map数据结构有以下属性和方法:

(1)size:返回成员总数。
(2)set(key, value):设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。
(3)get(key):读取key对应的键值,如果找不到key,返回undefined。
(4)has(key):返回一个布尔值,表示某个键是否在Map数据结构中。
(5)delete(key):删除某个键,返回true。如果删除失败,返回false。
(6)clear():清除所有成员,没有返回值。

b) Map原生提供三个遍历器:keys(),values(),entries()

  • WeakMap结构与Map结构基本类似,唯一的区别是它只接受对象作为键名(null除外),不接受原始类型的值作为键名,而且键名所指向的对象,不计入垃圾回收机制。

Iterator(遍历器)

  • 在ES6中具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。
  • ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性。也就是说,调用Symbol.iterator方法,就会得到当前数据结构的默认遍历器。Symbol.iterator是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为Symbol的特殊值,所以要放在方括号内
  • 调用默认iterator接口的场合:
    (1) 解构赋值:对数组和Set结构进行解构赋值时,会默认调用iterator接口。
    (2) 扩展运算符
  • ES6中,一个数据结构只要部署了Symbol.iterator方法,就被视为具有iterator接口,就可以用for...of循环遍历它的成员。

Generator 函数

  • ES6引入Generator函数,作用就是可以完全控制函数的内部状态的变化,依次遍历这些状态。Generator是一个普通函数,但是有两个特征。一是,function命令与函数名之间有一个星号;二是,函数体内部使用yield语句,定义遍历器的每个成员,即不同的内部状态
  • next方法的参数
    next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。
  • for...of循环可以自动遍历Generator函数,且此时不再需要调用next方法。
  • Generator函数还有一个特点,它可以在函数体外抛出错误,然后在函数体内捕获。
  • yield*语句:如果yield命令后面跟的是一个遍历器,需要在yield命令后面加上星号,表明它返回的是一个遍历器。

Promise对象

  • Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象还提供了一整套完整的接口,使得可以更加容易地控制异步操作。
  • Promise.prototype.then方法返回的是一个新的Promise对象,因此可以采用链式写法。
  • Promise.prototype.catch方法是Promise.prototype.then(null, rejection)的别名,用于指定发生错误时的回调函数。
  • Promise.all()、Promise.race()方法用于将多个Promise实例,包装成一个新的Promise实例。
  • Promise.resolve()、Promise.reject(),将现有对象转为Promise对象
  • 使用Generator函数管理流程,遇到异步操作的时候,通常返回一个Promise对象。

Class

  • a) ES6引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
    b) constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,该方法会被默认添加
    c) 生成实例对象的写法,与ES5完全一样,也是使用new命令。如果忘记加上new,像函数那样调用Class,将会报错。

    d) 可以通过proto属性为Class添加方法。
    e) ES6的Class只是ES5的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性。
    f) 与函数一样,Class也可以使用表达式的形式定义。
    g) Class不存在变量提升
    h) 类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。

  • Class的继承:Class之间可以通过extends关键字,实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。
    注意子类必须在constructor方法中调用super方法,否则新建实例时会报错。
  • class的取值函数(getter)和存值函数(setter):在Class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数。


本文是学习ES6的一点心得,想要具体学习ES6,请参考阮老师的书,电子版地址点这里

2 条评论