JS中的代码块是什么?

咱们的程序是由一条条语句形成的,语句是依照自上而下的程序一条条执行的。代码块(block)也被称为复合语句(coumpound statement),其作用是通过“{ }”将多条语句组合在一起。

{    // 复合语句    var a = 10;    console.log(a);}

那么为什么要将多条语句组合在一起呢?

因为咱们能够将多条语句“打包”在一起,放在一个JS只期待繁多语句的中央。这句话看上去有些艰涩,然而配合代码了解很容易:

在上面代码中,条件判断语句if (true) 前面,能够只写一条语句,不写{ }也能够失常运行。

if (true) console.log('hello'); // 只写一行语句,程序也能够失常运行// 输入 hello

然而如果咱们想在条件判断后做更多事件,就须要用到{ },在这个JS只期待繁多语句的中央放上更多语句:

if (true) {    console.log('hello');    console.log('world');    console.log('bye'); }

块级作用域是什么?

块级作用域(block scope)指的是大括号中的所有变量和函数只能够在这个大括号蕴含的区域中拜访到,在括号外是拜访不到的。上代码:

{    var a = 10; // var处于全局作用域    let b = 20;    const c = 30; // let和const都处于代码块作用域    console.log(a);     console.log(b);     console.log(c); }console.log(a); console.log(b); console.log(c); 

将下面的代码放到调试工具中,能够看到var和let、const申明的变量属于不同的作用域。当代码在大括号中执行时,程序能够拜访到2个作用域(代码块和全局)中的变量,如下图:

然而当代码执行到大括号之外,就会报错,因为当代码块中的语句执行完后,代码块作用域就会隐没(从栈中弹出),因而只留下一个全局作用域,其中只绑定了一个变量a,无法访问到变量b和c:

因而,该程序最终在控制台的输入后果是:

因为在块级作用域外打印b出错,程序会在此处进行运行,不过可想而知,打印c也会呈现同样的谬误。


遮蔽效应是什么?

不同作用域中雷同名称的变量就会触发遮蔽效应(shadowing)。

var的遮蔽效应

看代码,猜后果:

var a = 100;{    var a = 10;    let b = 20;    const c = 30;    console.log(a);    console.log(b);    console.log(c);}

控制台打印如下:

在大括号中的变量a会使得第1行申明的变量a有效,这就叫遮蔽效应。因为这两处a指向的都是全局作用域中的a。

那么,如果在括号外再打印一下a呢?

var a = 100;{    var a = 10;    let b = 20;    const c = 30;    console.log(a);    console.log(b);    console.log(c);}console.log(a); // 猜后果

让咱们来到调试工具中退出断点:

当程序执行完第1行时,这时全局变量a的值为100:

当程序执行完第3行时,全局变量a的值被二次申明的var a = 10从新赋值为10,这两行语句中的var a指向的都是同一个全局变量a:

因而,控制台打印如下:

let的遮蔽效应

看代码,猜后果:

let b = 100;{    var a = 10;    let b = 20;    const c = 30;    console.log(a);    console.log(b);    console.log(c);}console.log(b);

控制台打印如下:

在大括号中的变量b同样会使第1行申明的变量b有效,造成变量遮蔽。然而与var不同的是,let领有块级作用域,因而最初一行的b打印进去的仍是第1行的申明的b。

让咱们再次进入调试工具中加上断点:

能够分明的看到,程序中共存在3个作用域,1个是全局作用域,剩下2个是块级作用域(代码块和脚本)。只管第1行的let申明处于全局,然而let关键词会本人发明一个块级作用域(图中的脚本),处于内存中独立的空间,贮存了值为100的变量b。在大括号中的变量b,处于内存中另一个独立的空间,贮存了另一个值为20的变量b。

因而,程序第7行的b拜访的是代码块中的变量b,第10行拜访的是脚本(也能够了解成另一个代码块)中的变量b。

const的遮蔽效应

const的遮蔽效应和let统一,将之前的代码稍作批改:

const c = 100;{    var a = 10;    let b = 20;    const c = 30;    console.log(a);    console.log(b);    console.log(c);}console.log(c);

控制台打印如下:

函数中的遮蔽效应

遮蔽效应不仅产生在块级作用域中,也产生在函数中。看代码:

const c = 100;function x () {    const c = 30;    console.log(c);}x();console.log(c);

控制台打印如下:


非法遮蔽是什么?

如果应用var关键字触发遮蔽效应,是齐全可行的,如下:

var a = 100;{    var a = 20;    console.log(a);  // 20}

同理,应用let关键字触发遮蔽效应也是无效的:

let a = 100;{     let a = 20;    console.log(a);  // 20}

然而如果用var去遮蔽let,在程序运行之前就会报错:

let a = 100;{    var a = 20;    console.log(a);  // 语法错误}

那么,如果用let去遮蔽var是否也会报错呢?看代码:

var a = 100;{    let a = 20;    console.log(a); }

控制台打印后果如下:

程序并不会报错。那么为什么用var去遮蔽let就会报错呢?

因为遮蔽效应的准则是:反复申明的语句不能够超出本人所处的作用域。也就是,当咱们应用var在块级作用域中从新申明变量a时,因为var只有全局作用域或者函数作用域,因而块级作用域无奈限度var的申明,这时var a就会超出本人所在的作用域,而let关键字又不容许在同一个作用域中反复申明,因而程序报错。

因而,只须要将下面代码中的块级作用域改成函数作用域,程序就不会报错了:

var a = 100;function x () {    var a = 20;    console.log(a); }x(); // 20console.log(a); // 100

用const触发遮蔽效应和let的状况同理,因而就不赘述了。

const b = 100;{    const b = 20;    console.log(b); // 20}

块级作用域和词法作用域

词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的。

词法作用域的变量查找规定是:如果在以后作用域中找不到该变量,就会去上一层作用域中进行查找,以此类推。块级作用域也享有同样的查找规定:

const a = 20;{    const a = 100;    {        const a = 200;        console.log(a); // 200    }}
const a = 20;{    const a = 100;    {        const a = 200;    }}console.log(a); // 20
const a = 20;{    const a = 100;    {        console.log(a); // 100 往上一级作用域进行查找    }}

以上就是JavaScript中块级作用域和遮蔽效应的常识。