js作用域:小白探索之旅
2025-05-19 09:10 阅读(46)

昨天我写了一个函数,内部定义的变量在外部怎么也访问不到!就像是变魔术一样消失了,原来是‘作用域’在搞鬼。

1.  变量是什么

在 JavaScript 中,变量是用于存储数据的容器。我们可以使用 var、let 和 const 关键字来声明变量。

2 .js代码的执行过程



词法分析--> 拆解代码为'词语'

-例let age = 18 --> [let, age, =, 18]



语法分析--> 构建抽象语法树

-检查语法错误,构建代码结构



生成可执行代码--> 转化为机器指令



3.作用域是什么

在JavaScript中,作用域是指变量和函数的可访问性,即在代码中可以访问这些变量和函数的部分。

JavaScript主要有两种作用域类型:全局作用域和局部作用域。但是在es6版本之后,又引入了块级作用域。


全局作用域--> 程序的顶层空间

函数作用域--> 函数内部的独立王国

块级作用域--> 包裹着的领土


访问规则:全局作用域 <-- 函数作用域 <-- 块级作用域

内层作用域可以访问外层作用域,外层不能访问内层

根据上诉的规则我们来举几个例子

 var a = 1
 function foo(){
   console.log(a)
 }
 foo()


运行结果:1


在函数作用域中找不到变量a, 于是访问外层作用域,也就是全局作用域,找到了变量a, 并且值为1 ,于是打印a的值。


那大家想一想,下面这段代码是否会报错

 console.log(a)
 var a = 1


运行结果:undefiend

哎呀!不对呀!其实输出结果就是undefined。其实这就得牵扯到 var let const三者的区别

4. 变量声明进阶对比

1.var 声明的变量会存在声明提升(将变量的声明提升到当前作用域的顶部)

就是这个例子,用 var 声明的变量会声明提升,所以当执行输出时,全局有变量a, 但是此时还未赋值,所以打印结果为undefiend。

console.log(a)
 var a = 1


其实这份代码就等同于:


var a
console.log(a)
a = 1


运行结果:undefiend


let和const声明的变量不会声明提升

console.log(a)
let a =1


运行结果:报错


2. var可以重复声明变量

var a = 1
function(){
    var a = 2
    console.log(a)
}


运行结果:2


因为a在函数作用域已经找到了, 所以的值为2。甚至在js里面可以不进行声明,直接写a = 1都是可以的,js会默认给你声明成var。


let 和const不可以重复声明变量,否则报错


var a = 1
let a = 2 


运行结果:


3. let 和const 的区别

let和const的区别就在于其定义的变量的可变性:const定义的变量是不可变的,而let可以.


5.块级作用域

直接拿例子说话:


{
let a = 1
}
console.log(a)


运行结果:a is not defiend


其实就是let 与 {} 就形成了一个块级作用域,你要打印a, 即使全局没有声明,也不能从外往内找,相当于a 没有声明。换成一个简单的函数作用域作为参考:

function foo()
{
    var a = 1;
}
console.log(a);


运行结果:a is not defiend


6.欺骗词法

aval()案例:

function foo(str, a) {
    eval(str); //var b = 3;
  console.log(a, b);
}

foo('var b = 3',1);


大家对eval()这个函数肯定非常陌生,其实这行代码就是把 var b =3 这行代码从全局作用域搬到了函数作用域当中,起到了一个欺骗作用。


with(obj){}案例:


var obj = {
    a: 1,    
    b: 2,
    c: 3,
}
 with(obj){
     a =2
     b =3
     c =4
 }
 console.log(obj)


运行结果:


这个函数作用是批量修改对象的键值对,但是我们发现,要是with(){}出现了对象中没有的属性呢?那么with修改其属性会导致其泄露到全局,但是不会增加在此对象中。


var o2 = {
    b: 2,
}

// var a = 2
function foo(obj) {
    with(obj){
        a = 2; //在全局声明了
    }
}
foo(o2);
console.log(o1);
console.log(o2);
console.log(a);


运行结果:


结语

最后的魔法咒语:

"不是变量在消失,而是作用域在生效;

不是引擎太玄妙,而是规则未参透。

从var的迷雾走向let的清明,

便是从小白到法师的飞升之路!"


https://www.zuocode.com