前言
也没啥好说的,就拉几个关于作用域和作用域链的基础面试题出来遛遛,解答过程有误还望指出。基础知识默认掌握,刚学JS的小伙伴建议先别看,容易弄晕。
有哪些作用域类型
- 全局作用域(
window
下) - 函数作用域(函数里头)
- 块级作用域(
{}
里头),这是es6后才有的。
作用域的访问规则
- 内部的作用域只能往外一层层的访问
- 只要是内部访问到了外部就会产生闭包(和网上说的不一样?)
- 内部作用往外访问时,只看定义的时候,不看执行的时候
补充1:var和let的作用域问题
关于var
var是函数级的作用域,还涉及到了变量提升。
var name = 'hello';
(function(){
if(typeof name ==='undefined'){
var name = 'jack';
console.log("true"+name);
}else{
console.log('false'+name);
}
})()
// 问:控制台打出啥?
// 解答
var name = 'hello';
(function(){
var name // undefined
if(typeof name ==='undefined'){ // true
var name = 'jack'; // var声明的变量是函数级作用域,变量提升到外部
console.log("true"+name);
}else{
console.log('false'+name);
}
})()
var bar = 1;
function test(){
console.log(bar);//undefined 因为变量提升
var bar = 2;
console.log(bar);//现在函数内部找局部变量 2
}
test()
关于let
是块级作用域
function demo(){
let n=2;
if(true){
let n =1;
}
console.log(n); //输出几? 如果改成var就是输出啥
}
demo(); // 2
具体可以看【es6入门】变量声明
补充二:自由变量
通过作用域链获取到的变量可以被叫做自由变量
其实就是遵循上面说的作用域的访问规则的第三条。自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!
自由变量的题一般都喜欢结合闭包来考察。咱们来举例(例子来源于慕课网):
// 函数作为返回值
function create() {
const a = 100
return function () {
console.log(a)
}
}
const fn = create()
const a = 200
fn() // 100
// 函数作为参数被传递
function print(fn) {
const a = 200
fn()
}
const a = 100
function fn() {
console.log(a)
}
print(fn) // 100
作用域链和原型链是俩个东西
虽然都涉及到找东西,但是作用域链是在找一个独立的变量,而原型链更像在找对象上的东西
a = 1形式的作用域与作用域链判断
例题一
function test(){
console.log(bar);//因为作用域链,在局部中没有变量声明,js不知道bar是什么,直接报错
bar = 2 // js执行到这才能认识bar
}
test()
例题二
var f = true;
if(f===true){
var a = 10;
}
function fn(){
var b = 20;
c=30; // 这种没有声明的形式没有变量提升机制,js执行到了才认得
// 注意如果 var b = c =20 ,c也是个全局变量
}
fn();
console.log(a,c) // c是全局变量
console.log(b) // b是var声明的变量,为函数级作用域,所以报错
例题三
function fn() {
var a = 10
window.a = 20
console.log(a)
//因为作用域链,先找本层的变量,再找外部的,虽然window.a是在本层的,但是它是一个全局变量所以是找的是本层的变量a = 10
}
例题四
function fn() {
var a = 10
window.a = 20
a = 30 //作用域链关系,先找局部变量,找到,修改值
console.log(this.a) //而这里打印的是全局变量 20
}
例题五
window.onload = function fn() {
window.a = 20
a = 30 //因为作用域链,先找内部的变量,没有局部变量,有个全局window.a的,那就修改全局的
console.log(a) //局部变量没有,打印全局的 30
}
例题六
function fn() {
window.a = 20
a = 30 //因为作用域链,先找内部的变量,没有局部变量,有个全局window.a的,那就修改全局的
console.log(this.a) //此时this指window 30
}
例题七
function fn() {
window.a = 20
a = 30 // 下面有局部变量的声明,变量提升,所以a=30 改的是局部的
var a
console.log(this.a) //20
}
例题八
var a = 10
function fn(a) {
alert(a)
a = 20 // 此时改的是参数a的值,不是修改全局变量
}
fn(30) //弹出30
alert(a) //弹出10
例题九
var a = 10
function fn() {
alert(a)
a = 20
}
fn() //因为作用域链,函数内找不到变量声明,只能向函数外找,弹出10
alert(a) //此时外部的a变量已经和函数内部关联了(也就是作用域链),所以a的赋值生效,弹出20;
未完待续~