JS的机制解读(一)

102 阅读3分钟

JS机制

变量提升

对于var的声明赋值语句的声明部分将会被提升至变量环境。

注意是仅声明部分,赋值部分还是在原地

函数的声明也会提升

因为function的声明与赋值是一体的,所以有值

相同的函数会覆盖,对于var来说重复声明可以看作一次声明,几次赋值,但是对于let现在声明来说会遇见重复声明的错误。

调用栈

  1. 当JavaScript执行全局代码的时候,会编译全局代码并创建全局执行上下文,而且在整个页面的生存周期内,全局执行上下文只有一份。
  2. 当调用一个函数的时候,函数体内的代码会被编译,并创建函数执行上下文,一般情况下,函数执行结束之后,创建的函数执行上下文会被销毁。
  3. 当使用eval函数的时候,eval的代码也会被编译,并创建执行上下文。

let的实现

对于let在块中的执行:

首先在当前上下文中的词法环境中会创建这个变量,在遇见新的块级作用域时提升新的声明,不过是在词法环境中形成了一个新的栈,在使用变量时通过词法环境的栈顶向下寻找,如果在词法环境中没用找到就将去变量环境中寻找。

注意这个变量虽然在词法环境中创建了,但是由于是用let定义的,所以无法访问。

当作用域执行完成后,所定义的的变量就会从词法环境的栈中弹出。

闭包与作用域链

在每个执行上下文的变量环境中,都包含了一个外部引用,用来指向外部的执行上下文,我们把这个外部引用称为outer

词法作用域

词法作用域就是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。

即与何处调用无关,在编译时已经决定好了词法作用域。

作用域链

// 构造函数
function YourConstructor() {}
​
// JavaScript 引擎在背后做的:
YourConstructor.prototype = Object.create(Object.prototype, {
    constructor: {
        configurable: true,
        enumerable: true,
        value: YourConstructor,
        writable: true
    }
})
​
console.log(YourConstructor.prototype.__proto__ === Object.prototype)   

prototype可以被修改或者赋值,这是函数特有的属性,prototype是这个仓库,其中也有__proto__ 属性指向下一个prototype。

当然,函数的prototype也有__proto__

闭包

在函数中返回函数,因为后者的作用域链连接这前者的作用域,所以只有后者才能访问到前者中的值,也就形成了闭包。

通常,如果引用闭包的函数是一个全局变量,那么闭包会一直存在直到页面关闭;

如果引用闭包的函数是个局部变量,等函数销毁后,在下次JavaScript引擎执行垃圾回收时,判断闭包这块内容如果已经不再被使用了,那么JavaScript引擎的垃圾回收器就会回收这块内存。