ES6

1. let

1. let只在当前代码块内有效。
for(let i=0;i<arr.length;i++){
.....
}
console.log(i) // i is not defined

2. let不存在变量提升
3. 暂时性死区
var temp=123;
if(true){
let temp=4556;
//内部temp相当于一个局部变量,在声明之前,该变量不可使用。在语法上称为“暂时性死区”
}
console.log(temp) // 123

4. 不允许重复声明
let 不允许在相同作用域({})内重复声明一个变量。
ES6允许块级作用域任意嵌套,且外层作用域无法读取内层作用域的变量。
5. ES6规定,块级作用域中,函数声明语句类似let,块级作用域外不可引用

2. const

const声明是一个只读的常量,不能改变
只在声明所在的块级作用域内有效

notice:

var 命令和function命令声明的全局变量依旧是全局对象的属性,let,const命令声明的全局变量不再属于全局对象的属性。

3. 变量解构赋值

  1. 数组解构赋值: var [a,b,c]=[1,2,3]
  2. 对象解构赋值:
    var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
    baz // "aaa"
  3. 字符串解构赋值
  4. 函数参数解构赋值

用途
- 交换变量值 eg. [x,y]=[y,x]
- 从函数返回多个值。
- function example(){
return [1,2,3];
}
var [a,b,c]=example();

- 函数参数的定义
- // 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

- 提取JSON数据
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]

  • 函数参数的默认值
    jQuery.ajax = function (url, {
    async = true,
    beforeSend = function () {},
    cache = true,
    complete = function () {},
    crossDomain = false,
    global = true,
    // ... more config
    }) {
    // ... do stuff
    };
  • 遍历Map结构
    var map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');
    for (let [key, value] of map) {
    console.log(key + " is " + value);
    }
    // first is hello
    // second is world

  • 输入模块的指定方法:
    const { SourceMapConsumer, SourceNode } = require("source-map");

4. 字符串的扩展

  1. codePointAt([index]):返回对应位置字符的码点
  2. String.fromCodePoint([unicode]):用于从码点返回对应字符。
  3. at():返回字符串给定位置的字符。
  4. for….of: 新增字符串遍历接口
  5. includes(), startsWith(),endsWith(): 返回布尔值。
  6. repeat(n): 返回重复n次的字符串
  7. padStart(), padEnd(): ES7推出,头部、尾部补全。
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'

  8. 模板字符串:(“),模板字符串中嵌入变量,需要将变量名写在${}之中。

  9. String.raw()

5. 正则的扩展
6. 数值的扩展

  1. Number.isFinite(), Number.isNaN(): 只对数值数值有效,否则一律返回false
  2. Number.parseInt(), Number.parseFloat();
  3. Number.isInteger(): 3和3.0为同一个值。
  4. Number.EPSILON,新增一个极小常量。
  5. Math对象的扩展


  1. Math.trunc(): 去除一个数的小数部分,返回整数部分。
  2. Math.sign(): 用来判断一个数是正数,负数,零。

参数为正数,返回+1;
参数为负数,返回-1;
参数为0,返回0;
参数为-0,返回-0;
其他值,返回NaN。

7. 数组的扩展

1 . Array.from(arrlike,[func],[context]): 将类数组和可遍历的对象转换为数组。功能类似于ES5:[].slice.call(arraylike)。第二个参数,类似于map方法,将处理后的值放入返回的数组。第三个参数,传入this的环境。
2 . 扩展运算符:(…)也可以将某些数据转换为数组。eg. function foo() {
var args = [...arguments];
}

3 . Array.of(): 将一组值转换为数组。Array.of(3, 11, 8) // [3,11,8]
4 . copyWithin(target, start = 0, end = this.length):

target(必需):从该位置开始替换数据。
start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。

5 . find(): 用于找到第一个符合条件的数组成员。
6 . findIndex(): 返回第一个符合条件的数组成员的位置
7 . fill(): 使用给定值,填充一个数组。
8 . 数组实例的:entries(),keys(),values()

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}

9 . includes(): Array.prototype.includes返回一个布尔值。

8. 函数的扩展
1 . ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。eg. function log(x, y = 'World') {
console.log(x, y);
}

2.(…): 可以将一个数组转为逗号分隔的参数序列。
3 . name属性:返回该函数的函数名。

4 . 箭头函数

如果箭头函数的代码块部分多于一条语句,需要用大括号括起来,并使用return返回。
1. 函数体内的this对象,是定义时所在的对象,不是使用时所在的对象。
2. 不可以当作构造函数,即不能使用new命令,否则报错。
3. 不可以使用arguments对象,该对象在函数体内不存在。
4. 不可以使用yield命令。

