Javascript 执行机制
变量提升
把【变量声明部分】和【函数声明部分】提升到代码开头的机制;
在编译阶段,Javascript 解释器会扫描代码,并找到所有的变量声明,无论变量声明在代码的哪个位置,都会在代码执行阶段之前被提升到作用域的顶部;
作用域
作用域决定了代码块中的变量可以在哪里被访问。
全局作用域:在任何地方被访问,在浏览器中,全局作用域是 window
对象。
函数作用域:在函数内部被访问。
块级作用域:let
和 const
关键词用于声明在特定代码块(通常由一个花括号包围的区域),允许变量在如 if
语句或 for
循环中被局部化。
模块作用域:每个模块文件都有自己的作用域,变量或函数在模块内部声明,不会污染全局作用域,要在其他模块中使用这些变量或函数,必须显式导出并在另一个模块中导入它们。
作用域链:
在一个嵌套的作用域中,如果内部作用域没有声明某个变量,解释器会一直向上级作用域查找,直到找到该变量或者达到全局作用域。
this
执行上下文;
全局执行上下文中的 this:指向 window 对象;
函数执行上下文中的 this:默认情况下调用一个函数,其上下文中的 this 也指向 window 对象;
设置函数执行上下文的 this 指向
通过 call 方法设置:foo.call(bar)
通过对象调用方法设置:myObj.showThis()
通过构造函数设置:new CreateObj()
箭头函数
嵌套函数里的 this 不会从外层函数继承,箭头函数可以解决这个问题,它不会创建自身的执行上下文,它的 this 取决于外部函数。
闭包
闭包的形成需要满足三个条件:
首先,有一个【内层函数】;
其次,内层函数【引用】了【外层函数的变量】;
最后,外层函数【执行完毕】后,内层函数在【其他地方被引用】;
这时,内层函数依然可以使用外层函数里的变量,这就是闭包;
原型链
作用:通过对象之间的原型关系,实现属性和方法的继承;
原型链:每个对象都有一个原型(prototype),它是一个对象或 null,访问一个对象的属性或方法时,如果该对象本身没有定义该属性或方法,JavaScript 引擎会自动沿着原型链向上查找,直到找到对应的属性或方法或者达到原型链的顶端;
函数的原型
函数对象特有的属性,由函数对象的 prototype 属性表示,包含可被继承的属性和方法,用于实现基于原型的继承;
对象的原型
由 __proto__
表示,指向对象的原型对象,每个普通对象都具有的属性,用于实现属性和方法的继承;
关系
函数的原型对象也是一个普通对象,继承自 Object;
事件循环
所有同步任务在主线程上执行,形成了一个【执行栈】;
主线程之外还有一个【任务队列】,只要异步任务有了执行结果,就在任务队列当中放置一个事件;
主线程的同步任务执行完毕,就会读取任务队列,对应的异步任务会结束等待状态进入执行栈,开始执行;
宏任务和微任务
主线程里的宏任务执行结束,进入消息队列,执行消息队列里的微任务,结束之后,再执行消息队列里的内层宏任务;
微任务
process.nextTick
Promise.then/catch/finally
await
宏任务
setTimeout