【前端】JavaScript中的函数形式参数:预解析与作用域详解


在这里插入图片描述

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

文章目录

  • 💯前言
  • 💯示例代码
  • 💯1. 形式参数的预解析
    • 模拟预解析后的代码
  • 💯2. 函数作用域与子函数的关系
    • 代码详解
  • 💯3. 扩展:块作用域与变量提升
  • 💯4. 实际应用场景与最佳实践
  • 💯小结


在这里插入图片描述


💯前言

  • JavaScript 编程中,函数的形式参数是一个经常被忽视但极为重要的概念。形式参数不仅充当局部变量的角色,其初始化方式和作用域规则更是与普通变量存在显著差异。这些独特规则不仅影响代码的可读性维护性,还可能在复杂的嵌套作用域中引发意料之外的行为。理解形式参数的预解析机制及其在不同作用域中的表现,是开发者深入掌握 JavaScript关键
    本文以一个具体的示例代码为基础,详细剖析 JavaScript 中形式参数的预解析、作用域规则及其与子函数的相互影响,并通过扩展讨论块作用域变量提升的问题,最终总结出实用的开发建议与最佳实践
    JavaScript在这里插入图片描述

💯示例代码

以下是本文分析的核心代码示例:

function a(nms) {nms = 100; // 修改形式参数 nmsconsole.log(nms); // 输出 100function b() {var w = 10; // 声明局部变量 wconsole.log(nms); // 此处访问的依然是 a() 函数的 nms 参数nms = 20; // 修改的仍然是 a() 函数作用域内的 nms}
}

💯1. 形式参数的预解析

在JavaScript中,形式参数的行为等同于在函数体顶部以var声明一个变量。这意味着,在函数内部执行代码之前,形式参数已被隐式声明并初始化为局部变量。


模拟预解析后的代码

为了更清晰地理解形式参数的预解析过程,我们通过模拟代码展示实际执行的逻辑:

function a(nms) {// 预解析阶段的效果,相当于在函数顶部添加以下代码:var nms; // 形式参数被隐式声明为局部变量function b() { //函数声明提前var w // 变量声明提前w = 10;console.log(nms); // 此处访问的依然是 a() 函数的 nms 参数nms = 20; // 修改的仍然是 a() 函数作用域内的 nms}// 执行阶段nms = 100; // 修改的是函数 a 内部作用域的形式参数 nmsconsole.log(nms); // 输出 100
}

解析

  • 形式参数nms在函数定义时已被隐式声明,相当于在函数顶部添加var nms
  • 在函数内部,形式参数的作用域优先级高于任何同名的全局变量或外部变量。

这种预解析过程与JavaScript的变量提升机制密切相关。变量声明会被提升到作用域的顶部,但赋值操作仍保持在原有位置。形式参数因而可以在整个函数体内使用,其初始值仅在实际调用函数时被赋予。

验证形式参数的优先级

let nms = 50;
function a(nms) {console.log(nms); // 输出 undefined,因为形式参数在作用域中被隐式声明但尚未赋值
}

这种行为在实际开发中有助于避免局部变量命名覆盖全局变量或外部变量,从而提高代码的稳定性和可维护性。


💯2. 函数作用域与子函数的关系

JavaScript采用词法作用域(Lexical Scope),即函数的作用域在定义时就已确定,而非在运行时动态生成。在示例代码中,子函数b可以访问父函数a中的形式参数nms,且对其的修改会直接影响父函数的nms


代码详解

  1. 父函数作用域的继承

    function a(nms) {nms = 100;console.log(nms); // 输出 100function b() {var w = 10;console.log(nms); // 输出 100,访问的是父函数的 nms}
    }
    
    • 子函数b的作用域链包括自身作用域、父函数a的作用域以及全局作用域。
    • 子函数b能够读取父函数a中定义的局部变量nms
  2. 子函数对父函数变量的修改

    function a(nms) {nms = 100;console.log(nms); // 输出 100function b() {nms = 20; // 修改的是父函数作用域中的 nmsconsole.log(nms); // 输出 20}b(); // 调用子函数 bconsole.log(nms); // 输出 20,因为 nms 已经被子函数 b 修改
    }
    
    • 子函数b直接修改了父函数a中的nms
    • 因为nms是父函数a的局部变量,子函数和父函数共享这部分作用域。

这种设计机制在需要多个嵌套函数共享数据时尤其有用。


💯3. 扩展:块作用域与变量提升

在ES6之前,JavaScript仅支持函数作用域(Function Scope),而没有块作用域(Block Scope)。这导致了变量提升(Hoisting)的现象。

