JavaScript作用域

迷南。 2022-03-27 02:39 416阅读 0赞

ES5中的作用域

一、全局变量

全局变量有 全局作用域: 网页中所有脚本和函数均可使用
如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量

1.最外层函数和在最外层函数外面定义的变量为全局变量,拥有全局作用域:

  1. var boyName = "刘家军"
  2. function person(){
  3. var girlName = "袁姮"
  4. function doSth(){
  5. console.log(girlName)
  6. }
  7. doSth()
  8. }
  9. console.log(boyName) // 刘家军
  10. console.log(girlName) // 报错: girlName is not defined
  11. person() // 袁姮
  12. doSth() // 报错:doSth is not defined

2.所有末定义直接赋值的变量为全局变量,拥有全局作用域:

  1. function doSth(){
  2. var boyName = "刘家军"
  3. girlName = "袁姮"
  4. console.log(boyName )
  5. }
  6. doSth() // 刘家军
  7. console.log(girlName) // 袁姮
  8. console.log(boyName) // 报错:boyName is not defined

3.所有window对象的属性拥有全局作用域

二、局部变量

变量在函数内声明,变量为局部变量,拥有局部作用域,因为只能在函数内部访问,也称作函数作用域

  1. function person(){
  2. var boyName = "刘家军"
  3. function doSth(){
  4. console.log(boyName)
  5. }
  6. doSth()
  7. }
  8. console.log(boyName) // 报错:boyName is not defined
  9. doSth() // 报错:doSth is not defined

三、变量提升

在ES6之前,JS没有块级作用域,只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。看代码:

  1. console.log(boyName) // undefined
  2. var boyName = "刘家军"
  3. console.log(boyName) // 刘家军
  4. function person() {
  5.   console.log(girlName) // undefined
  6.   var girlName = "袁姮"
  7.   console.log(girlName ) // 袁姮
  8. }
  9. person();

之所以会是以上的打印结果,是由于js的变量提升,实际上上面的代码是按照以下来执行的:

  1. var boyName // 变量提升,全局作用域范围内,此时只是声明,并没有赋值
  2. console.log(boyName) // undefined
  3. boyName = "刘家军" // 此时才赋值
  4. console.log(boyName) // 打印出刘家军
  5. function person () {
  6.   var girlName // 变量提升,函数作用域范围内
  7.   console.log(girlName)
  8.   girlName = "袁姮"
  9.   console.log(girlName )
  10. }
  11. person()

ES6中的块级作用域

‘块级作用域’(一对花括号{}即为一个块级作用域)通过新增命令let和const来体现,

let

let和var差不多,都是用来声明变量的。区别就在于:

 1、 let声明的变量只在所处于的块级有效
 2、 let没有‘变量提升’的特性,而是‘暂时性死区’特性

1.let声明的变量只在块级有效

  1. function person(){
  2. if(true){
  3. let boyName = "刘家军"
  4. console.log('in:' + boyName ) // 刘家军
  5. }
  6. console.log('out: ' + boyName ) // 报错:boyName is not defined
  7. }

在if外打印boyName ,报错:boyName is not defined
这因为let声明的变量boyName 是属于if内的块级作用域;而不是像var一样

2.let没有‘变量提升’的特性,而却有‘暂时性死区’的特性

  1. var boyName = "刘家军"
  2. function person(){
  3. console.log(boyName) // 报错:boyName is not defined
  4. let boyName = "刘家军测试";
  5. };
  6. person()

boyName报错了,说明变量提升了,只是let规定了不能在其声明之前使用而已。我们称这特性叫“暂时性死区”。这一特性,仅对遵循‘块级作用域’的命令有效(let、const)

3.可以解决闭包问题

  1. var arr = [];
  2. for(var i = 0; i < 2; i++){
  3. arr[i] = function(){
  4. console.log(i);
  5. }
  6. }
  7. arr[1]() // 2
  8. var arr = [];
  9. for(let i = 0; i < 2; i++){
  10. arr[i] = function(){
  11. console.log(i);
  12. };
  13. };
  14. arr[1]() // 1

关于闭包 我们明天再仔细讲一讲

const

const命令与let命令一样,声明的变量,其作用域都是块级。
所以const遵循的规则与let相差无二,只是,const是用来声明恒定变量的。
且,用const声明恒定变量,声明的同时就必须赋值,否则会报错。

  1. function test(){
  2. const num//报错,声明就得赋值
  3. num = 666
  4. console.log(num)
  5. }

作用域链的组成

在JS中,函数的可以允许嵌套的。即,在一个函数的内部声明另一个函数

  1. function person(){
  2. var boyName = "刘家军";
  3. function getName(){ // 在person函数内部,声明了函数getName,这就是所谓的函数嵌套。
  4. var girlName = "袁姮";
  5. }
  6. }

对于person来说,person函数在执行的时候,会创建其person函数的作用域, 那么函数getName在创建的时候,会引用person的作用域,如图:
在这里插入图片描述
函数getName在执行的时候,其作用域类似于下面:
在这里插入图片描述
从上面的两幅图中可以看出,函数getName在执行的时候,是会引用函数person的作用域的。所以,像这种函数作用域的嵌套就组成了所谓的函数作用域链。当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。

友情链接: 点击查看所有文章目录

友情链接:点击查看 JavaScript作用域、闭包、this指向系列文章目录

发表评论

表情:
评论列表 (有 0 条评论,416人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JavaScript作用

    ES5中的作用域 一、全局变量 > 全局变量有 全局作用域: 网页中所有脚本和函数均可使用 > 如果变量在函数内没有声明(没有使用 var 关键字),该变量为全