JavaScript的作用域介绍

JavaScript的作用域介绍

作用域(scope)是编程语言中的一个基本概念,它定义了程序中变量、函数、对象等标识符(identifier)的可见性和生命周期。简单说,就是决定了在程序的哪些部分可以访问或使用这些标识符。

JavaScript的作用域规定了变量和函数的可访问性和可见性。作用域定义了变量和函数的有效范围和生命周期。

JavaScript中有以下几种作用域:

全局作用域(Global Scope):

全局作用域是定义在代码的最外层,不在任何函数内部的作用域。在全局作用域中定义的变量和函数可以在代码的任何地方访问。

var globalVar = 'I am global';

function globalFunction() {
    console.log(globalVar); // 输出 "I am global"
}

console.log(globalVar); // 输出 "I am global"
globalFunction();

在全局作用域中使用var声明变量时,在整个脚本范围内都可以访问,且这些变量会成为全局对象(在浏览器中是window对象)的属性。这意味着可以通过全局对象来访问这些变量,例如window.x。
在全局作用域中使用let声明变量时,在整个脚本范围内都可以访问,但这些变量不会成为全局对象(在浏览器中是window对象)的属性。这意味着不能通过全局对象来访问这些变量,例如window.y。
例如
var x = 10;
let y = 20;
console.log(window.x); // 10
console.log(window.y); // undefined

在现代JavaScript开发中,推荐使用let(或const,如果变量不需要重新赋值)来替代var。let提供了更好的作用域控制,减少了因变量提升或作用域混淆造成的错误,提高代码的可维护性和可读性。

 

函数作用域(Function Scope):

函数作用域是指在函数内部定义的变量和函数只在函数内部可见。函数作用域可以避免变量命名冲突,并且提供了封装和信息隐藏的特性。

function myFunction() {
    var x = 10;
    console.log(x); // 输出 10
}

myFunction();
console.log(x); // 报错:x is not defined

块级作用域(Block Scope):

块级作用域是指在一对花括号{}内部定义的变量和函数,只在该块级作用域内可见。在ES6之前,JavaScript中没有块级作用域,只有函数作用域和全局作用域。

function blockScopeExample() {
    if (true) {
        var x = 10; // 在块级作用域之外仍可访问
        let y = 20; // 只在块级作用域内可访问
        const z = 30; // 只在块级作用域内可访问
    }
    console.log(x); // 输出 10
    console.log(y); // 报错:y is not defined
    console.log(z); // 报错:z is not defined
}

blockScopeExample();

在上述示例中,变量x在块级作用域之外仍可访问,而使用let和const声明的变量y和z则只在块级作用域内可访问。

词法作用域(Lexical Scope)

词法作用域(Lexical Scope)和闭包相关。

闭包(Closure)是指一个函数能够访问和操作其词法作用域之外的变量的能力。简而言之,闭包是由函数以及其相关的引用环境组合而成的包裹(或封闭)体。

在JavaScript中,当一个函数被定义时,它会创建一个词法作用域,并捕获(或保存)它所在的作用域链。作用域链是一个包含所有父级作用域的链式结构,它决定了函数在执行时可以访问的变量。当函数形成闭包时,它会保留对其词法作用域中变量的引用,即使该词法作用域的上下文已经销毁。

闭包的特性使得函数可以在其定义的作用域之外被调用,但仍然可以访问其词法作用域中的变量。这使得闭包非常有用,可以用于创建私有变量和实现模块化的代码结构。

JavaScript采用词法作用域,也称为静态作用域。词法作用域意味着变量的作用域是在函数定义时确定的,而不是在函数调用时确定的。

function outer() {
    var x = 10;

    function inner() {
        console.log(x); // 闭包:可以访问外部函数outer的变量x
    }

    return inner;
}

var closureFunc = outer(); // 返回inner函数形成的闭包
closureFunc(); // 输出 10

在上述示例中,函数inner形成了一个闭包,可以访问外部函数outer中的变量x。即使outer函数执行完毕,变量x的相关信息仍然保留在闭包中,使得closureFunc可以继续访问并输出x的值。

Javascript中,在“严格模式”中不会自动创建全局变量

"自动创建全局变量"是指在非严格模式下,当在全局作用域或函数内部使用一个未声明的变量时,JavaScript会自动将该变量创建为一个全局变量。这意味着该变量可以在程序的任何地方被访问和修改,而不仅仅在当前作用域内。

在 JavaScript 的严格模式(strict mode)下,如果在全局作用域或函数内部使用未声明的变量,会抛出一个错误,而不是自动创建一个全局变量。可以在脚本或函数的顶部添加 "use strict"; 来启用严格模式。

在非严格模式下,如果你在全局作用域或函数内部使用一个未声明的变量,JavaScript 会自动创建一个全局变量。例如:

function foo() {
    x = 10; // 在非严格模式下,会自动创建一个全局变量 x
}
foo();
console.log(x); // 输出 10
但是,在严格模式下,这种行为是不允许的。你必须显式地声明变量,否则会抛出一个错误。例如:
"use strict";

function foo() {
    x = 10; // 在严格模式下,会抛出一个 ReferenceError,因为 x 没有被声明
}

foo(); // 抛出 ReferenceError: x is not defined

使用严格模式可以帮助你避免一些常见的编程错误,例如使用未声明的变量,并促使你编写更加规范和可维护的代码。建议在 JavaScript 文件的开头或函数的开头启用严格模式,以确保整个脚本或函数都运行在严格模式下。

Javascript的作用域链

JavaScript的作用域链(scope chain)是指在程序执行过程中,变量和函数的查找顺序。当在一个作用域中引用一个变量或函数时,JavaScript会按照作用域链的顺序从内层作用域向外层作用域逐级查找,直到找到该变量或函数为止。

作用域链的构建是基于函数的嵌套关系。每当定义一个函数时,JavaScript会创建一个包含该函数的作用域,并将其嵌套在当前作用域中。这样形成了一个作用域的层级结构,每个作用域都有一个指向外层作用域的引用。

当在一个作用域中引用一个变量时,JavaScript首先在当前作用域中查找该变量,如果找到了,则使用该变量;如果未找到,则会沿着作用域链向上查找,直到全局作用域。如果在全局作用域中仍未找到该变量,则会抛出一个错误。

以下是一个简单的示例来说明作用域链的概念:

let x = 10;

function outer() {
    let y = 20;
    
    function inner() {
        let z = 30;
        console.log(x + y + z); // 在此处的作用域链为 inner -> outer -> global
    }
    
    inner();
}

outer();

在上面的示例中,当在inner函数中引用变量x、y和z时,JavaScript会按照作用域链的顺序查找这些变量。首先在inner的作用域中查找变量z,然后在外层作用域outer中查找变量y,最后在全局作用域中查找变量x。因此,最终输出的结果为60。

附录

作用域https://developer.mozilla.org/zh-CN/docs/Glossary/Scope

闭包https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

实用的闭包https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

理解Javascript的作用域和作用域链https://juejin.cn/post/6844904069413224462

一文彻底搞懂JS作用域https://segmentfault.com/a/1190000044251549

深入理解JavaScript作用域和作用域链https://segmentfault.com/a/1190000018513150

说说你对作用域链的理解https://vue3js.cn/interview/JavaScript/scope.html#%E4%B8%80%E3%80%81%E4%BD%9C%E7%94%A8%E5%9F%9F

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习&实践爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值