function test() {console.log(x); // 输出 undefined,因为变量 x 被提升但尚未赋值var x = 10;
}

ES6引入了letconst,使块作用域成为可能,解决了变量提升带来的问题。

function test() {console.log(x); // 报错:ReferenceError,因为 x 在块作用域内未被声明let x = 10;
}

此外,块作用域还使得循环中的变量处理更加安全:

for (let i = 0; i < 5; i++) {setTimeout(() => console.log(i), 1000);
}
// 输出:0, 1, 2, 3, 4

相比之下,使用var时,由于变量提升问题,console.log会输出相同的值。


💯4. 实际应用场景与最佳实践

  1. 避免全局变量污染

    • 使用局部变量代替全局变量,确保形式参数不会覆盖全局变量。
    function process(data) {let result = data + 100; // 使用 let 声明局部变量console.log(result);
    }
    
  2. 理解作用域链

    • 理解作用域链的工作机制,避免在子函数中无意修改父函数的变量。
  3. 使用严格模式

    • 在严格模式下,未声明变量会导致运行时错误,从而减少作用域相关问题。
    'use strict';
    function a(nms) {nms = 100;console.log(nms);
    }
    
  4. 模块化编程

    • 使用ES6模块或CommonJS模块,将变量作用域局限于模块内部,避免全局污染。

💯小结

  • 在这里插入图片描述
    本文深入探讨了 JavaScript 中函数形式参数的预解析和作用域管理。通过分析具体代码示例,我们了解了形式参数如何被隐式声明为局部变量,以及它们在函数执行过程中所表现出的独特行为。我们还探讨了函数作用域链块作用域变量提升,并总结了适用于实际开发的最佳实践
    现代 JavaScript 提供了letconst等新特性,使开发者能够更精确地控制变量作用域。通过实践严格模式和模块化编程,开发者可以有效减少作用域相关错误,提高代码质量。掌握这些关键概念将帮助开发者更自信地编写复杂应用,避免常见的作用域问题,最终提升开发效率代码可维护性

在这里插入图片描述


在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/488062.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一个C++程序--(蓝桥杯备考版)

第一个C程序 基础程序 #include <iostream>//头⽂件 using namespace std;//使⽤std的名字空间 int main()//main函数 {cout << "hello world!" << endl; //输出&#xff1a;在屏幕打印"hello world!" return 0;}main函数 main 函数是…

AMD-Vi completion-wait loop timed out

前言 内核大量打印"AMD-Vi completion-wait loop timed out"&#xff0c;同时伴随有soft lockup或者rcu cpu stall&#xff0c;如下&#xff1a; Dec 8 10:02:17 kernel: AMD-Vi: Completion-Wait loop timed out Dec 8 10:02:17 kernel: AMD-Vi: Completion-W…

14.在 Vue 3 中使用 OpenLayers 自定义地图版权信息

在 WebGIS 开发中&#xff0c;默认的地图服务通常会带有版权信息&#xff0c;但有时候我们需要根据项目需求自定义版权信息或添加额外的版权声明。在本文中&#xff0c;我们将基于 Vue 3 的 Composition API 和 OpenLayers&#xff0c;完成自定义地图版权信息的实现。 最终效果…

docker的网络类型和使用方式

docker的网络类型 5种网络类型 bridge 默认类型&#xff0c;桥接到宿主机docker0的网络&#xff0c;有点类似于VM虚拟机的NAT网络模型。 案例: docker run --rm -itd --network bridge --name wzy666wzy-bridge alpine host host类型&#xff0c;共享宿主机的网络空间&#…

Micropython 扩展C模块<HelloWorld>

开发环境 MCU&#xff1a;Pico1&#xff08;无wifi版&#xff09;使用固件&#xff1a;自编译版本开发环境&#xff1a;MacBook Pro Sonoma 14.5开发工具&#xff1a;Thonny 4.1.6开发语言&#xff1a;MicroPython 1.24 执行示例 在github上获取micropython&#xff0c;我使…

0002.简易酒店管理系统后台

一.系统架构 springmvcjsplayuimysql 二.功能特性 简单易学习&#xff0c;虽然版本比较老但是部署方便&#xff0c;tomcat环境即可启用&#xff1b;代码简洁&#xff0c;前后端代码提供可统一学习&#xff1b;祝愿您能成尽快为一位合格的程序员&#xff0c;愿世界没有BUG; …

Android 车载虚拟化底层技术-Kernel 5.10 -Android12(multi-cards)技术实现

