做软装有什么网站找图片,福州网站建设,长沙网站seo外包,seo刷词工具在线JavaScript变量的作用域介绍
JavaScript 变量的作用域决定了变量在代码中的可访问性。
var 是 JavaScript 中最早用于声明变量的关键字#xff0c;它函数作用域或全局作用域。
let 关键字#xff0c;具有块级作用域、全局作用域。
const关键字#xff0c;具有块级作用域…JavaScript变量的作用域介绍
JavaScript 变量的作用域决定了变量在代码中的可访问性。
var 是 JavaScript 中最早用于声明变量的关键字它函数作用域或全局作用域。
let 关键字具有块级作用域、全局作用域。
const关键字具有块级作用域、全局作用域。
var、let 和 const 关键字对比表 特性 var let const 作用域 函数作用域或全局作用域 块级作用域、全局作用域 块级作用域、全局作用域 变量提升 提升到作用域顶部初始化为 undefined 声明前访问会报错因存在“暂时性死区”Temporal Dead Zone 声明前访问会报错因存在“暂时性死区”Temporal Dead Zone 重复声明 合法后续声明覆盖前一个值 不合法抛出 SyntaxError 不合法抛出 SyntaxError 是否可变 可变 可变 不可变引用不可变但内容可变 是否成为全局对象属性 是在全局上下文中 否 否
下面展开介绍
1. 作用域类型
全局作用域Global Scope
定义在函数外声明的变量。特点 任何地方都可访问包括函数内部。过度使用全局变量可能导致命名冲突和代码难以维护。在浏览器环境中全局变量通常与 window 对象关联。浏览器环境中var 声明的全局变量会成为 window 对象在浏览器环境中的属性let 和 const 不会。
注意
避免隐式全局变量始终显式声明变量。
在非严格模式下未使用 var、let 或 const 关键字声明的变量会被隐式提升为全局变量。
在严格模式下未声明的变量会导致 ReferenceError因此不会创建隐式全局变量。
var在全局上下文中声明的变量会成为全局对象的属性具有全局作用域。
let 和 const在全局上下文中声明的变量是全局变量但不会成为全局对象的属性 let 或 const 关键字还可以声明块级作用域见后面。 全局变量的创建方式
1)隐式全局变量
myGlobalVar Hello, World!; // 隐式全局变量
console.log(myGlobalVar); // 输出 Hello, World!
console.log(window.myGlobalVar); // 输出 Hello, World!因为它是 window 的属性2)显式全局变量
使用window对象可以明确地创建全局变量。
window.myExplicitGlobalVar Hello, again!; // 显式全局变量
console.log(window.myExplicitGlobalVar); // 输出 Hello, again!
console.log(myExplicitGlobalVar); // 输出 Hello, again!直接访问也可以。3) 使用 var、let 或 const 关键字声明全局变量
//使用 var 声明全局变量
var globalVar Hello;
console.log(globalVar); // 输出: Hello
console.log(window.globalVar); // 输出: Hello因为它是 window 对象的属性//使用 let 声明全局变量
let globalLetVar Hello;
console.log(globalLetVar); // 输出: Hello
console.log(window.globalLetVar); // 输出: undefined不是 window 的属性//使用 const 声明全局变量
const globalConstVar Hello;
console.log(globalConstVar); // 输出: Hello
console.log(window.globalConstVar); // 输出: undefined不是 window 的属性
注意虽然全局变量在某些情况下是必要的但为了防止命名冲突和提高代码质量现代编程实践中通常不鼓励过度依赖全局变量。 函数作用域Function Scope
定义在函数内部用var声明的变量和函数参数作用范围为整个函数。特点 在函数内任何位置包括嵌套代码块可访问。 示例
function func() {if (true) {var innerVar 内部变量; // 属于函数作用域}console.log(innerVar); // 内部变量正常访问
}
func();此例同时说明var 声明的变量没有块级作用域即使在块如 if、for、while 等中声明变量仍然属于包含它的函数或全局作用域。
var 声明的变量会被提升hoisting到当前作用域的顶部但赋值不会被提升。这意味着变量在声明之前可以访问但值为 undefined。例如
console.log(hoistedVar); // 输出: undefined
var hoistedVar I am hoisted;块级作用域ES6
定义由 {} 包围的代码块如 if、for使用 let 或 const 声明。特点 变量仅在块内有效。避免循环变量泄露等问题。 示例
if (true) {let blockVar 块内变量;const PI 3.14;
}
console.log(blockVar); // 报错blockVar未定义此例说明let 和 const 不会被提升存在“暂时性死区”Temporal Dead Zone即声明前访问会报错。 注意 • let 和 const 声明的变量仅在 声明它们的代码块内有效。 • 如果在函数体的最外层不嵌套在任何代码块中声明则作用域为 整个函数体因为函数体本身是一个块级作用域。 • 如果在函数内的嵌套代码块中声明如 if 内部则作用域仅限该代码块。 var、let和const的区别
var 具有函数作用域在函数内部声明的变量只在函数内部有效。如果在全局作用域中声明则具有全局作用域。存在变量提升hoisting但未初始化的变量会返回undefined。可以重复声明同一个变量。 let和const 具有块级作用域在代码块内部声明的变量只在代码块内部有效。不会被提升到块的顶部。不允许重复声明同一个变量。let声明的变量可以重新赋值而const声明的变量不能重新赋值具有只读性且必须在声明时立即赋值否则报错。 2.作用域链与闭包
作用域链Scope Chain函数在定义时确定作用域链逐级向上查找变量。闭包Closures函数保留对外部作用域的引用即使外部函数已执行完毕。 内部函数可以访问外部函数的变量。外部函数执行完毕后其作用域不会被销毁而是被内部函数引用。 作用域链示例
let globalVar global;function outerFunction() {let outerVar outer;function innerFunction() {let innerVar inner;console.log(innerVar); // 输出: innerconsole.log(outerVar); // 输出: outerconsole.log(globalVar); // 输出: global}innerFunction();
}outerFunction();当访问一个变量时JavaScript会按照作用域链的顺序查找变量。作用域链是从当前作用域开始逐级向上查找直到全局作用域。 闭包示例
function outerFunction() {let outerVar I am outer;function innerFunction() {console.log(outerVar); // 访问外部变量}return innerFunction;
}let myClosure outerFunction();
myClosure(); // 输出: I am outer闭包是指函数可以访问其外部作用域的变量即使外部函数已经执行完毕。 附1、严格模式使用use strict
在严格模式下未声明的变量会导致ReferenceError从而避免全局变量污染。严格模式是ES5引入的一种特殊的运行模式使代码在更严格的条件下运行。通过在代码开头添加 use strict 声明来启用。可以应用于整个脚本或单个函数。
启用方式
// 整个脚本使用严格模式 use strict; // 后续代码...
// 或在函数内使用 function myFunction() { use strict; // 函数代码... }
示例非严格模式和严格模式下未声明变量直接赋值的行为差异。
假设我们有以下代码片段
function myFunction() {x 10; // 未声明的变量 xconsole.log(x); // 输出 x 的值
}myFunction();
console.log(x); // 在全局作用域中访问 x1)非严格模式下的行为 在非严格模式下如果直接给未声明的变量赋值JavaScript 会自动将该变量提升为全局变量。 function myFunction() { x 10; // 未声明的变量 x console.log(x); // 输出 10 }
myFunction(); console.log(x); // 输出 10 解释 在myFunction函数中变量x没有被声明没有使用var、let或const但直接赋值为10。 非严格模式下JavaScript 会自动将x提升为全局变量。因此x在函数内部和全局作用域中都可以被访问。 这种行为可能导致意外的全局变量污染。 2)严格模式下的行为 在严格模式下未声明的变量直接赋值会抛出ReferenceError。 use strict; // 启用严格模式
function myFunction() { x 10; // 未声明的变量 x console.log(x); // 抛出 ReferenceError : x is not defined }
myFunction(); console.log(x); // 这行代码不会被执行 解释 在严格模式下JavaScript 不允许直接给未声明的变量赋值。 如果尝试给未声明的变量赋值JavaScript 会抛出ReferenceError提示变量未定义。 这种行为可以防止意外创建全局变量减少潜在的错误和命名冲突。
关于 JavaScript 严格模式的官方文档可见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode 附2、可变Mutable和不可变Immutable
“可变”Mutable和“不可变”Immutable是描述变量或数据是否可以被修改的术语。
1)可变Mutable
如果一个变量或数据结构的内容可以被修改那么它就是可变的。这意味着你可以直接改变变量的值或数据结构中的某些部分而不会创建新的对象。
示例
// 可变的变量
let number 10;
number 20; // 修改变量的值number 现在是 20 // 可变的对象
let obj { name: Alice };
obj.name Bob; // 修改对象的属性obj 现在是 { name: Bob }
obj.age 25; // 添加新的属性obj 现在是 { name: Bob, age: 25 }
在上面的例子中
number 是一个可变的变量因为它的值可以从 10 改为 20。
obj 是一个可变的对象因为它的属性可以被修改或添加。 2)不可变Immutable
如果一个变量或数据结构的内容不能被修改那么它就是不可变的。这意味着一旦创建它的值或内容就无法被改变。如果需要“修改”通常会创建一个新的对象或变量。
示例
// 不可变的变量使用 const 声明
const PI 3.14;
PI 3.14159; // 抛出 TypeError: Assignment to constant variable.
在上面的例子中
PI 是一个不可变的变量因为它被 const 声明不能被重新赋值。 不可变对象
虽然 JavaScript 中没有原生的不可变对象但可以通过一些技术手段如 Object.freeze()使对象的结构和属性不可变。
JavaScript复制
const obj Object.freeze({ name: Alice });
obj.name Bob; // 不会报错但不会生效obj 仍然是 { name: Alice }
obj.age 25; // 不会报错但不会生效obj 仍然是 { name: Alice }
在上面的例子中
obj 是一个不可变的对象因为通过 Object.freeze() 方法它的属性无法被修改或添加。 3. 可变与不可变的区别
可变数据 可以直接修改。修改操作通常会影响原始数据。在某些情况下可能导致意外的副作用如在函数中修改传入的对象。 不可变数据 不能直接修改。修改操作会创建一个新的对象或数据结构。更安全避免了意外修改导致的错误。常用于函数式编程因为函数式编程强调“无副作用”的函数。 小结
可变Mutable可以被修改。不可变Immutable不能被修改。在 JavaScript 中let 声明的变量是可变的而 const 声明的变量是不可变的但对象或数组的内容可以被修改。不可变性有助于提高代码的安全性和可维护性尤其是在复杂的应用中。