关于Javascript作用域的那些事儿前言 作用域是指在程序中定义变量的可访问性和可见范围。在编程语言中,作用域定义了
前言
作用域是指在程序中定义变量的可访问性和可见范围。在编程语言中,作用域定义了变量的生命周期及其在代码中可访问的范围。不同的作用域规定了不同变量的可见性和访问权限,有助于避免变量冲突和提高代码的可维护性。作用域分为全局作用域,函数作用域,块级作用域。注:内层作用域可访问外层作用域,反之则不行。
正文
先聊聊浏览器是怎么读懂你的代码的
例如
var a = 2
-
Js引擎会对代码进行词法分析,分析出代码含有哪些词法单元。
词法单元:var, , a, =, 2 注:var后的空格也是一个词法单元,等号两边的空格无意义只是为了格式好看点。
-
再将将词法单元转换成一个逐级嵌套的程序语法结构 --- 抽象语法树。
-
最后生成代码。
全局作用域
代码演示
var a = 1;
对于上述的代码进行的步骤:
- 词法分析:词法单元:var,a,=,2
- 解析:将词法单元=转换成一个 逐级嵌套 的程序语法结构树 --- 抽象语法树
- 生成代码:var a = 2
有效标识符
在编程语言中用来命名变量、函数、类等的符号
function foo(a) {
var b = 2
console.log(a + b)
}
a, b 是foo的有效标识符
综合代码
var b;
function foo(a) {
function bar(a){
return a - 1;
};
b = a + bar(a * 2);
console.log(b * 3);
};
foo(2);
- 全局作用域的有效标识符:b,foo(2)
- foo函数作用域的有效标识符:a,bar()
- bar函数作用域的有效标识符:a
分析:当执行b = a + bar(a * 2);时,该bar函数作用域没有a,那么这个时候内层作用域是可以访问外层作用域的,就去foo函数作用域,查找到a=2,此时就可以执行,则b=5。
块级作用域
代码演示
if (true) {
let a = 1;
}
console.log(a);
分析:报错是因为{let/const}
这种形式会形成块级作用域,并且外层不能访问内层,所以报错。
小知识
自执行函数 (立即执行函数)
(function() {
var a = 3;
console.log(a);
})();
声明提升
console.log(a);
var a = 1;//声明提升
分析:此时没有报错,因为var具有声明提升,上面的代码相当于:
var a;
console.log(a);
var a = 1;
注意:如果将上述的代码中的var改为let,将报错,因为var可以重复声明变量,let不可以。
let a;
console.log(a);
let a = 1;
let VS var
- var存在声明提升,let不存在
- 在全局,通过var声明的变量相当于是在window对象上添加了一个属性
- let会和{}形成块级作用域
- var可以重复声明变量,let不可以
const:定义的为常量,不可改值
const a = 1; // 常量
a = 2;
console.log(a);
欺骗词法作用域
- eval():将原本不属于这里的代码变成就像天生就定义在这里一样
function foo(str ,a) {
eval(str);//var b = 3
console.log(a ,b);
};
var b = 2;
foo('var b = 3', 1);
- with():用于修改一个对象中的属性值,但如果修改的属性在原对象中不存在,那么该属性就会被泄露到全局
var obj = {
a:1,
b:2,
c:3
};
with (obj) {
a = 3,
b = 4,
c = 5
}
console.log(obj);
function foo(obj) {
with(obj){
a = 2;
}
};
var o2 = {
b: 3
};
foo(o2);
console.log(o2);
console.log(a);
转载自:https://juejin.cn/post/7416382505702391827