详细代码实现见 Android Display Graphics系列文章-汇总​​​​​​Android Display Graphics系列文章-汇总 Android Display Graphics系列文章-汇总 Android Display Graphics系列文章-汇总 本文主要包括部分&#xff1a; 一、Android12的Kernel 5.10版本 1.1 Kernel 5…

「Mac玩转仓颉内测版50」小学奥数篇13 - 动态规划入门

本篇将通过 Python 和 Cangjie 双语介绍动态规划的基本概念&#xff0c;并解决一个经典问题&#xff1a;斐波那契数列。学生将学习如何使用动态规划优化递归计算&#xff0c;并掌握编程中的重要算法思想。 关键词 小学奥数Python Cangjie动态规划斐波那契数列 一、题目描述 …

MySQL(数据类型)

目录 1. 数值类型 2. bit类型 3.小数类型 3. 字符串类型 4 日期和时间类型 5. enum和set 1. 数值类型 对标C语言&#xff1a; tinyint->char(1字节)&#xff1a; 有符号&#xff1a;127 ~ 255 无符号&#xff1a;0 ~ -128。 smalli…

1. Flink自定义Source

一. Source 简介 DataStream是Flink的低级API&#xff0c;用于进行数据的实时处理&#xff0c;Flink编程模型分为Source、Transformation、Sink三个部分&#xff0c;如下图所示。 默认Flink提供了大量的内置Source&#xff0c;常见的Source如下&#xff1a; 基于文件的Sour…

运维新手入门——KVM(Beginner‘s Guide to Operations and Maintenance - kvm)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

一个功能强大的视频翻译和本地化配音工具,支持影视级双语字幕/视频配音

家好&#xff0c;今天给大家分享一个功能强大的视频翻译和本地化配音工具VideoLingo&#xff0c;旨在为用户提供高质量的字幕和配音服务&#xff0c;让全世界的知识能够跨越语言的障碍共享。 项目介绍 VideoLingo项目的开发旨在解决视频内容创作者和翻译者面临的跨语言障碍问题…

力扣-图论-9【算法学习day.59】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…

doxygen–自动生成文档工具

原文地址&#xff1a;doxygen–自动生成文档工具 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 简介 doxygen是软件开发中广泛使用的文档生成工具。它可以从源代码注释中自动生成文档&#xff0c;解析类、函数、参数相关信息&#xff0c;并生…

上市公司投资效率Biddle模型数据(包括最终数据、原始数据及构造说明)2003-2022年

一、计算方式&#xff1a;参考《Journal of accounting and economics》Biddle G C&#xff0c;构建Biddle模型使用企业投资对成长机会的回归模型来估计企业的投资效率&#xff0c;这里成长机会用销售增长率来衡量。回归模型如下图所示: 二、资料范围&#xff1a;包括原始数据…

用JavaScript实现一个贪吃蛇游戏

原理如下&#xff0c;贪吃蛇的蛇身就是一个数组&#xff0c;数组中的每个元素都是一个坐标&#xff0c;蛇身每次移动时都会在数组前插入一个新坐标&#xff0c;并在数组尾部删掉一条记录&#xff0c;吃到食物后数组的尾部记录就不删。如果移到屏幕边缘会从屏幕的另一边出现。好…

【Canvas与光阑】立方体六彩光阑

【成图】 120*120的png图标 大小图&#xff1a; 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>立方体 六彩光阑 Draft2</…

[代码随想录14]二叉树的常用操作,翻转,对称,最大深度和最小深度,递归版本

前言 在二叉树的题目中&#xff0c;递归的解法无疑是是最简单和最好理解的&#xff0c;也能快速解题&#xff0c;本篇介绍一下递归的常见的二叉树题目。 题目链接 226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 101. 对称二叉树 - 力扣&#xff08;LeetCode&#…

css基础记录

基础 选择器 复合选择器 后代选择器 div p {}; 类似如上,找到div中所有的后代,注意是所有的后代 子代选择器 > div > a 只选择div的儿子中有a的 并集选择器 用逗号,分隔 p,div,span,h1 { … } 一般一行写一个 CSS元素显示模式 分为块元素,行内元素 块元素 特点…

HDR视频技术之六:色调映射

图像显示技术的最终目的就是使得显示的图像效果尽量接近人们在自然界中观察到的对应的场景。 HDR 图像与视频有着更高的亮度、更深的位深、更广的色域&#xff0c;因此它无法在常见的普通显示器上显示。 入门级的显示器与播放设备&#xff08;例如普通人家使用的电视&#xff0…