面试10家公司,得有8家会问到作用域的题。所以说JS的作用域一定要弄清楚,非常重要!
1、除了函数之外,JS没有块级作用域
2、作用域链:内部可以访问外部的变量,但是外部不能访问内部变量,如果内部有,优先内部的,如果内部没有,就先查找外部的
3、注意声明变量是用var,还是没有写,如果没写var,直接赋值,就是(window.下面的全局)
4、变量提升
5、优先级:声明变量 > 普通声明函数 > 参数 > 变量提升
普通声明函数,不看写函数的时候的顺序,反正都是要变量提升的,而且取值就是函数本身,这就相当于是,函数不仅声明提升了,定义也提升了
题目:除了函数之外,JS没有块级作用域
结果为:报错
分析:
因为a在函数内部,函数有块级作用域
但是在函数外部,a不仅没声明也没定义
注意:如果没声明没定义就报错,如果声明了,没定义,就是undefined
结果为:10
分析:
因为JS除了函数以外没有块级作用域
for循环没有块级作用域 i做完循环=10
所以最后打印出来为10
结果为: 10
分析:
因为JS除了函数以外没有块级作用域
a = 10
考点:作用域链 – 内部可以访问外部的变量,但是外部不能访问内部变量
结果为:10
分析:
foo内部没有a
根据作用域链,一层一层往外找
考点:使用了var,就是声明了变量,没使用var的,就是没声明变量
结果:
·a不能打印,会报错,因为a在函数内部声明,具有块级作用域,函数外部没有定义
·b可以打印,结果为10,因为b没有使用var在函数内部声明,b相当于是全局变量windows.b=10相当于是在函数外面声明赋值的
结果为:
undefined
undefined分析:
js除了函数,没有块级作用域,所以if不是块级作用域
var a变量提升 所以第一个a是undefined
由于if语句里面是false,所以并没有赋值 第二个a也是undefined
考点:变量提升
结果:
函数内部的bar变量提升却没有赋值,所以第一个是undefined
第二个赋值了,就是2
优先级:
结果:10
分析:
声明变量 > 普通声明函数
结果:f(){}
函数表达式声明,就是a的变量声明
结果:f(){}
分析:
虽然函数定义在下方,但是打印出来的不是undefined
因为,普通函数声明 取 函数值,不取声明值
这意味着:在普通声明函数上方调用,或者在普通声明函数下方调用,这个顺序是没影响的
考点:声明变量 > 普通声明函数 > 参数 > 变量提升
结果:100
分析: 参数 > 变量提升
声明变量 > 普通声明函数 > 参数 > 变量提升
结果为:10
分析:声明变量 > 普通声明函数 > 参数 > 变量提升
注意:这里的a是windows下的,其实a不在函数块级作用域内,它其实是windows.a,在函数外部找到的
结果为:20
分析:a其实是windows下的,但是本作用域中有var a = 20,所以最后是20
结果为:10
分析:这是上面题反过来,这是变量的再赋值了,所以是10
这个也是变量的再次赋值
结果:10
分析:
首先是var a变量提升
然后,a = 10,变量的赋值
2、普通函数声明、函数表达式、箭头函数有什么区别?
在 JavaScript 中,普通函数声明、函数表达式、和箭头函数在语法和行为上有一些区别。下面是主要的区别:
1. 普通函数声明(Function Declaration)
普通函数声明在其作用域内会被提升(hoisted)。
foo(); // 可以调用,因为函数提升
function foo() {
console.log('普通函数声明');
}
- 拥有自己的
this
、arguments
、super
和new.target
。 - 可以使用
new
运算符调用(即作为构造函数)。 - 可以被提升。
2. 函数表达式(Function Expression)
函数表达式定义了一个匿名函数,或者可以命名,但是不会被提升。
foo(); // TypeError: foo is not a function
var foo = function() {
console.log('函数表达式');
}
- 与普通函数声明相似,拥有自己的
this
、arguments
、super
和new.target
。 - 可以使用
new
运算符调用(即作为构造函数)。 - 不会被提升。
3. 箭头函数(Arrow Function)
箭头函数使用 “箭头” (=>
) 语法编写。
const foo = () => {
console.log('箭头函数');
}
- 没有自己的
this
,this
的值继承自包围它的函数(词法this
)。这使得箭头函数在某些场景中更为方便,比如在回调函数中。 - 没有
arguments
对象。如果你需要访问参数列表,你需要使用剩余参数(...args
)。 - 不能使用
new
运算符调用。箭头函数没有[[Construct]]
方法,因此不能作为构造函数。 - 没有
super
和new.target
。
总结:
- 普通函数声明可以被提升,而函数表达式和箭头函数不能。
- 箭头函数不绑定自己的
this
,并且缺少普通函数和函数表达式的一些特性,如arguments
对象。 - 普通函数声明和函数表达式在功能上相似,但函数表达式不会被提升。