当前位置: 首页 > article >正文

【前端】JavaScript作用域与预解析:深入理解问题与解答


在这里插入图片描述

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
本文专栏: 前端

文章目录

  • 💯前言
  • 💯题目一:局部变量与提升
    • 代码分析:
    • 预解析后的代码结构
    • 详细执行过程
    • 输出结果:
    • 思考要点:
  • 💯题目二:函数参数与变量提升
    • 代码分析:
    • 预解析后的代码结构
    • 详细执行过程
    • 输出结果:
    • 思考要点:
  • 💯题目三:函数声明与局部变量遮蔽
    • 代码分析:
    • 预解析后的代码结构
    • 详细执行过程
    • 输出结果:
    • 思考要点:
  • 💯拓展知识:函数声明与变量声明的提升
    • 函数声明是局部变量的声明
    • 变量遮蔽与作用域链
  • 💯小结


在这里插入图片描述


💯前言

  • 在 JavaScript 中,作用域、变量提升(Hoisting)、函数声明与赋值的行为经常是开发者在学习中遇到的难点。本文通过对几道经典的代码解析题目进行详细剖析,来帮助你更好地理解 JavaScript 的执行顺序和作用域链。我们会一一讨论题目中的预解析结果、具体的输出以及背后的原因。
    JavaScript在这里插入图片描述

💯题目一:局部变量与提升

在这里插入图片描述


代码分析:

在这里插入图片描述

var x = 20;

function fn() {
    if (x) {
        var x = 30;
    }
    console.log(x); // 这里打印值是多少?
}

fn();
console.log(x); // 这里打印值是多少?

预解析后的代码结构

在这里插入图片描述
在 JavaScript 中,变量声明和函数声明会被提升到各自作用域的顶部。因此,函数 fn 中的 var x 也会被提升到函数顶部。预解析后的代码结构如下:

var x; // 全局变量声明提升,初始值为 undefined
function fn() {
    var x; // 局部变量声明提升,初始值为 undefined

    if (x) {
        x = 30; // 不会执行,因为 x 是 undefined,条件为 false
    }
    console.log(x); // 输出 undefined
}

// 执行阶段
x = 20; // 全局变量赋值
fn();   // 调用函数 fn,进入局部作用域
console.log(x); // 输出 20

详细执行过程

在这里插入图片描述

  1. 全局作用域提升阶段:

    • var x 提升到全局作用域顶部,初始值为 undefined
    • 函数 fn 提升到全局作用域顶部,完整保留。
  2. 执行 fn() 函数:

    • fn 内的 var x 被提升到函数顶部,初始值为 undefined
    • if (x) 语句中,x 的值为 undefined,所以条件为 false,不会进入 if 块。
    • console.log(x) 输出的是局部变量 x 的值,即 undefined
    • 然后在全局作用域中,console.log(x) 输出全局变量的值 20

输出结果:

  • fn() 内的 console.log(x) 输出:undefined
  • 全局的 console.log(x) 输出:20
    在这里插入图片描述

思考要点:

  • 局部变量 x 遮蔽了全局变量 x,即使局部变量未赋值。
  • if (x) 判断时,使用的是函数作用域中的局部 x,初始值是 undefined
    在这里插入图片描述

💯题目二:函数参数与变量提升

在这里插入图片描述


代码分析:

在这里插入图片描述

function fun(param) {
    console.log(param); // 这里打印值是多少?
    var param = function () {
        console.log(1);
    };
    console.log(param); // 这里打印值是多少?
}

fun(5);

预解析后的代码结构

在这里插入图片描述
在 JavaScript 中,当函数参数和局部变量同名时,参数的声明会被优先考虑,但局部变量的声明会被忽略,赋值操作仍然会执行。

function fun(param) {
    // 参数 `param` 被提升,作为函数的局部变量,初始值为传递的参数值 5
    console.log(param); // 输出 5
    param = function () { // 赋值操作覆盖了参数的值
        console.log(1);
    };
    console.log(param); // 输出函数体
}

// 执行阶段
fun(5);

详细执行过程

在这里插入图片描述

  1. 调用 fun(5) 时,参数 param 被赋值为 5
  2. 第一次 console.log(param)
    • 输出 5,因为此时 param 的值是传递的参数。
  3. 执行 param = function() { console.log(1); }
    • param 被赋值为一个函数,覆盖了之前的参数值。
  4. 第二次 console.log(param)
    • 输出 function () { console.log(1); },因为此时 param 已经被覆盖为该函数。

输出结果:

  • 第一次 console.log(param) 输出:5
  • 第二次 console.log(param) 输出:function () { console.log(1); }
    在这里插入图片描述

思考要点:

  • 函数参数会优先于函数内部的 var 声明。
  • var param 的声明被忽略,但赋值操作仍然执行,因此覆盖了参数 param 的值。

在这里插入图片描述


💯题目三:函数声明与局部变量遮蔽

在这里插入图片描述


代码分析:

在这里插入图片描述

var foo = 1;

function bar() {
    function foo() {}
    foo = 10;
    console.log(foo); // 这里打印值是多少?
}

