了解JS作用域

作用域

什么是作用域

作用域其实就是看代码在执行过程中某个区域内是否能访问到某个变量、函数或者对象。

举个栗子

function foo() {
    
    
    var a = 10;
    console.log(a); // 10
}
foo() // 函数调用
console.log(a); // Uncaught ReferenceError: a is not defined

从上面这个例子我们可以看到,函数调用后,函数里面输出10,然而变量a在函数外并没有声明,函数执行后,外面并不能访问到a,那么结果就会报错。因此,我们可以理解为,作用域是为了将变量进行隔离,防止其对全局环境造成污染

ES6 之前,我们说js只有两种作用域,全局作用域函数作用域,而对着 ES6 的到来,为我们提供了另一种作用域,即块级作用域(需通过 letconst 来声明)。

全局作用域

在代码的任何地方都能访问到的变量拥有全局作用域

window 对象的属性具有全局作用域

在这里插入图片描述

console.dir(alert);
console.dir(clearInterval)
fn()

function fn() {
    
    
    console.dir(alert);
    console.dir(clearInterval)

    function foo() {
    
    
        (function () {
    
    
            console.dir(alert);
            console.dir(clearInterval)
        })()
    }
    foo()
}

在这里插入图片描述

定义在全局的变量拥有全局作用域
var a = 0;

function fn() {
    
    
    console.log(a); // 0

    function foo() {
    
    
        (() => {
    
    
            console.log(a); // 0
        })();	// IIFE
    }
    foo() // 函数调用
}
fn() // 函数调用

在这里插入图片描述

上面代码我们可以看出,变量a通过var关键字在代码最外层声明(var关键字在全局下声明的变量会被挂在window上),并且在任何地方都能被访问到,因此变量a具有全局作用域。

未声明直接赋值的变量具有全局作用域
function fn() {
    
    

    function foo() {
    
    
        (function () {
    
    
            b = 100;
        })() // IIFE
        console.log(b); // 100
    }
    foo() // 函数调用
    console.log(b); // 100
}
fn() // 函数调用
console.log(b); // 100

在这里插入图片描述

变量b并没有通过任何关键字声明,在函数里直接被赋值100,函数调用后,变量b被挂在全局对象window上,在全局任何地方都能被访问,因此变量b拥有全局作用域。

函数作用域

只能在函数内部访问的变量拥有函数作用域

function foo() {
    
    
    var a = 1000000;
    (function () {
    
    
    	var b = 999;
        console.log(a); // 1000000
    })()
    // console.log(b); // Uncaught ReferenceError: a is not defined
}
foo()
console.log(a); // Uncaught ReferenceError: a is not defined

比如最开始的例子和上面这个例子,变量a和变量b始终只能在其声明时的函数fn内不进行访问,在函数外就会报错,因此变量ab拥有函数作用域。

块级作用域

块级作用域是 ES6 增加的一种作用域,通过letconst声明的变量会产生块级作用域;

{
    
    
    let a = 5;
    const b = 6;
    var c = 7;
    console.log(a); // 5
    console.log(b); // 6
    console.log(c); // 7
}
// console.log(a); // Uncaught ReferenceError: a is not defined
// console.log(b); // Uncaught ReferenceError: b is not defined
console.log(c); // 7

在这里插入图片描述

在 { } 之中声明的变量,用 let 和 const 声明的变量拥有局部作用域 在 { } 外部不能被访问,而通过var声明的则被挂在了全局对象window上,成为了全局变量可以在任何地方被访问。

举个栗子

for (var a = 0; a < 5; a++) {
    
    
    // console.log(a);
}
console.log(a); // 5
if (true) {
    
    
    var b = 111111;
}
console.log(b); // 111111

在这里插入图片描述

我们可以看到,最终输出 a 是 5,b 是 111111,并且a和b都被挂在了全局对象window上,这显然并不是我们想看到的结果。

因此我们可以改用let关键字来定义这些变量

for (let a = 0; a < 5; a++) {
    
    
    // console.log(a);
}
// console.log(a); // Uncaught ReferenceError: a is not defined
if (true) {
    
    
    let b = 111111;
    const c = 2222;
}
// console.log(b); // Uncaught ReferenceError: b is not defined
console.log(c); // Uncaught ReferenceError: b is not defined

因为使用了letconst关键字,所以这些变量产生了块级作用域,使其在声明时的 {} 外面无法被访问,从而解决一些不必要的麻烦。

猜你喜欢

转载自blog.csdn.net/m0_37825174/article/details/115434355