串讲ES6特性

93 阅读5分钟
  1. let与const

对于let和const最重要的两个特性

  1. 暂时性死区(和var一样,let和const在预编译阶段,就已经声明,但是无法访问,存在暂时性死区)

  2. 块级作用域(区分于函数作用域,因为var有函数作用域,但是没有类似for的块级作用域Script)

在执行上下文(es6)中,let和const放在不同的位置,let和const保存在词法环境中而非变量环境中

那也就意味着,在es6中,变量环境仅仅保存着var变量

outer指针(作用域链的指针)let和const变量,this指针都保存在词法环境中(在es5中this是单独拆分出来的,es5的执行上下文包括词法环境,变量环境,this指针);

浏览器的let保存在scope中的script中,而非global,scope是一个es3的概念,这边我也没查到相关资料,为什么会使用scope。可能是浏览器还是es3标准,兼容更高的es标准(存疑);

  1. 箭头函数

箭头函数与普通函数除了可以省略return之外,只有this指向的问题(我推荐先把普通的this搞搞清楚再来看箭头函数的this)。

通过执行上下文我们不难看出,每一个运行的函数作用域都有自己的词法环境,词法环境中保存着函数运行的this指向。

箭头函数的函数作用域不会像普通函数一样维护自己的this指向,而是继承定义箭头函数的函数作用域的this指向(可以理解为从作用域链查找this),这是一件很有意思的事。

var name = 'window'
const obj = {
    name:'obj',
    fun:()=>{
        console.log(this.name)
    }
}
obj.fun() //window;

let name = 'window'
const obj = {
    name:'obj',
    fun:()=>{
        console.log(this.name)
    }
}
obj.fun() //undefined,let变量不挂载在window上。

const Fun = function(){
    this.name = 'Fun';
    this.fun = ()=>{
        console.log(this.name)
    }
}

const FunObject = new Fun();
FunObject.fun()

//想要明白这个案例,必须要知道new到底干了什么;
const myNew = (callback,args)=>{
    const obj = Object.create(null);
    callback.call(obj,args)
    obj.__proto__ = callback.prototype;
    return obj
}

现在我们分析构造函数的运行流程:

  1. 构造函数的定义(函数的定义),但函数没有运行,可以把它当作一个对象;
  2. new阶段:构造函数在new创造的this下运行,

我们此时关注一下构造函数中的箭头函数(21行);

它的定义是在new的运行阶段运行了构造函数(32行);

所以它的this会指向这个构造函数的this也就是obj;

所以最终会输出 'Fun';

  1. 解构赋值

用[]结构会访问迭代器;所以用[]解构不含迭代器的数据会报错(比如普通对象)

用{}解构访问的是key值;

  1. 类和继承

这位更是重量级;

先来看一个普通的类

class Person {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    
    sayHello() {
        console.log('class')
    }
}

类本质是一个语法糖;

constructor就是构造函数;

其余方法挂载在实例对象的原型;

还有一些继承和super,可以自行总结

  1. promise

小熊摊手

promise是符合promiseA+规范的一个一个异步处理,产生一个异步操作的最终结果;

promise有三个状态。Pending(等待态),执行态(Fulfilled),拒绝态(Rejected)

还有一个常见的名词thenable,是指任何携带then方法的对象,都称之为thenable对象(promise.resolve()就要处理thenable对象)

async是es7的特性,是结合promise及generator实现的;

去把他们都写一遍吧。

juejin.cn/post/685621…

  1. 生成器和迭代器

这位最是重量级;

  1. 迭代器

常见的内置迭代器的数据结构有Array,set,map,String,arguments,Dom集合;

迭代器接口就是一个特殊的Symbol.iterator;

能够调用这个接口的方法有:

  1. for...of循环

  2. 数组解构(上面说过了)

  3. 扩展操作符[...arr]-扩展运算符会进行判断,有迭代器的使用迭代器,没有迭代器通过key来遍历

  4. Array.from

  5. Promise.all() 参数为promise组成的可迭代对象

  6. Promise.race() 参数为promise组成的可迭代对象(所以这两个方法要先判断传入的是否是可迭代对象)

  7. yield*操作符,在生成器中使用

现在我们来访问已经自带迭代器对象的迭代器

const arr = [1,2,3,4];

const iterFun = arr[Symbol.iterator]; //ƒ values() { [native code] } ——这是一个迭代器构造函数

const iter = iterFun() //ArrayIterator {} ——这是一个迭代器;

console.log(iter.next()) //{value:1,done:false};
console.log(iter.next()) //{value:2,done:false};
console.log(iter.next()) //{value:3,done:false};
console.log(iter.next()) //{value:4,done:true};
console.log(iter.next()) //{value:undefined,done:true}

我们可以自己实现一个迭代器

class iterClass {
    constructor(){
        
    }
    // 添加一个构造器生成函数——一个构造函数
    [Symbol.iterator](){
    // 一般来讲,这里会定义一些变量从而next产生闭包,实现迭代;
    
    
     //返回一个带有next方法的对象
        return {
        
            next(){
                return {done:false , value:1}
            }
        }
    }
}

const iterObject = new iterClass()

const iter = iterObject[Symbol.iterator]();

iter.next() // {value:1,done:false}

那么我们现在实现一个有实际作用的迭代器;

class iterClass {
    constructor(limit){
        this.limit = limit
    }
    // 添加一个构造器生成函数——一个构造函数
    [Symbol.iterator](){
    // 一般来讲,这里会定义一些变量从而next产生闭包,实现迭代;
    let count = 0 ;
    const limit = this.limit
    
     //返回一个带有next方法的对象
        return { 
            next(){
                if(count<limit){
                    count++;
                    return {done:false , value:count}
                }
                else{return {done:true,value:count}}
            },
            //终止迭代器
            return() {
                return {done:true}
            }
        }
    }
}

const iterObject = new iterClass()

const iter = iterObject[Symbol.iterator]();

iter.next() // {value:1,done:false}

迭代器内部也实现了迭代器生成函数,可以生成一个一模一样的迭代器。。。。意义不明的操作

迭代器除了带有next方法,还带有迭代器终止方法,可以在for...of中终止迭代(21行代码)

  1. 下面我们来讲生成器

生成器可以帮我们快速生成一个迭代器;

你可能会产生一个疑惑,我不是已经生成迭代器了吗?

生成器生成迭代器代码可读性更高,更容易控制;

举个例子

function* gene(value){   
    yield value+10;
    yield value+20;
    yield value+15
}

const iter = gene(10)
console.log(iter.next().value);// 20
console.log(iter.next().value);// 40
console.log(iter.next().value);// 55
console.log(iter.next().value);// undefined

每次执行到yield关键字,会返回一个迭代器对象;

生成器的优点:

  1. 懒加载
  2. 内存效率

生成器的缺点:

  1. 只能按照顺序访问

  2. 只能一次性访问

async-await是如何实现的

async function asyncAwait(){
    const a = await task0;
    console.log(a);
    const b = await task1;
    console.log(b)
}

//模仿await 用迭代器生成一个

function* generatorPromise() {
    const a = yield task0;
    console.log(a);
    const b = yield task1;
    console.log(b)
}

只看不敲代码是不行滴