作用域三部曲之一:块级作用域

Posted by Lxxyx on 2016-01-08

三部曲的简介

本篇文章,是介绍JavaScript中作用域部分。
自己这段时间也算是看了很多JavaScript的书,都是和作用域方面有关的。
ES6那是后话,暂时不提。这儿是ES5的情况。
考虑到内容过多。准备分为三部分来讲述。
分别是:块级作用域、IIFE与ES6 let、闭包。

第一篇文章,讲的就是块级作用域的内容。

什么是块级作用域?

在C语言,Java中,都有块级作用域的概念。举个最经典的例子。

1
2
3
4
5
for (int i = 0; i < count; ++i)
{
/* 这是C语言 */
}
printf("%d\n",i ); //出错,读取不到i的值

在循环结束后,变量i就不复存在。这就是块级作用域,变量只能在函数、循环运行是存在。一旦函数或循环运行完毕,变量就会被销毁。

原理

块级作用域的原理,是我看《大话数据结构》这本书中学习到的。
栈是一种LIFO的结构。先进后出。
以刚才的循环为例。
在运行for的时候,压栈,把for循环和对应的变量i压入栈内存。运行结束时便将栈内存弹出。里面的变量i也不复存在了。

为什么要有块级作用域

打个比方,如果一个项目有一百个人在同时开发。每个人都写了好几个循环。
如果没有块级作用域,那么在最后项目合并时候,将会有数不清的变量名冲突。比如说,100个i?
这种块级作用域中定义变量的方式,叫做局部变量。

JavaScript中的块级作用域

在JavaScript中,存在一个全局变量环境。但JavaScript的块级作用域是不完整的。
它可以有局部变量。像这样的。

1
2
3
4
5
6
7
function test() {
var i = 0;
console.log(i)
}

test();// 0
console.log(i);// error,i未被定义

这是局部变量的概念。其实非常好理解。
这个用var定义的变量。只有在函数执行的瞬间才存在,执行完毕就会被销毁。
如果不用var。直接
1
2
3
4
5
6
7
function test() {
i = 0;
console.log(i)
}

test();// i = 0
console.log(i);// i = 0

因为在函数内不用var关键字定义的变量,在函数运行后会成为全局变量。

而JavaScript没有块级作用域所暴露的问题,在循环就有体现。
假如在JavaScript运行一个for循环

1
2
3
4
for (var i = 0; i < 10; i++) {
//一些操作
}
console.log(i) // i = 10

你会发现i还会存在。此时的i,是在全局变量环境中的。
这是极其恐怖的事情,因为在当代的前端开发中,大型项目往往有很多人一起开发。但是全局变量环境只有一个。
那么也就是说,如果这样的话,项目中变量的冲突会极其严重。

那怎么解决?

这就是下一章要讲述的内容啦,会讲述JavaScript如何模仿块级作用域,同时也会讲述ES6原生实现的块级作用域。