ES6标准入门(阮一峰)读书笔记

2019.5.27开始   2019.6.2结束   于2019.6.3 整理

目录

1.let const:

2.箭头函数

3.函数的扩展

4.解构赋值

5.数组

6.字符串

7.正则扩展

8.对象扩展

9.面向对象

10.JOSN

11.Symbol

12.Set、Map

1.Set

weakSet

2.Map

WeakMap

13.Proxy和Reflect

14.Promise

15.Iternator迭代器和for..of循环

16.Generator函数

17.async



1.let const:

JS中-----var:

1.可以重复声明

2.无法限制修改

3.没有块级作用域

 

ES6:-----------let 变量 / const 常量(不可修改read only )

1.不可重复声明

2.块级作用域

3.声明时必须赋值

 

2.箭头函数

传统:function(){ }

es6: ()=>{ }

去function 变 =>

作用:简化回调函数

 

1.如果只有一个参数,()可以省

2.如果只有一个return , { }和return 可以一起省

3.如果箭头函数返回一个对象,必须在对象外面加上括号

 

注意:

1.函数体内的this对象就是定义时所在的对象(固定),而不是使用时所在的对象

this指向的固定化是因为箭头函数并没有自己的this,导致内部的this就是外层代码块的this。正因为它没有this对象,也就不可以当做构造函数。也不能使用bind(),apply(),call()方法。

2.不可以当做构造函数(不可以使用new 命令)

3.不可以使用argements对象(可用test参数代替)

4.不可以使用yield命令,因此箭头函数不可用作Generator函数

 

3.函数的扩展

rest参数

rest参数(形式为“...变量名”),用于获取函数的多余参数

function show(a,b,...args){}

rest参数必须为最后一个,否则会报错

函数的length属性不包括rest参数

扩展运算符

扩展运算符是三个点(...)。

好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log(...[1,2,3])//1,2,3

 

扩展运算符的应用:

1.合并数组

[...arr1,...arr2,...arr3]

2.与解析赋值结合生成数组

3.函数可返回多个值

4.将字符串转为数组

5.可将类似数组的对象转为真正的数组

6.Map、Set结构,Generator函数

 

默认参数

直接写在函数定义的后面

参数变量默认声明,因此不能用let 或者const再次声明

 

默认参数的位置:

默认值的参数应该是函数的尾参数。如果非尾部的参数设置默认值,该参数无法省略。

function f(x=1,y){ return [x,y]; } f() //[1,undefined] f(2)//[2,undefined] f(, 1)//报错 f(underfined,1) //[1,1]

上述代码中,默认值的参数并不是函数的尾参数,因此该参数不可省略,可显式输入undefined。如果传入undefined,将触发该参数等于默认值,null则没有该效果。

函数的length属性:

指定默认值后,函数的length属性为没有指定默认值的参数个数。

length属性的含义是该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。

作用域:

先是当前函数的作用域,再是全局作用域

name的属性:

返回该函数的函数名

如果将一个匿名函数的对象赋值给一个变量,会返回实际的函数名(ES5中返回空字符串)

Function构造函数返回的函数实例,name的属性值为"annoymous"

bind返回的函数,name属性值会加上“bound”前缀

function foo(){}; foo.bind({}).name //"bound foo" (function(){}).bind({}).name //"bound"

 

4.解构赋值

解构:按照一定模式,对变量进行赋值

1.左右两边解构一致(按照位置的对应关系对变量赋值)

2.右边必须是个东西(数组、对象、Map、Set)

3.声明和赋值不能分开(必须在一句话里完成)

 

解构赋值适用于var let const命令

不完全解构:等号左边的模式只匹配右边的一部分

只要某种数据结构具有Iterator接口,都可以结构赋值

解构赋值允许指定默认值

 

对象的解构赋值与数组的区别

数组的元素按次序排列,变量的取值由位置决定;

对象的属性没有次序,变量必须与属性同名,才能取到正确值。

对象的解构赋值的内部机制是:先找到同名属性,再赋值给对应的变量。真正被赋值的是后者。

 

圆括号问题

以下三种解构赋值不得使用圆括号:

