时间记录:24.08.30
今天刷面经时无意中看到一题
(function(){
var a = b = 5;
})();
console.log(b);
console.log(a);
虽然题面简单,但是乍一看还是有点懵逼,惭愧惭愧,看来基础还是不扎实啊,遂总结一下。
1. 代码输出过程分析
var a = b = 5;
-
- 先执行
b = 5;
,为隐式的全局变量赋值(因为b
前面没有使用var
、let
或const
来声明)。 - 再声明
a
为局部变量,赋值为b
(即5)
- 先执行
- 函数执行完毕后,
a
变量随之消失(因为它是一个局部变量),b
变量仍存在于全局作用域中,且值为5。 - 执行
console.log(b);
,输出全局变量b
的值,即5。 - 执行
console.log(a);
时,由于a
是一个在函数内部声明的局部变量,在函数外部不可见,因此这会导致一个ReferenceError
,指出a
未定义。
所以,输出结果为:
5
Uncaught ReferenceError: a is not defined
2. 涉及知识点分析
2.1. JS中的运算符执行顺序
在MDN-运算符优先级中有说明,运算符的优先级大于结合性。
2.1.1. 优先级
即不同运算符操作时的先后顺序。
2 ** 3 / 3 ** 2
//相当于:
(2 ** 3) / (3 ** 2)
//结果是0.8888888888888888
2.1.2. 结合性
分为左结合(从左往右)和右结合(从右往左)
- 赋值运算符是右结合的(与今天的题目有关!)
- 除此之外,幂运算符也是右结合的,其他算术运算符都是左结合。
2 ** 3 ** 2
// 相当于:
2 ** (3 ** 2)
//结果是512
- 当有多个具有相同优先级的运算符时,结合性的差异就会发挥作用。
2.2. 立即执行函数(IIFE)
立即执行函数有三种写法:(今天的题目涉及的是第一种!)
( function ( " 参数 " ) { " 函数方法 " ; } ) ( " 给参数传的值 " )
( function ( " 参数 " ) { " 函数方法 " ; } ( " 给参数传的值 " ) )
! function ( " 参数 " ) { " 函数方法 " ; } ( " 给参数传的值 " )
// ! 可以换作 void 或其他运算符(比如 +,-,= 等,都能起到立即执行的作用)
2.2.1. 立即执行函数的特点
- 只运行一次,之后不会再被访问
- 创建了一个块级作用域,避免了变量共享/污染全局作用域。
- 内部可以访问外部,但是外部无法访问内部
2.2.2. 使用时的注意点
(function (a){
console.log(a)
})(1)(function (a){
console.log(a)
}(2));
如图,当我们在使用立即执行函数时,该函数的前一个函数必须要有分号,否则会引起浏览器报错。
(也可以直接在立即执行函数的前面加上分号)
2.3. 作用域
- 全局作用域:声明在全局的变量,在整个程序中都是可用的。
- 局部作用域:声明在函数体内的变量,在整个函数执行环境和其子函数内可用,但是在函数外无法访问。
此处仅作简单描述,具体涉及内部作用域、作用域链等……之后单独总结。