发表于: 2021-11-29 23:15:28

0 793


今天完成的事情:

看了JS知识点
明天计划的事情:

继续看知识点
遇到的问题:

慢慢收集问题
收获:

如何理解JS作用域与作用域链?

(1)背景介绍:

 当js代码运行在中的时候,浏览器会为其提供为JS代码提供执行的环境,这个环境叫作用域也叫栈内存。离开了作用域代码就是一堆字符串,没有什么作用。因为没有作用域代码就不能正常执行,所以作用域也可以理解为变量与函数的可访问范围。

(2)知识剖析:

作用域分为全局作用域,私有作用域和块级作用域。

作用范围在整个页面的作用域叫做全局作用域,前端用window表示。在全局作用域下声明的变量任何地方都可以使用,全局作用域的生命周期跟页面一样长,只有页面销毁全局作用域才销毁。

函数执行时所形成的作用域叫做私有作用域,私有作用域里面的变量外面不能调用,全局作用域与私有作用域的区别就是,全局作用域是公共公园,里面的东西都是公共设施谁都可以玩,私有作用域是私人庭院,里面的设施外人是不能随便碰的。

块级作用域是ES6的概念,也相当于一个私有作用域,但是以大括号作为作用域的范围 在ES6语法中,一般用大括号包起来的都是块级作用域,if大括号是块级作用域,for循环体也是块级作用域,初始值设置的变量是当前本次块级作用域中的变量。

对象不是块级作用域,就是一个值。

(3)常见问题:

私有变量没有用关键字声明影响全局变量。

在一个私有作用域中,如果不带关键字声明就不是私有变量,这时他会向他的上级作用域查找,看是否为上级的变量,如果不是继续向上级查找,一直找到全部局变量位置,我们管这种查找机制叫做作用域链。

(4)解决方案:

给私有变量用关键字声明即可。

(5)编码实战:

var b =12

function op (){

   let b =13

}

op()

console.log(b)

op里的b因为在私有作用域里,所以外面调用不了,这里的console.log还是12

let a =12;

function q(){

    function d(){

        function k(){

            console.log(a)

        }

    k()}

d()}

q()

k函数里因为没有变量a,根据作用域链的机制console.log里的a会一直向上级作用域查找,一直找到全局作用域里的a,所以这里的a是12

(6)拓展思考:

私有作用域的释放与闭包

一般情况下,当函数执行完成,所形成的私有作用域都会自动释放掉,在私有作用域存储的值也会释放掉,但是也有特殊情况不销毁,1.函数执行完成,当前形成的私有作用域中,某些内容被私有作用域以外的变量占用了,此时私有作用域不能释放,也就是说私有作用域里边的东西被外边占用了,就不销毁。

举个例子

   function lo(){

             function ll(){

                 console.log(12)

             }

            

         }

 lo()

这里函数lo执行完毕之后其私有作用域是要销毁的,但是假如把里面的ll函数赋值给一个全局变量

let a =ll,这时候lo函数所形成的私有作用域就不会销毁,因为lo函数里面的ll函数被赋值给了一个全局变量,如果销毁了那ll函数也就不会存在了。

私有作用域有两大作用,一个是保护,一个是保存。保护就是函数执行会形成一个私有的作用域,外面无法直接获取里面的变量值,此时私有作用域把私有变量保护了起来,外面不管发生什么都不会影响里面的变量。保存就是像jQ这样吧所有的方法放到一个函数中保存起来,这种保存机制叫做闭包。

举个例子

假如有一个li列表,要求我随便点击哪一个它的背景颜色变成红色,如果你是这样写那就错了

let box =document.getElementsByTagName("li")

for(var i=0;i<box.length;i++){

    box[i].onclick=function(){

        box[i].style.backgroundColor='red'

    }

    }

因为这个函数绑定点击事件的时候并没有触发,它是点击的时候才会触发,所以绑定的时候函数里面的i是字符串i,他不是变量i,等到点击触发函数的时候,此时的i的值早就不是跟索引号一样了。这个问题可以用闭包的原理解决。

let box =document.getElementsByTagName("li")

for(var i=0;i<box.length;i++){

    box[i].onclick= (function(i){

        return  function(){

              box[i].style.backgroundColor='red'

          }

          })(i)

    }

这样写才是对的,点击事件绑定一个自执行函数,然后把变量i当做实参传入到自执行函数里,因为函数执行会自动形成一个私有的作用域,所以当全局变量i传进去之后就会变成了私有变量i,因为return返回一个函数绑定了事件,所以自执行函数的作用域在函数执行完不能销毁,此处体现了作用域的保存机制,把变量i保存了下来。当点击触发里面的函数时里面所调用的变量i就是自执行函数所保存的变量i。




返回列表 返回列表
评论

    分享到