bar();
console.log(foo); // 这里打印值是多少?

预解析后的代码结构

在这里插入图片描述

var foo; // 全局变量声明,初始值 undefined
function bar() {
    function foo() {} // 局部变量 foo,初始值为函数
    foo = 10;         // 覆盖局部变量 foo 的值
    console.log(foo); // 输出 10
}

// 执行阶段
foo = 1; // 全局变量赋值
bar();   // 调用 bar 函数
console.log(foo); // 输出 1

详细执行过程

在这里插入图片描述

  1. 全局作用域提升阶段:

    • var foo 提升,初始值为 undefined
    • 函数 bar 提升到全局作用域顶部。
    • bar 函数中,function foo() 声明被提升到 bar 内部顶部,声明了一个局部变量 foo,初始值为函数。
  2. 执行阶段:

    • 调用 bar() 时,局部变量 foo(最初是一个函数)被重新赋值为 10
    • console.log(foo) 输出 10,因为局部变量 foo 已被赋值为 10
    • 最后在全局作用域中,console.log(foo) 输出全局变量的值 1,因为全局变量 foo 没有被 bar 内部的操作影响。

输出结果:

  • bar() 内的 console.log(foo) 输出:10
  • 全局的 console.log(foo) 输出:1
    在这里插入图片描述

思考要点:

  • 函数声明 function foo()bar 中被提升,相当于声明了一个局部变量。
  • foo = 10 是对局部变量的重新赋值,不会影响全局变量。

在这里插入图片描述


💯拓展知识:函数声明与变量声明的提升

在 JavaScript 中,函数声明的提升优先于变量声明。这意味着函数会被完整地提升到作用域的顶部,并且在变量声明之前可以使用。但变量声明只会被提升声明,赋值操作仍然保留在原地。
在这里插入图片描述


函数声明是局部变量的声明

在题目三中,function foo() 实际上相当于声明了一个局部变量 foo,并将其初始化为一个函数对象。正因如此,当后续的 foo = 10 进行赋值时,修改的是这个局部变量,而不是全局的 foo

这说明函数声明不仅仅是定义一个可调用的代码块,它也会在当前作用域中创建一个变量,这个变量的名字与函数名相同。
在这里插入图片描述


变量遮蔽与作用域链

在这里插入图片描述

当函数内部声明一个与外部变量同名的变量时,这个内部变量会遮蔽外部的变量,这就是所谓的作用域链中的遮蔽现象。遮蔽意味着在当前作用域中,同名的外部变量变得不可访问,除非使用特定的方式(例如 this 或全局对象)访问全局变量。


💯小结

  • 在这里插入图片描述
    通过以上几个例子,我们深入理解了 JavaScript 中的作用域变量提升函数声明与变量声明之间的关系。关键点包括:
  1. 函数参数与变量声明的优先级
    函数参数会优先于函数内部的同名 var 声明

  2. 函数声明是局部变量的声明
    在函数内部声明函数,相当于在当前作用域创建了一个局部变量,且初始值为函数对象

  3. 变量遮蔽
    函数内部的变量会遮蔽外部的同名变量,函数声明也会有类似的行为。

  4. 预解析的重要性
    理解 JavaScript预解析过程有助于理解代码的执行顺序,尤其是复杂的作用域变量提升问题。


在这里插入图片描述



http://www.kler.cn/a/410221.html

相关文章:

  • Java面试之多线程并发篇
  • 微信小程序下拉刷新与上拉触底的全面教程
  • Vue 3 动态组件教程
  • Java 8 Stream API 在数据转换中的应用 —— 将列表转换为映射
  • 【食品包装原纸】市场未来几年行业竞争将更加激烈,尤其在中国市场
  • 高级网络安全——SSL/TLS, HTTPS, VPN(week4)
  • Python期末复习-系列数据类型
  • 路由缓存后跳转到新路由时,上一路由中的tip信息框不销毁问题解决
  • fingerprint.js的使用
  • 【RAG 项目实战 05】重构:封装代码
  • King‘s IOT :实验室设备及环境物联监控预警系统
  • Flask 创建API接口服务
  • 学习threejs,使用设置bumpMap凹凸贴图创建褶皱,实现贴图厚度效果
  • JDK1.8新增特性
  • Java 面经 - HashMap
  • 深入探索Go语言中的sync.Mutex与sync.RWMutex:原理、应用与实践
  • Git Github Gitlab与Gitee的关系
  • 如何在 Eclipse 中调试ABAP程序
  • 【vim】vim怎么把某一列内容复制到另一列
  • 长短时记忆网络(SLTM):理解与实践
  • 基于web的音乐网站(Java+SpringBoot+Mysql)
  • 用 Python 从零开始创建神经网络(十):优化器(Optimizers)(持续更新中...)
  • 利用Google的OR-Tools解决智能调度问题
  • 小程序-基于java+SpringBoot+Vue的美食推荐系统设计与实现
  • 无监督跨域目标检测的语义一致性知识转移
  • vxe-grid table 修改表格数据校验的主题样式