作用域

我所理解的作用域,就像一个套一个的盒子;你在哪个盒子里,要么伸手拿自己盒子里的东西,要么从包裹你的盒子里拿东西;要想到你下面的盒子里去拿东西,是不被允许的。

// 首先,定义自己的log函数
const log = function() {
        console.log.apply(console, arguments)
}

作用域,也称为运行环境。对于JS,运行在web浏览器上时,浏览器为其提供一个运行环境;而NodeJS也是为JS代码的执行提供了一个运行环境。

作用域有大小之分,大的称为全局作用域,小的称为局部作用域,再小的称为块级作用域;相对应的作用域中的变量,则称为全局变量局部变量;暂时没听到块级变量这么一说。

作用域的大小之分,并不是为了比较谁大谁小;其不是相互独立的,可以理解成包含被包含关系。局部作用域块级作用域一定是包含在全局作用域之内;局部作用域之间可能有包含被包含的关系,也可能是彼此独立的;而块级作用域局部作用域类似。

全局作用域 -- 全局变量

一个变量因其所在作用域的不同,能够被访问的限制也是不同的;在局部作用域中,只能访问自己作用域内定义的变量,以及向上访问包含自己的父级作用域,或者延长的作用域。在全局作用域内定义一个全局变量,在整个环境中都可以访问的到,无论是是局部作用域中,还是在块级作用域中。比如:

// 例子1

// 定义全局变量i
var i = 0
// 在 局部作用域 中访问全局变量
const showme = function() {
    log(i)
}
showme()                // 0

// 在 块级作用域 中访问全局变量
for(; i < 2; i++) {
    log(i)              // 0 1
}

JS语句执行时,会先在当前自己的作用域中搜索变量,如上例中的i;当在当前作用域中找不到的时候,会向上层去查找。在这里就是直接到全局作用域中找到了变量i

局部作用域 -- 局部变量

全局变量之下的变量,有局部和块级两个,不分上下级,只因声明的区域不同。局部变量一般是声明在函数内部,如上例中的showme函数。一个函数的定义,就定义了一个局部作用域,其内声明的变量则只在这个作用域、及其下层作用域可以被访问的到。

// 例子2

// color为全局变量,在函数内部也可以访问
var color = 'blue'

var changeColor = function() {
    // 注意:当变量不用var声明时,是一个全局变量,尽量不要这样使用

    // anothorColor为changeColor函数内部变量,不能被外部所访问
    var anothorColor = 'red'

    var swapColor = function() {
        // tempColor与anothorColor类似,是swapColor函数内部变量,不能被外层访问到
        var tempColor = anothorColor
        // 当访问anothorColor时,会先从本函数内部寻找,找不到,会到上层changeColor()寻找
        anothorColor = color
        // 当访问color时,在本层寻找不到,会逐级向上直到全局作用域
        color = tempColor
    }
    return swapColor
}

// 由于anothorColor tempColor属于局部作用域中的局部变量,在全局环境中无法访问
log(anothorColor)           // Uncaught ReferenceError: anothorColor is not defined
log(tempColor)              // Uncaught ReferenceError: tempColor is not defined

// 调用changeColor()函数,获得swapColor()函数的引用
var swapColor = changeColor()
// 调用swapColor函数
swapColor()                              // "red"
// 上面两条语句合并为一条: changeColor()()

如上代码,一个全局变量color,其后由changColor函数定义了一个局部作用域A;而在changColor的局部作用域A之内,又由swapColor函数定义了一个层级更低的局部作用域B。在局部作用域中可以看到,变量的访问是一层一层逐级往上层查找的;找到了就结束查询;一直到全局作用于中都没有找到,则报错。

块级作用域 -- 块级变量

其实没有块级变量,是我自己喊的,方便称呼块级作用域中声明的变量。块级变量也是一个局部变量,但其不是在函数定义的局部作用域中;而是存在于由大括号{}(或for()圆括号)包裹的块级作用域中。块级作用域可以看作比局部变量更小的作用域;其访问的限制也是一样的,只可向上访问,不能向下访问。如例子1中的变量i
既然一样,为什么还要有个块级作用域呢?块级作用域的存在确实方便了我们的代码编写,也帮我们避免了一些不小心的错误。如下:

// 例子3    ES6新增块级作用域,使用let声明变量

// 以前
if(2 == '2') {
    var i = 10
}
log(i)                  //10

// ES6
if(2 == '2') {
    let j = 10
}
log(j)                  // Uncaught ReferenceError: j is not defined

// 尤其for循环
for(var j = 0; j < 2; j++) {
    log(j)              // 0 1
}
log(j)                  // 2

// ES6
for (let k = 0; k < 2; k++) {
    log(k)              // 0 1
}
log(k)                  // VM473:4 Uncaught ReferenceError: k is not defined

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容