5 . 函数绑定
函数绑定运算符:(::),左边是对象,右边为函数,运算符会自动将左边对象作为上下文环境。

6 . 尾调用优化,尾递归

9. 对象的扩展
1 . 属性简洁表示:

  1. ES6允许在对象中,只写属性名,不写属性值,这时属性值等于属性名所代表的变量。eg.
    function f(x, y) {
    return {x: x, y: y};
    }
    f(1, 2) // Object {x: 1, y: 2}
  2. 方法也可以简写: eg.
    var o={method(){return 'hello!'}}
  3. ES6允许字面量定义对象,使用变量作为属性名。eg:
    let obj = {[propKey]: true, ['a' + 'bc']: 123
    };
  4. 属性名表达式与简洁表示法不能同时使用。

2 . Object.is(): 比较两个值是否严格相等,基本与“===”相同,但+0不等于-0,二是NaN等于自身。

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

3 . Object.assign(): 用于对象的合并,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举属性。

var target = { a: 1 };

var source1 = { b: 2 };
var source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

notes:
- Object.assign是浅拷贝,即如果源对象某个属性的值是对象,那么目标对象得到的是对这个对象的引用。如果源对象发生变化,目标对象的属性也会改变。
- Object.assign还能用来处理数组,但会把数组视为对象。eg:
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]

4 . 属性遍历:

  1. for…in
  2. Object.keys(obj): 返回自身所有可枚举属性的数组
  3. Object.getOwnPropertyNames(obj): 返回自身的所有属性的数组。
  4. Object.getOwnPropertySymbols(obj):返回一个数组,包含自身所有symbol属性。
  5. Refletc.ownKeys(obj)
  1. __proto__属性: 读取或设置当前prototype对象。可以用:Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.create()(生成操作)代替
  2. Object.setPrototypeOf():设置对象的prototype对象。
  3. Object.getPrototypeOf():读取
  4. Object.values(), Object.entries(),Object.keys

5 . 对象的扩展运算符

  1. Rest解构赋值(…): 用于从一个对象取值,将所有可遍历但未读取的属性,分配到对象上。
    eg:
    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    x // 1
    y // 2
    z // { a: 3, b: 4 }
  2. 扩展运算符(…): 用于取出参数对象的所有可遍历属性,拷贝到当前对象中。

10 . Symbol
原始数据类型,表示独一无二的值,保证对象的属性独一无二。

Symbol作为属性名,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有Symbol属性名。
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值。

11 . Set和Map数据结构
set
类似于数组,成员值都是唯一的,无重复。

var s=new Set();
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
 log([...s])// [1, 2, 3]
 log(Array.from(s))//[1, 2, 3]
 log(s)//Set(3) {1, 2, 3}

1 . set 函数可以接受一个数组或类数组作为对象,转换为set数据。

var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
> 向set加入值,不会发生类型转换。5和"5"是不同值,但NaN等于NaN。

2 . set实例属性和方法:
- Set.prototype.constructor:构造函数,默认就是Set函数。
- Set.prototype.size:返回Set实例的成员总数。
- 实例方法:
add(value):添加某个值,返回set结构本身
delete(value):删除某个值,返回布尔值,表示是否删除成功。
has(value): 返回一个布尔值,表示是否为Set成员。
clear():清除所有成员,没有返回值。

3 . 遍历操作:
keys(),values(),entries(),forEach()
由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以key方法和value方法的行为完全一致。

let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

Set结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。这意味着,可以省略values方法,直接用for…of循环遍历Set。

let set = new Set(['red', 'green', 'blue']);

for (let x of set) {
  console.log(x);
}
// red
// green
// blue

WeakSet
weakSet与Set类似,也是不重复的值的集合,区别:
1. WeakSet成员只能是对象
2. WeakSet对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,如果其他对象不再引用这个对象,那么垃圾回收机制将自动回收该对象所占内存。这意味着无法引用WeakSet的成员,因此WeakSet不可遍历。

var ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set

WeakSet可以接受一个数组或类似数组的对象作为参数。该数组的所有成员,都会自动成为WeakSet实例对象的成员。因此:数组的成员只能是对象。

原型方法:

WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。
WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中。

Map
Map类似于对象,也是键值对的集合,但是“键”不限于字符串,各种类型的值都可以当键。
1 . 接受对象作为键值

    var m=new Map();
    var o={p:"hello world"};

    m.set(o,"content");
    m.get(o);// "content"
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false

2 . 接受数组作为参数,数组成员是一个个表示键值对的数组。

var map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"

只有对同一个对象的引用,Map结构才将其视为同一个键。

var map = new Map();

map.set(['a'], 555);
map.get(['a']) // undefined