1.变量声明语句(var / let / const...)

2.函数参数

3.不能将整个模式或嵌套模式的一层放在圆括号中

 

可以使用圆括号的情况:赋值语句的非模式部分

 

解构赋值的用途

1.交换变量的值

2.从函数返回多个值

3.函数参数的定义

4.提取JSON数据

5.遍历Map结构

6.输入模块的指定方法

 

5.数组

map 映射(一个对一个)

reduce 汇总(一堆对一个)

filter 过滤器

forEach 循环(迭代)

 

 

6.字符串

1.新方法:

startsWith()/endsWith() 以...开头或者结尾

2.字符串模板:(字符串的连接)

反单引号``

直接把东西放入字符串 ${东西}

可以折行

 

7.正则扩展

y修饰符:

g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。

不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。

var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;

console.log(r1.exec(s));//["aaa"]
console.log(r2.exec(s));//["aaa"]

console.log(r1.exec(s));//["aa"]
console.log(r2.exec(s));//null

//判断是否是y修饰符
console.log(r1.sticky,r2.sticky);//false true

u修饰符:

会正确处理四个字节的UTF-16编码。

ES5则不支持四个字节的UTF-16编码,会将其识别为两个字符。

console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A'));//true

console.log('u-2',/^\uD83D/u.test('\uD83D\uDC2A'));//false

 

点(.)字符在正则表达式中,含义是除了换行符以外的任意单个字符。

对于码点大于0xFFFF的 Unicode 字符,点字符不能识别,必须加上u修饰符。

var r = '?'; console.log('u',/^.$/.test(r));//false

console.log('u-0',/^.$/u.test(r));//true

 

8.对象扩展

函数新增特性:

简洁表示法

属性和方法都可以简写

属性表示法

扩展运算符

Object新增方法

1.Object.is();

//ES5:

console.log(+0===-0);//true

console.log(NaN===NaN)//false

//ES6:

console.log(Object.is(+0,-0));//false

console.log(Object.is(NaN,NaN));//true

 

2.Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。第一个参数是目标对象,后面的参数都是源对象。

Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性。不拷贝继承属性,也不拷贝不可枚举的属性(enumerable: false)。

只有字符串的包装对象,才会会产生可枚举属性。

const v1='abc'; const v2=true; const v3=10; const obj=Object.assign({},v1,v2,v3); //只有字符串合入目标对象(以字符数组的形式),数值和布尔值都会被忽略 console.log(obj);//{0: "a", 1: "b", 2: "c"}

注意:

1.浅拷贝

2.同名属性会进行覆盖

3.可用来处理数组,会把数组当做对象

Object.assign([1, 2, 3], [4, 5])// [4, 5, 3]

 

3.Object.keys()---键名

Object.values()---键值

Object.entries()---键值对

Object.fromEntries()--将键值对数组转化为对象

 

9.面向对象

1.class关键字、构造器和类分开

2.class里面直接加方法

function Point(x,y){
    this.x=x;
    this.y=y;
}
Point.prototype.toString=function(){
    return'('+this.x+','+this.y+')';
}
||
//定义类
class Point(){
    //构造方法:
    constructor(x,y){
        this.x=x;
        this.y=y;
    }
    toString(){
         return'('+this.x+','+this.y+')';
    }
}

 

继承:通过extends关键字实现

class ColorPoint extends Point{
    constructor(x,y,color){
        super(x,y);//调用父类constructor(x,y)
        this.color=color;
    }
    toString(){
        return this.color+''+super.toString();
    }
}

10.JOSN

json的标准写法:

1.只能用双引号

2.所有的名字(key)都得用双引号包起来

 

简写:

1.key value一样时可以只写一个;

let a=21;
let b=5;

let json2={a:a,b:b};
console.log(json2);//{a: 21, b: 5}
//可简写如下:
let json3={a,b,c:74};
console.log(json3);//{a: 21, b: 5, c: 74}
  

2.函数里面的方法" :function "可省略

let json4={
    a:12,
    show:function(){
        console.log(this.a);
    }
};
json4.show();//12
//可简写如下:
let json5={
    a:12,
    show(){
    console.log(this.a);
    }
};
json5.show();//12

