内容页中js未执行_JS代码执行过程详解(面试中的加分项)

本文详细探讨了JavaScript代码在执行过程中的内存分配、变量提升、作用域链和函数执行等核心概念。通过三个示例题目,解释了基本数据类型与引用数据类型的区别,以及它们在赋值操作中的不同行为。此外,还介绍了变量提升、作用域链的形成与查找机制,以及函数执行的步骤。最后,通过一道综合题目巩固了所学知识,强调理解这些概念对于解决实际问题和面试中的加分作用。
摘要由CSDN通过智能技术生成

60374920087448c74ca514acf489950d.png

代码在执行过程中都干了哪些事(增加面试分的知识)

3296904f23ed35bd5066df54ca801ebf.png

1. 开胃题

let a = 12;
let b = a;
b = 13;
console.log(a);
-----------------
let a = {n: 12};
let b = a;
b['n'] = 13;
console.log(a.n);
-----------------
let a = {n: 12};
let b = a;
b = {n: 13};
console.log(a.n);
❝ 当你看到上面这三个题的时候,可能会立马说出输出的结果,但是对于它的执行过程中开辟那些内存,以及其中值发生的变化真的清楚吗?下面以这三个题来作为今天的开场白,咱们一起来聊聊JS代码在执行过程中的一系列过程:

2.JS代码执行中遇到的几个‘词’

「执行环境栈内存ECStack:」 浏览器加载页面的时候,想让代码执行,首先会形成一个栈内存(执行环境栈);然后开始让代码准备执行; 「堆内存Heap」 :存储在执行过程中引用数据类型的值:对象存储的是键值对;函数存储的是字符串 「全局执行上下文EC(G):」 最开始要执行的一定是全局下的代码,此时会形成一个全局代码的执行环境(全局上下文EC(G)),把EC(G)压缩到栈内存中去执行(进栈操作);每一个函数的执行也是这样的操作;

有些上下文在代码执行完成后,会从栈内存中移除去(出栈操作),但是有些情况是不能移除去的(例如:全局上下文就不能移出去);
在下一次有新的执行上下文进栈的时候,会把之前没有移出去的都放栈内存的底部,让最新要执行的在顶部执行; 「GO全局对象=>window:」 在全局下使用var、function声明的变量会在全局对象window中也存储一份,并且建立映射机制(一边的值改变另一边值也改变); 「全局变量存储值对象VO(G):」 把在全局下声明的变量存储在VO(G)中;

「私有变量存储值对象AO(XX):」 当形成私有作用域时,私有变量对象存储在AO(XX)中

3. 结合图片理解开胃题中的执行过程

3.1 基本数据类型值和引用数据类型值的区别

JS中的数据类型目前有两大类:「基本数据类型」「引用数据类型」,他们有什么区别呢?

基本数据类型包括number、string、Boolean、null、undefined、symbol、bigint......;他们都是把值存储在栈内存中的,操作的是值;

引用数据类型包括对象(普通对象、数组对象、正则对象、函数对象、日期对象......) 和 函数;他们都是把值存储在堆内存中,然后把堆内存的地址存储在栈内存中,后期操作的是都是堆内存的地址;

3.2 '='

JS中的'='不像数学函数中的'='那样,它是把「右侧的结果(如果是一个表达式或者自执行函数等都是先计算它的结果)」 赋值 「给左侧的变量」

例如:let a = 1; 就是定义了一个变量a,并且把右侧的1赋值给左侧的变量a

例如: let b = 1+2; 定义了一个变量b,把右侧的运算结果3赋值给左侧的变量b

3.3 变量的关联

在JS中,一个变量只能关联一个值,但是一个值却可以关联多个变量

f4788da1b2e912a86a80d8fb1c61dc4b.png

3.4 执行过程

let a = 12; 它的执行过程是:先创建一个值是12,放在栈内存中;然后再创建一个变量a;最后把两个关联起来;

3.5 开胃题讲解

结合上面的知识来分析一下开胃题

  • 首先浏览器会先开辟一个供代码执行的栈内存
  • 在栈内存中开辟一个全局代码执行的环境EC(G),让代码在这个作用域中一步步的执行
