js块语句中的作用域

478 阅读2分钟

作用域指的是声明的变量可以被访问到的范围

看到一道题目,瞬间觉得需要了解一下

// 正常的
if (a) {
    function a() {}
}
// 奇葩的
if (a) {
    a = 1;
    function a() {};
    a = 2;
}

作用域的分类

全局作用域

全局变量的作用域是全局的:网页的所有脚本和函数都能够访问它(参考w3c的定义)

局部作用域

函数在执行的时候,会形成自己的作用域,里面声明的变量,仅在函数内部访问到。

块级作用域

在块语句(或其他语言的复合语句),通过let和cosnt声明的语句,仅仅可以在块级语句中访问到。

块语句

并不是碰到块语句就会形成块级作用域

  • 块语句中通过let, const声明的变量作用域才是当前的语句

  • 块语句中通过var声明的变量不是当前的作用域,而是会变量提升

  • 块语句中function声明的变量在不同的浏览器里可能有不同的效果(但是变量名会被提升)

特殊的function声明(在不同浏览器中处理不同)

块语句中通过function声明的变量,语句执行前的表现

  • safari会在执行前提升到全局为function

  • google在执行前提升变量但是不赋值为undefined,但是在块级语句执行的时候,变量立即变成function

块语句中function声明语句执行时的表现

  • safari 会赋值到全局的变量
  • google 会在声明语句后生成一个同名的块级变量
if(false) {
    function a() {}
}
console.log(a) // google: undefined safari: 'funciton'

总结:

通过前3条可以知道,块语句中用了var,function,这些变量会提升。执行过后,块级语句的外部也可以访问到这些变量

// 正常的一些问题
var globalFunc = 2
console.log(globalScope)
console.log(globalFunc1)
if (true) {
    console.log(globalFunc)
   let blockScope = 'a';
   var globalScope = 'c';
   globalFunc1 = 'e';
   function globalFunc() {}
   function globalFunc1() {}
}

// 在外部访问的情况
blockScope // Uncaught ReferenceError: is not defind
globalScope // 'c'
globalFunc // function...
globalFunc1 // 'e'

现在看一下例外的情况

当然大家都不可能这么写,但是大胆的讨论一下

if (true) {
    a = 1;
    function a() {};
    a = 2;
}

// 就如MDN里面说的不同浏览器不同效果
// google下:window.a为1
// safari下:window.a为2

// google可能是在funciton a() {}语句后,声明了let a,才会出现这个结果
// safari 就是比较中规中矩的表现