-
let与const
对于let和const最重要的两个特性
-
暂时性死区(和var一样,let和const在预编译阶段,就已经声明,但是无法访问,存在暂时性死区)
-
块级作用域(区分于函数作用域,因为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标准(存疑);
-
箭头函数
箭头函数与普通函数除了可以省略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
}
现在我们分析构造函数的运行流程:
- 构造函数的定义(函数的定义),但函数没有运行,可以把它当作一个对象;
- new阶段:构造函数在new创造的this下运行,
我们此时关注一下构造函数中的箭头函数(21行);
它的定义是在new的运行阶段运行了构造函数(32行);
所以它的this会指向这个构造函数的this也就是obj;
所以最终会输出 'Fun';
-
解构赋值
用[]结构会访问迭代器;所以用[]解构不含迭代器的数据会报错(比如普通对象)
用{}解构访问的是key值;
-
类和继承
这位更是重量级;
先来看一个普通的类
class Person {
constructor(name,age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log('class')
}
}
类本质是一个语法糖;
constructor就是构造函数;
其余方法挂载在实例对象的原型;
还有一些继承和super,可以自行总结
-
promise
小熊摊手
promise是符合promiseA+规范的一个一个异步处理,产生一个异步操作的最终结果;
promise有三个状态。Pending(等待态),执行态(Fulfilled),拒绝态(Rejected)
还有一个常见的名词thenable,是指任何携带then方法的对象,都称之为thenable对象(promise.resolve()就要处理thenable对象)
async是es7的特性,是结合promise及generator实现的;
去把他们都写一遍吧。
-
生成器和迭代器
这位最是重量级;
-
迭代器
常见的内置迭代器的数据结构有Array,set,map,String,arguments,Dom集合;
迭代器接口就是一个特殊的Symbol.iterator;
能够调用这个接口的方法有:
-
for...of循环
-
数组解构(上面说过了)
-
扩展操作符[...arr]-扩展运算符会进行判断,有迭代器的使用迭代器,没有迭代器通过key来遍历
-
Array.from
-
Promise.all() 参数为promise组成的可迭代对象
-
Promise.race() 参数为promise组成的可迭代对象(所以这两个方法要先判断传入的是否是可迭代对象)
-
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行代码)
-
下面我们来讲生成器
生成器可以帮我们快速生成一个迭代器;
你可能会产生一个疑惑,我不是已经生成迭代器了吗?
生成器生成迭代器代码可读性更高,更容易控制;
举个例子
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关键字,会返回一个迭代器对象;
生成器的优点:
- 懒加载
- 内存效率
生成器的缺点:
-
只能按照顺序访问
-
只能一次性访问
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)
}
只看不敲代码是不行滴