JavaScript作用域

本文深入解析JavaScript中的作用域概念,包括函数作用域和全局作用域的特点,并通过具体示例阐述变量的可见性和生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


载自《Node.js开发指南》附录A.1


        作用域(scope)是结构化编程语言中的重要概念,它决定了变量的可见范围和生命周期,正确使用作用域可以使代码更清晰、易懂。作用域可以减少命名冲突,而且是垃圾回收的基本单元。和 C、C++、Java 等常见语言不同,JavaScript 的作用域不是以花括号包围的块级作用域(block scope),这个特性经常被大多数人忽视,因而导致莫名其妙的错误。例如下面代码,在大多数类 C 的语言中会出现变量未定义的错误,而在 JavaScript 中却完全合法:

if (true) {
var somevar = 'value';
}
console.log(somevar); // 输出 value

这是因为 JavaScript 的作用域完全是由函数来决定的,if、for 语句中的花括号不是独立的作用域。


1、函数作用域


       不同于大多数类 C 的语言,由一对花括号封闭的代码块就是一个作用域,JavaScript 的作用域是通过函数来定义的,在一个函数中定义的变量只对这个函数内部可见,我们称为函数作用域。在函数中引用一个变量时,JavaScript 会先搜索当前函数作用域,或者称为“局部作用域”,如果没有找到则搜索其上层作用域,一直到全局作用域。我们看一个简单的例子:


var v1 = 'v1';
var f1 = function() {
  console.log(v1); // 输出 v1
};
f1();
var f2 = function() {
  var v1 = 'local';
  console.log(v1); // 输出 local
};
f2();

以上示例十分明了,JavaScript 的函数定义是可以嵌套的,每一层是一个作用域,变量搜索顺序是从内到外。下面这个例子可能就有些令人困惑:
var scope = 'global';
var f = function() {
  console.log(scope); // 输出 undefined
  var scope = 'f';
}
f();

       上面代码可能和你预想的不一样,没有输出 global,而是undefined,这是为什么呢?这是 JavaScript 的一个特性,按照作用域搜索顺序,在 console.log 函数访问 scope 变
量时,JavaScript 会先搜索函数 f 的作用域,恰巧在 f 作用域里面搜索到 scope 变量,所以上层作用域中定义的 scope 就被屏蔽了,但执行到 console.log 语句时,scope 还
没被定义,或者说初始化,所以得到的就是 undefined 值了。
        

        我们还可以从另一个角度来理解:对于开发者来说,在访问未定义的变量或定义了但没有初始化的变量时,获得的值都是 undefined。于是我们可以认为,无论在函数内什么地方定义的变量,在一进入函数时就被定义了,但直到 var 所在的那一行它才被初始化,所以在这之前引用到的都是 undefined 值。(事实上,JavaScript 的内部实现并不是这样,未定义变量和值为 undefined 的变量还是有区别的。)

        函数作用域的嵌套

        接下来看一个稍微复杂的例子:

var f = function() {
  var scope = 'f0';
  (function() {
     var scope = 'f1';
     (function() {
       console.log(scope); // 输出 f1
     })();
  })();
};
f();

       上面是一个函数作用域嵌套的例子,我们在最内层函数引用了 scope 变量,通过作用域搜索,找到了其父作用域中定义的 scope 变量。
       有一点需要注意:函数作用域的嵌套关系是定义时决定的,而不是调用时决定的,也就是说,JavaScript 的作用域是静态作用域,又叫词法作用域,这是因为作用域的嵌套关系可以在语法分析时确定,而不必等到运行时确定。下面的例子说明了这一切:
var scope = 'top';
var f1 = function() {
  console.log(scope);
};
f1(); // 输出 top
var f2 = function() {
  var scope = 'f2';
  f1();
};
f2(); // 输出 top

       这个例子中,通过 f2 调用的 f1 在查找 scope 定义时,找到的是父作用域中定义的 scope 变量,而不是 f2 中定义的 scope 变量。这说明了作用域的嵌套关系不是在调用
时确定的,而是在定义时确定的。

2、全局作用域

       在 JavaScript 中有一种特殊的对象称为 全局对象。这个对象在Node.js 对应的是 global对象,在浏览器中对应的是 window 对象。由于全局对象的所有属性在任何地方都是可见的,所以这个对象又称为 全局作用域。全局作用域中的变量不论在什么函数中都可以被直接引用,而不必通过全局对象。
满足以下条件的变量属于全局作用域:
        在最外层定义的变量;
        全局对象的属性;
        任何地方隐式定义的变量(未定义直接赋值的变量)。


        需要格外注意的是第三点,在任何地方隐式定义的变量都会定义在全局作用域中,即不通过 var 声明直接赋值的变量。这一点经常被人遗忘,而模块化编程的一个重要原则就是避免使用全局变量,所以我们在任何地方都不应该隐式定义变量。



资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 在 Android 开发中,Fragment 是界面的一个模块化组件,可用于在 Activity 中灵活地添加、删除或替换。将 ListView 集成到 Fragment 中,能够实现数据的动态加载与列表形式展示,对于构建复杂且交互丰富的界面非常有帮助。本文将详细介绍如何在 Fragment 中使用 ListView。 首先,需要在 Fragment 的布局文件中添加 ListView 的 XML 定义。一个基本的 ListView 元素代码如下: 接着,创建适配器来填充 ListView 的数据。通常会使用 BaseAdapter 的子类,如 ArrayAdapter 或自定义适配器。例如,创建一个简单的 MyListAdapter,继承自 ArrayAdapter,并在构造函数中传入数据集: 在 Fragment 的 onCreateView 或 onActivityCreated 方法中,实例化 ListView 和适配器,并将适配器设置到 ListView 上: 为了提升用户体验,可以为 ListView 设置点击事件监听器: 性能优化也是关键。设置 ListView 的 android:cacheColorHint 属性可提升滚动流畅度。在 getView 方法中复用 convertView,可减少视图创建,提升性能。对于复杂需求,如异步加载数据,可使用 LoaderManager 和 CursorLoader,这能更好地管理数据加载,避免内存泄漏,支持数据变更时自动刷新。 总结来说,Fragment 中的 ListView 使用涉及布局设计、适配器创建与定制、数据绑定及事件监听。掌握这些步骤,可构建功能强大的应用。实际开发中,还需优化 ListView 性能,确保应用流畅运
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值