实例属性和操作方法:
(1)size属性
(2)set(key, value)
(3)get(key)
(4)has(key)
(5)delete(key)
(6)clear()
遍历方法:
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回所有成员的遍历器。
forEach():遍历Map的所有成员。

12 . Iterator和for…of循环
遍历器(Iterator)是一种接口,为各种不同数据结构提供统一访问机制。任何数据只要部署Iterator接口,就可以完成遍历操作。
作用:
1. 提供统一的访问接口
2. 使数据结构的成员按照某种次序排列
3. 创造了新的遍历命令for…of循环,Iterator接口主要供for…of消费。

13 . Generator函数

function * foo(x, y) { ··· }

Generator函数是一个普通函数,有两个特征:
1. function关键字和函数名之间有一个*号
2. 函数体内部,使用yield语句,定义不同内部状态。如果有多条yield语句,可以遍历然后输出

Generator函数调用同样加圆括号,但是调用后并不执行,必须调用遍历器对象的next方法,才执行,遇到yield语句,暂停,直到遇到下个next方法恢复执行,一直执行到return语句,遍历结束,done属性为true.

1 . yield语句
Generator函数也可以省略yield,即变成一个单纯的暂缓执行函数。

function* f() {
  console.log('执行了!')
}

var generator = f();

setTimeout(function () {
  generator.next()
}, 2000);
  1. yield语句不能再普通函数中调用。
  2. yield语句如果用在一个表达式之中,必须放在圆括号里面。

for…of循环可以自动遍历Generator函数生成的Iterator对象,此时不再需要调用next方法。

14 . Promise
Promise是一个对象,可以获取异步操作的消息。
Promise状态:
pending, resolved, rejected
只有异步操作的结果,可以决定当前是哪种状态,任何其他操作都无法改变这个状态。

基本用法

 var promise=new Promise(function(resolve,reject){
       //...some code

       if(/*异步操作成功*/){
           resolve(value)
       }else{
           reject(error)
       }
   })

Promise 构造函数接受一个函数作为参数,该函数两个参数分别是resolvereject,是两个函数。由js引擎提供。
resolve函数作用:将Promise对象的状态从“pending”变“resolved”,在异步操作成功时调用,并将异步操作结果传递出去。
reject函数作用:将状态由“pending”变“reject”,失败时调用,并将错误作为参数传递出去。
Promise实例生成后,可以用then方法分别制定resolved,reject状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

实例:

   var proTimer=function(){
      return new Promise(function(resolve,reject){
          setTimeout(function(){
              if(test>100){
                  resolve("成功")
              }else{
                  reject("失败")
              }
          },1200)

   })};
//proTimer异步函数执行后,promise状态改变,会立即出发then方法绑定的回调函数。
    proTimer().then(function(value){
        log(value)
    },function(err){
        log(err)
    });

Promise.prototype.then()
then方法返回的是一个新的promise实例,因此可以采用链式写法,then后面再调用then, 第一个回调函数完成后,会将返回结果作为参数传递给第二个then回调函数。

Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

getJSON("/posts.json").then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法。
跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。但chrome浏览器不遵守这条规定,会抛出错误。

promise.all()
用于将多个Promise实例,包装成一个新的promise实例

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

Promise.all方法的参数必须有iterator接口,且返回的每个成员都是promise实例。

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race()

Promise.race同样将多个promise实例包装成一个新实例。

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

不同的是,只要任一个实例率先改变,p的状态就跟着改变。率先改变的promise实例的返回值就传递给p的回调函数。

Promise.resolve()
将现有对象转换为Promise对象。

Promise.resolve("foo")
//等价于
new Promise(resolve=>resolve("foo"))

Promise.resolve方法参数分为四种情况:
1. 参数是一个promise实例:那么不做任何修改,返回这个实例。
2. 参数是一个thenable对象,指具有then方法的对象。

let thenable={
then:function(resolve,reject){...
.)}

Promise.resolve会将这个对象转换为promise对象,然后立即执行thenable对象的then方法。
3. 参数不是具有then方法的对象,或者不是对象。
promise.resolve返回一个新的promise对象,状态为resolved.

var p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello

4 . 不带参数:直接返回一个resolved状态的promise对象。立即resolve的promise对象,是在本轮“事件循环”结束时,setTimeout是在下一次事件循环开始时。

Promise.reject()
Promise.reject(reason)也会返回一个promise实例,实例状态为rejected.

部署done(), finally()方法

done()
保证抛出任何可能出现的错误。

 Promise.prototype.done=function(onFullfilled,onRejected){
        this.then(onFullfilled,onRejected)
                .catch(function(reason){
                    setTimeout(()=>{throw reason},0)
                })
    }

