JavaScript那些事--✪--作用域

作用域

1 定义:

作用域日常有很多叫法比如

  • this绑定的值
  • this绑定值定义的执行上下文
  • 一个变量的“生命周期”、
  • 变量的值解析方案或词法绑定

作用域通俗的讲就是一个变量多长时间内保持一定的值。

2 分类:

作用域从范围上划分可以分成全局作用域局部作用域(常见的是函数内部,也叫函数作用域)。

作用域按照工作模式分词法作用域(静态作用域)动态作用域。

2.1 全局作用域

1.在全局声明的变量生命周期将跨越整个程序(尽力少些,并且不好维护)。

2.在JS中没有用var 关键字声明的变量都是全局变量,能被程序中任何函数或方法访问。

    aVariable = '我是全局变量'

    function aTest() {
        console.log(aVariable)
    }
    aTest() // 我是全局变量

就是因为任何一段代码可以随便改变它们,会引起之后一些的麻烦,相当的危险。

2.2 词法作用域

先说说词法,词法的中文意思是特定文本内语词的构成和使用的法则。

在大部分编译器也有这类似步骤,对源代码进行字符检查,如果是有状态的解析过程,就会赋予单词语义。

词法作用域是指一个变量的可见性,及其文本表述的模拟值。(大概先记着有个印象)

上个代码:

    aVar = 'One'

    function aFun() {
        let aVar = 'Two'
        return [1, 2, 3].map(function (item) {
            var aVar = 'three'
            console.log([aVar, item].join(''))
        })
    }
    aFun() //three1  three2   three3

分析

换句话说,词法作用域是由你写代码时将变量或块作用域写在哪里所决定的。

2.3 动态作用域

在编程中最容易被低估或过度滥用的概念就是动态作用域。

aVariable = '我是全局变量'
    function aTest() {
        var aVariable = "我是TEST作用域的变量"

        function childFun() {
            var childVar = "我是child的变量"
            console.log(aVariable, childVar)
        }
        childFun()
    }
    aTest() // 我是TEST作用域的变量 我是child的变量

 

 

 

 

但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到第一个值,最如果一直没有会一层层直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链

 

 aVariable = '我是全局变量'

    function aTest() {
        var aVariable = "我是TEST作用域的变量"
        childFun()
    }

    function childFun() {
        var childVar = "我是child的变量"
        console.log(aVariable, childVar)
    }
    aTest() // 我是全局变量 我是child的变量

 

动态作用域的核心是维护一个命名绑定栈的全局映射。

缺点:任何给定的绑定的值,在确定调用其函数之前,都是不可知的

(JS中this引用是动态作用域,尤其是事件处理函数中,如果点击按钮得到的this没用,会破坏程序的正常运行,是危险的)

 

2.4 函数作用域

 

在任意代码片段外部添加包装函数,可以将内部的变量和函数定义“隐藏”起来,外部作用域无法访问包装函数内部的任何内容。

function testFun(n) {
    for(var i=0;i<n;i++);
    console.log(i)
}
testFun(100) // 100

搜索在JS中所有在函数体内的var声明都会隐式地移到函数的顶部,JS重新排列变量声明的动作成为吊装(hoisting)

上面的代码实际重新排列就成这样了

    function testFun(n) {
        var i;
        for (i = 0; i < n; i++);
        console.log(i)
    }
    testFun(100) // 100

举个例子:

    i = 100
    function testFun(n) {
        console.log(i)
        var i = 111;
    }
    testFun()
    console.log(i)

原因分析:

    i = 100 // 定义全局的 i

    function testFun(n) {
        var i; // JS吊装排列
        console.log(i) // 此时还没有定义说undefined
        i = 111; // 定义当前作用域的 i
    }
    testFun()
    
    console.log(i) // 打印全局变量i

 

【ES6的let填坑了,会直接报错 Uncaught ReferenceError: Cannot access 'i' before initialization(初始化之前不能访问')

Hositing的概念真的理解了么,再来个测试~~~ do it~

 

    i = 100 

    function testFun(n) {
        console.log(i) 
        i = 111; 
    }
    testFun()

    console.log(i) 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章