javascript作用域之块级作用域

栏目: JavaScript · 发布时间: 5年前

内容简介:昨天对函数作用域进行了简单介绍目录看一个栗子

昨天对函数作用域进行了简单介绍

简单回顾

目录

看一个栗子

let d = 4;

(function(c) {
  let a = 1,
    b = 2
  foo2()

  function foo2() {
    let a = 11
    foo3()

    function foo3() {
      console.log(`a:${a}`); //=>11
      console.log(`b:${b}`); //=>2
      console.log(`c:${c}`); //=>3
      console.log(`d:${d}`); //=>4
      console.log(`e:${e}`); //Uncaught ReferenceError: e is not defined
    }
  }
})(3)

上面函数就是下面的简写形式

let d = 4;

function foo1(c) {
    //相同部分省略
}
foo1(3)

当然也可以这么写

let d = 4;
  (function (c) {
    let a = 1,
      b = 2;
    (function () {
      let a = 11;
      (function () {
        console.log(`a:${a}`); //=>11
        console.log(`b:${b}`); //=>2
        console.log(`c:${c}`); //=>3
        console.log(`d:${d}`); //=>4
        console.log(`e:${e}`); //Uncaught ReferenceError: e is not defined
      })()
    })()
  })(3)

理论上是可行的,但代码可读性太差

函数创建后立即执行,并传入一个参数=>3

javascript作用域之块级作用域

变量的查找是从内向外逐层查找,如果到最外层依然找不到就会抛一个not defined的错

这样就形成了一个作用域链,内层同名变量会覆盖外层的,(有没有想到原型链?)

块级作用域

先普及一个概念:

ECMAScript和JavaScript关系:

ECMAScript是一个国际通过的标准化脚本语言。可以简单理解为:ECMAScript是JavaScript的语言规范,JavaScript是ECMAScript的实现和扩展。

什么是块级作用域?

任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。

在es6标准出来之前,javascript是不存在块级作用域的

一个栗子

{
  var name = "郭靖";
  console.log(name);//=>郭靖
}
console.log(name);//=>郭靖

再看一个不那么hello world的栗子

function foo() {
  var hisName = "郭靖"
  for (var i = 0; i < 10; i++) {
    // 啥也不干
  }
  console.log(i);//=>10
  console.log(hisName);//=>"郭靖"
}
foo();
//console.log(i);//=>Uncaught ReferenceError: i is not defined
console.log(hisName); //=>Uncaught ReferenceError: hisName is not defined

通过上面的栗子我们可以发现

在foo内部,在for循环外部,成功的打印出i,这说明使用var声明的变量是不存在块级作用域的

在foo外部,我们打印i或者hisName,都会报Uncaught ReferenceError的错误,i和hisName是foo内部的私有变量,这说明使用var声明的变量存在函数作用域

我们上面介绍了js块级作用域的概念,两个花括号内部定义的内容,外部无法访问的,而javascript又存在函数作用域,

好了,我们可以通过javascript的函数作用域来模拟实现块级作用域

还是上面的栗子

function foo() {
  (function () {
    var hisName = "郭靖"
    for (var i = 0; i < 10; i++) {
      // 啥也不干
    }
  })()
  console.log(i);//Uncaught ReferenceError: i is not defined
  console.log(hisName);//上面报错,这里就不会执行,这里就算执行,也会报错
}
foo();
// console.log(i);//=>Uncaught ReferenceError: i is not defined
// console.log(hisName); //=>Uncaught ReferenceError: hisName is not defined

这不正是我们昨天讨论的内容吗?立即执行函数,函数执行后,内部变量会被销毁(闭包情况暂不考虑,后面的文章会详细介绍),所以外部就无法访问啦

所以又说到昨天的内容了,为了防止命名冲突我们一般这么写

(function () {
  var herName = "黄蓉"
})()
console.log(herName);//Uncaught ReferenceError: herName is not defined

一个简易块级作用域诞生了

ES6中块级作用域

我们现在写代码,如果项目允许使用ES6,那就很少会有人通过函数作用域来实现块级作用域了,因为ES6支持块级作用域

let

说起let,就会情不自禁的将let和var进行比较,

关于let和var的介绍的文章多如牛毛,不再赘述

说几个明显的区别

var变量声明提升

看几个栗子,有助于理解

hisName = "郭靖"
var hisName
console.log(hisName);

undefined?

最后输出“郭靖”

上面的代码经过js引擎编译处理,变成了这样

var hisName
hisName = "郭靖"
console.log(hisName);

继续看栗子

console.log(hisName);
var hisName = "郭靖"

最后输出“undefined”

上面的代码经过js引擎编译处理,变成了这样

var hisName
console.log(hisName);
hisName = "郭靖"

javascript代码并不是一行一行往下执行的,分为2个步骤:

  • 编译(词法解释/预解释)
  • 执行

理解了没?如果理解了,继续看一个栗子

var hisName = "郭靖";

function hero() {
    console.log(hisName);
    var hisName = "洪七公";
}
hero();
console.log(hisName);

先不关心输出什么,我排一下顺序

var hisName = "郭靖";

function hero() {
  var hisName
  console.log(hisName);
  hisName = "洪七公";
}
hero();
console.log(hisName);

如果顺序排队了,基本就没什么问题

执行hero函数,打印hisName,声明了,但是没有复制,所以是undefined

到这里,你可能会有一个疑问,js存作用域链,hero内部的hisName是undefined,它不会继续像外层作用域继续查找吗?

当然不会啦,只要声明过,如果没赋值,就存在一个默认值=>undefined

hero()后面的console.log(hisName);//=>郭靖,为什么?

因为函数作用域的作用,hero内部的变量,外部无法访问(暂不考虑闭包),变量首先查找的是同级作用域,同级作用域不存在就会继续向外层查找,但不会向内层查找

通过这三个栗子,我相信,你已经搞懂了javascript的变量提升

let块级作用域

前面说在ES6标准出来之前,是不存在块级作用域的,需要函数作用域进行配合模拟实现块级作用域

let 存在块级作用域,let 不存在变量提升(必须先声明,声明前不能进行赋值等相关操作)

{
  hisName = "郭靖";//在这里级报错了Uncaught ReferenceError: hisName is not defined
  let hisName
  console.log(hisName);
}

再来一个栗子

let hisName = "黄药师";
let herName = "黄蓉"; {
  let hisName = "洪七公"; {
    let hisName = "郭靖";
    console.log(hisName);//=>郭靖
    console.log(herName);//=>黄蓉
  }
  console.log(hisName);//=>洪七公
}
console.log(hisName);//=>黄药师

输出也没什么悬念

//=>郭靖
//=>黄蓉
//=>洪七公
//=>黄药师

let 暂时性死区

暂时性死区,听起来好迷糊,其实没什么,

因为let不存变量提升,使用let命令声明变量之前,该变量都是不可用的

其实还是关于变量提升的问题

const?

关于const在块级作用域上,和let保持一致,不在此赘述

END


以上所述就是小编给大家介绍的《javascript作用域之块级作用域》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Transcending CSS

Transcending CSS

Andy Clarke、Molly E. Holzschlag / New Riders / November 15, 2006 / $49.99

As the Web evolves to incorporate new standards and the latest browsers offer new possibilities for creative design, the art of creating Web sites is also changing. Few Web designers are experienced p......一起来看看 《Transcending CSS》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具