let a = 12;
let b = a;
b = 13;
console.log(a);
-----------------
let a = {n: 12};
let b = a;
b['n'] = 13;//先创建值13存储在栈内存中,然后让b执行的堆内存中的n这个属性改为13
console.log(a.n);
-----------------
let a = {n: 12};
let b = a;
b = {n: 13}; //先创建一个堆内存用来存储值,然后把堆内存的地址存储在栈内存中和变量关联,因为b这个变量只能指向一个值,因此此时b的指向就改为`n:13`的这个堆内存
console.log(a.n);

508d08a79f29b69edb7b72443649cc0b.png

4. 变量提升

「变量提升」是在当前执行上下文中(不管是全局的还是函数执行私有的),JS代码自上而下执行之前,都是先把带varfunction 的进行变量提升;而letconst等没有变量提升机制;

var:会进行提前声明,并且会把声明的变量存储在GO全局变量对象中,之后会存在映射机制; function :会进行提前声明+定义,但是如果function出现在if/for等这些大括号内只会提前声明,并不会定义;

5. var let function const 这四者的区别

  1. varfunction会进行变量提升,而letconst没有变量提升机制;
  2. varfunction声明的变量在定义之前可以使用,而letconst声明的变量在声明之前不能使用;
  3. 在全局执行上下文中使用varfunction声明的变量会向window中也映射一份,而letconst不会;
  4. typeof检测数据类型的时候有一个‘暂时性死区’的问题:如果没有定义这个变量 返回结果是undefined,而不是报错;但是在使用letconst声明这个变量之前使用typeof检测会报错;
  5. if/for这样的大括号内,如果有使用let或者const定义的变量,那么它就是私有的,会存放在if/for这个块作用域中;
  6. 使用const定义的某些值是可以修改的。当const定义基本数据类型的时候不可以修改;但是const定义的是引用数据类型,那么就可以修改它执行的这个堆内存中的内容,此时并没有修改const这个变量的指向。
const a = 10;  //这里a是不可以修改,如果修改会报错
const obj = {age:21};
obj = [10,20];     //这是不可以修改的,如果修改会改变他的指向,因此会报错
obj.age = 22;      //这是可以修改的,他修改的是obj指向的堆内存中的值,并没有改变obj的指向

6. 作用域 与 作用域链

6.1 作用域链的形成

在某一个上下文中创建函数,除了开辟堆内存和赋值之外,还多做了一件事情‘给当前函数设置作用域链[[scope]] = 当前函数创建时候所在的上下文’

6.2 作用域链的查找机制

在当前上下文中,代码执行过程中遇到一个变量,首先看它是否为私有的

  • 如果是私有的,接下来的所有操作,都是操作自己的,和别人没有关系
  • 如果不是私有的,则按照scopeChain作用域链进行操作,在哪个上下文这个找到,当前变量就是谁的...一直找到全局上下文为止
    • 如果找到EC(G)都找不到:如果是获取变量值就会报错,如果是设置值,相当于给GO加属性

7. 函数的执行过程

「创建函数」

  • 在变量提升过程中,如果有带function的,直接定义加创建(自执行函数和函数表达式以及if/for内的除外)
  • 形成自己的作用域:[[scope]] = EC(XX);

「执行函数」

  • 开辟一个私有的上下文
  • 进栈执行
    • 初始化作用域链 [[scope-chain]] = <当前上下文,上级上下文>
    • 初始化this
    • 初始化arguments = {0:1,1:2,length:2}
    • 形参赋值,分别给每个形参赋值
    • 变量提升:var 和 function
    • 代码执行
    • 是否销毁上下文 :如果外面有占用则不销毁,如果没有执行完就立即销毁

8. 检测成果

❝ 下面这个题就是结合了变量提升、函数执行等的一道题目,我把解题的思路使用画图的方式展示出来了,如果还是有不明白的地方,可以在下方的讨论去交流
var x=5,
    y=6;
function func(){
    x+=y;
    func=function(y){
      console.log(y + (--x));
    };
    console.log(x, y);
}
func(4);
func(3);
console.log(x, y);

e5ba22c8ed7034b3ab382bf14a82478f.png

9. 总结

上面关于JS中的变量提升是JS语言中需要攻克的四座大山之一,是我们之后在写程序时候快速解决BUG的基础知识之一。如果在面试过程中,可以把代码每一步的执行过程都说出来,那也是一个加分项。加油

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值