11.Symbol

JS数据类型:

字符串(String)、数值(Number)、布尔值(Boolean)、undefined、null、对象(Object)。

Symbol为JS中第七种数据类型,用来保证每个属性名都是独一无二的

 

对象的属性名的两种类型:原有字符串、Symbol类型

 

1.Symbol.protoytpe.descriptioon

用来返回Symbol的描述

const sym=Symbol('foo'); console.log(sym.description);//foo

 

2.Object.getOwnPropertySymbols()

用来遍历属性名,获取指定对象的所有Symbol的属性名

 

可拿到Symbol和非Symbol的属性

const obj = {};
let foo = Symbol("foo");
Object.defineProperty(obj, foo, {
    value: "foobar"
});
for (let i in obj) {
    console.log(i); // 无输出
}
console.log(Object.getOwnPropertyNames(obj));// []
console.log(Object.getOwnPropertySymbols(obj));// [Symbol(foo)]

3.Symbol.for()、Symbol.keyFor()

共同点:都会生成新的Symbol

区别:

Symbol.for()会先检查给定的key是否存在,若不存在才会新建。

Symbol()在每次调用都会产生一个新的Symbol

 

12.Set、Map

1.Set

类似数组,成员值唯一

返回长度:size

Set元素不可重复(可用来去重)

转换元素的时候不会做数据类型的转换

Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。

操作方法

add(value):添加某个值,返回 Set 结构本身。

delete(value):删除某个值,返回一个布尔值,表示删除是否成功。

has(value):返回一个布尔值,表示该值是否为Set的成员。

clear():清除所有成员,没有返回值。

遍历方法

keys():返回键名的遍历器

values():返回键值的遍历器

entries():返回键值对的遍历器

forEach():使用回调函数遍历每个成员

weakSet

与Set区别:

1.WeakSet 的成员只能是对象,而不能是其他类型的值。

2.WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。

2.Map

类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

Map 结构的实例有以下属性和操作方法。

(1)size 属性:返回 Map 结构的成员总数。

(2)set(key, value):set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。

(3)get(key):get方法读取key对应的键值,如果找不到key,返回undefined。

(4)has(key):has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。

(5)delete(key):delete方法删除某个键,返回true。如果删除失败,返回false。

(6)clear():clear方法清除所有成员,没有返回值。

WeakMap

WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。WeakMap结构有助于防止内存泄漏。

注意,WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。

 

13.Proxy和Reflect

Proxy

--修改某些操作的默认行为

注意:要使得Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标对象进行操作。

var proxy = new Proxy(target, handler);

target参数:要拦截的目标对象

handler参数:也是一个对象,用来定制拦截行为(拦截处理函数)。

 

Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

 

14.Promise

同步与异步

"异步",简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。

连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能一直等着。

 

1.含义

Promise 是异步编程的一种解决方案,是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。

有三种状态:Pending(进行中)、Resolved(已完成)、Rejected(已失败)

状态改变:

进行中--->已完成

进行中--->已失败

特点:

(1)对象的状态不受外界影响;

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果;

(3)Promise对象提供统一的接口,使得控制异步操作更加容易。

缺点:

(1)无法取消Promise,一旦新建它就会立即执行,无法中途取消。

