一知半解的Javascript??深入学习预编译操作

187 阅读3分钟

前言:了解什么是预编译

JavaScript的"预编译"通常指的是在代码运行前进行的一些代码转换或优化过程,其作用是为了确保代码运行时未被声明的变量使用情况,还能够提高代码的性能、兼容性和安全性。

声明提升

  • 变量声明,声明提升
  • 函数声明,函数提升

eg one:

6dc0460c7b29e988555c1b12e505c33.png

看到这么一串代码许多人会说“这不一眼就是错的吗?秒了秒了。”

但试着运行会发现是可以运行的,只是并没有a的数值,只是找不到罢了,所以输出的就是undefined

在上面的例子中,尽管a代码是在由于声明提升,它在console.log之前就已经存在了

得到结论:

声明提升是指变量和函数声明在代码执行前被提升到它们各自作用域的顶部的行为。这意味着变量和函数可以在声明之前使用,而不会引发错误。它可以帮助开发者避免一些常见的错误,并更好地控制代码的行为。

函数中预编译

在面对许多大公司的面试里,常常会出一道这样的考题,让你说出分别输出的答案

function fn(){
    console.log(a);
    var a = 10;
    console.log(a);
    function a(){}
    console.log(a);
    var b = function(){} 
    console.log(b);
    function d (){}
    var d = a 
    console.log(d);
}
fn(1)

是不是感觉有些红温了???

解决方法

  1. 创建函数的执行上下文对象 AO (Activation Object)
  2. 找形参和变量声明,将形参和变量名作为AO的属性,值为undefined
  3. 将实参和形参统一
  4. 在函数体内找到函数声明,将函数名作为AO的属性名,值赋予函数体
  • 第二步:可以找到变量声明 var a = 10var b = function(){}var d = a赋值为undefined

26ada5a89ecb18684ffda4dab73a7ac.png

  • 第三步:将实参和形参统一,这里把a赋值为1

e85d3380599386f21cf6b48aceaac92.png

  • 第四步:找到函数声明,值赋予函数体

950e8a3b62a98473a303e85c4662702.png

  • 至此预编译结束,开始从上往下执行function内代码,可以得到结果

c851a15ab9bb056af6338ae46049448.png

全局的预编译

刚刚面试官给你出了一道关于函数中预编译的题目让你顺利过关了,紧接着给你出了一道关于全局的预编译题目,考考你理解的深度

global = 100
function fn() {
    console.log(global);
    global = 200
    console.log(global); 
    var global = 300

}

fn()
console.log(global);
var global

解决方法有些区别

  1. 创建全局执行上下文对象 GO
  2. 找变量声明,将变量名作为AO的属性名,值为undefined
  3. 在全局找函数声明,将函数名作为AO的属性名,值为函数体
  • 第二步:可以找到变量声明var global
  • 第三步:找函数声明function fn()

b6f535ffc159adbc7a2ba3edf60f7d5.png

  • 至此全局的预编译结束等待函数的预编译
  • 函数的预编译

ede732e1ca4992350213f4b7bfd19ed.png

  • 最后得到结果

c3258b54ad797942054c8da8af38f83.png

调用栈

在运行代码的时候实现这么多复杂操作,都要经过栈进行默默地调用,是个默默无闻的老大哥

他是JavaScript中管理函数调用的一个数据结构,一种后进先出的栈。当代码执行时,他会跟踪函数调用的顺序,并在调用栈中保存这些信息,使得代码同步执行,一个函数执行完毕之后,调用栈才会继续执行下一个函数。