finally()
finally方法用于指定不管promise对象最后状态如何,都会执行的操作,接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

 Promise.prototype.finally=function(callback){
        let P=this.constructor;
        return this.then(
                value => P.resolve(callback()).then(()=>value),
        reason=>P.resolve(callback()).then(()=>{throw reason})
        )
    }

15 . 异步操作和Async函数
异步编程的实现:

回调函数:

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

Promise:将回调函数的嵌套修改成链式调用。

Generator函数

协程:多个线程相互协作,完成异步任务
运行流程如下:
第一步,协程A开始执行。
第二步,协程A执行到一半,进入暂停,执行权转移到协程B。
第三步,(一段时间后)协程B交还执行权。
第四步,协程A恢复执行。
协程A就是异步任务,它分两段或多段执行
写法如下:

   function * asyncJob(){
       //...其他代码
       var f=yield readFile(fileA);//执行到此处,执行权转让出去,等到执行权返回后,再从这继续往后执行
       //...其他代码
   }

Generator函数调用next()方法可以继续执行任务。

Generator函数的数据交换和错误处理:
next():返回的值是Generator函数向外输出的数据,next()还可以接受参数,进而传入到Generator函数,作为上个阶段任务的返回结果。

function* gen(x){
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }

Generator函数内部还可以部署错误处理代码,捕获函数体外抛出的错误:

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw('出错了');
// 出错了

异步任务的封装:

    var fetch=require("node-fetch");

    function * gen(){
        var url = 'https://api.github.com/users/github';
        var result = yield fetch(url);
        console.log(result.bio);
    }

    var g=gen();
    var result= g.next();
    result.value.then(function(data){
        return data.json();
    }).then(function(data){
        g.next(data)
    })

Thunk函数的含义
参数求值策略:
1. 传值调用:进入函数体之前,就计算好参数的值
2. 传名调用:进入函数体之后,用到该参数的时候,计算该参数的值。
传名调用的实现,即将参数放到一个临时函数中,再将这个临时函数传入函数体,这个临时函数成为Thunk函数。

function f(m){
  return m * 2;
}

f(x + 5);

// 等同于

var thunk = function () {
  return x + 5;
};

function f(thunk){
  return thunk() * 2;
}

JS中也是传值调用,但是它的thunk函数替换的不是表达式,而是多参数函数,将其替换成单参数版本,且只接受回调函数作为参数。

Async函数
1. async函数返回一个promise对象
async函数内部,return语句返回的值,会成为then方法回调函数的参数。
2. async函数返回Promise对象,必须要等到内部所有await命令的promise对象执行完,才会发生状态改变。
3. 正常情况下,await命令后面是一个promise对象,如果不是,会调用Promise.resolve()转换成promise对象。

await命令后面的Promise对象如果变为reject状态,reject的参数会被catch方法的回调函数接收到。
只要一个await的promise变为reject,那么整个async函数都会中断执行。
eg.

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

为避免这个问题,两种解决方法:
1. 放在try…catch结构里

async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world
  1. await后面promise对象再跟一个catch

async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出错了
// hello world

如果有多个await命令,可以统一放在try…catch结构中

4 . 如果await后面的异步操作出错,那么等同于async函数返回的promise对象被reject.

注意点

  1. 最好把await命令放在try…catch代码块中
  2. 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

继发:

let foo = await getFoo();
let bar = await getBar();

同时触发:

// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

3 . await只能用在async函数中,用在普通函数中会报错,例如forEach里不能用await.可以使用for循环。

16. Class类
ES6引入class概念,通过class关键字定义类。

//定义类
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {//定义在prototype原型上的方法
    return '(' + this.x + ', ' + this.y + ')';
  }
}

定义类的方法的时候,不需要function关键字,直接定义函数就可以,方法之间不需要都好分隔,否则会报错。

使用类,也是用new命令,跟构造函数用法一致。

可以使用Object.assign()一次性向类添加多个原型方法:

class Point{
    constructor(){
        //...
    }
}
    Object.assign(Point.prototype,{
        toString(){},
        toValue(){}
    })

类内部定义的所有方法,都是不可枚举的。

  1. constructor方法:生成实例自动调用该方法,如果没有显示定义,会默认添加一个空的constructor(){}, 默认返回实例对象,也可以改写。
  2. 不存在变量提升。
  3. 类也可以用表达式的形式定义。
const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};
//使用表达式定义了一个类。需要注意的是,这个类的名字是MyClass而不是Me,Me只在Class的内部代码可用,指代当前类。如果内部没有用到Me,可以省略Me,即:
const MyClass=class {//....}

4 . 私有方法:
es6不提供私有方法,可以在模块外定义私有方法,然后模块内部调用bar.call(this,baz),这就使得bar成为当前模块的私有方法。
5 . this指向:默认指向类的实例,

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值