(2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

(3)当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

 

2.基本用法

resolve函数:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

 

reject函数:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

 

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

then方法可以接受两个回调函数作为参数。(then方法将会在当前脚本所有同步任务执行完才执行)

第一个回调函数是Promise对象的状态变为resolved时调用;(必选)

第二个回调函数是Promise对象的状态变为rejected时调用。(可选)

 

function timeout(ms){ return new Promise(function (resolve,reject){ setTimeout(resolve,ms,'done'); }) } timeout(100).then(function (value){ console.log(value);//done });

 

Promise.prototype.then()

作用:

为Promise添加状态改变时的回调函数

参数:

参数一:Resolved状态的回调函数

参数二:(可选)Reject状态的回调函数

 

Promise.prototype.catch()

指定发生错误的回调函数(处理前一个函数运行时发生的错误)

 

Promise.all()、Promise.race()

多个Promise实例包装成一个新的Promise实例

var p=Promise.all([p1,p2,p3]); var p=Promise.race([p1,p2,p3])

注意:

在Promise.all方法中,只有p1,p2,p3状态都改变,p的状态才改变;

而Promse.race中,只要有一个状态改变,p就改变。

 

15.Iternator迭代器和for..of循环

概念

遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。

 

原生具备 原生具备 Iterator 接口的数据结构如下:

Array Map Set String TypedArray 函数的 arguments 对象 NodeList 对象

作用

一是为各种数据结构,提供一个统一的、简便的访问接口;

二是使得数据结构的成员能够按某种次序排列;

三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。

 

16.Generator函数

基本概念:

1.状态机,封装了多个内部状态

2.会返回一个遍历器对象

特征:

1.function 函数与函数名之间有一个 *

2.函数体内部使用yield定义不同的内部状态

注意:

1.任意一个对象的Symbol.iterator方法等于该对象的遍历器对象生成函数,调用该函数会返回该对象的一个遍历器对象

function *gen()
{
}
var g = gen();
console.log(g[Symbol.iterator]() === g);//true

2.yield后面的表达式只有调用next()或者内部指针指向该语句时才会执行。

//1.调用next()
function *f()
{
    yield 1;
    yield 2;
    yield 3;
}
var g=f();
console.log(g.next());//{value: 1, done: false}
console.log(g.next());//{value: 2, done: false}
console.log(g.next());//{value: 3, done: false}
console.log(g.next());//{value: undefined, done: true}

 

//for..od遍历
let obj={};
obj[Symbol.iterator]=function* (){
    yield 1;
    yield 2;
    yield 3;
}
for(let value of obj){
    console.log(value);
     //1
    //2 
    //3
}
//简写:for..of会自动遍历Generator对象
function*foo()
{
    yield 1;
    yield 2;
    yield 3;
}
for(let v of foo()){
    console.log(v);
     //1
    //2 
    //3
}

案例1:

模拟抽奖

let draw = function (count) {
    alert(`剩余${count}次`);
}
let residue = function * (count)
{
    while (count > 0) {
        count--;
        yield draw(count);
    }
}
let star = residue(5);
let btn = document.createElement('button');
btn.id = 'start';
//    btn.textContent='抽奖';
btn.innerText = '抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click', function () {
    star.next();
}, false);

案例2:

长轮询

//    模拟AJAX过程
let ajax=function* (){
    yield new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve({code:0})
        },200);
    })
}
let pull=function(){
    let generator=ajax();
    let step=generator.next();
    step.value.then(function(d){
        if(d.code!=0){
            setTimeout(function(){
                console.log('wait');
                pull();
            },1000);
        }else{
            console.info(d);
        }
    })
}
pull();

 

17.async

它是 Generator 函数的语法糖。

async函数对 Generator 函数的改进,体现在以下四点。

(1)内置执行器。

Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。

asyncReadFile();

上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

(2)更好的语义。

async和await,比起星号和yield,语义更清楚。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。

co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

(4)返回值是 Promise。

async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

 

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

 

18.修饰器(Decorator)

修饰器函数,用来修改类的行为

修饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。

 

19.模块化

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

ES6 的模块自动采用严格模式,严格模式主要有以下限制:

  • 变量必须声明后再使用
  • 函数的参数不能有同名属性,否则报错
  • 不能使用with语句
  • 不能对只读属性赋值,否则报错
  • 不能使用前缀 0 表示八进制数,否则报错
  • 不能删除不可删除的属性,否则报错
  • 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
  • eval不会在它的外层作用域引入变量
  • eval和arguments不能被重新赋值
  • arguments不会自动反映函数参数的变化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全局对象
  • 不能使用fn.caller和fn.arguments获取函数调用的堆栈
  • 增加了保留字(比如protected、static和interface)

 

export:使用export命令定义了模块的对外接口

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export { firstName, lastName, year };

import:用于输入其他模块提供的功能。

// main.js
import { firstName, lastName, year } from './profile.js';
function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

 

你可能感兴趣的:(ES6标准入门(阮一峰)读书笔记)