信息发布→ 登录 注册 退出

javascript作用域和作用域链详解

发布时间:2026-01-11

点击量:
目录
  • 一、javascript的作用域
    • 1、全局作用域
    • 2、局部作用域
  • 二、javascript的作用域链
    • 三、作用域链和优化
      • 四、改变作用域链
        • 1、with语法改变作用域链
        • 2、catch语法
      • 总结

        一、javascript的作用域

        1、全局作用域

        1、最外层函数和最外层函数定义的变量
        var age = 20
        function func1() {
          var sex = "男"
          function func2() {
            console.log("hello func2")
          }
          func2()
        }
        console.log(age)    //20
        console.log(func1)  //正常执行
        console.log(func2)  //报错
        console.log(sex)    //报错
        
        2、所有未直接声明的变量,直接赋值为全局变量
        function func1() {
          var age = 20
          sex = "男"
        }
        func1()
        console.log(sex)    //男
        console.log(age)    //报错
        
        3、window对象上面的属性具有全局作用域
        function func1() {
          var age = 20
          sex = "男"
          console.log(top)   //window....
          
        }
        func1()
        console.log(sex)   //"男"
        console.log(top)   //window....
        

        2、局部作用域

        和全局作用域相反,局部作用域只在函数内部可以访问到。function func1() {  var age = 20  func1()  function func1() {    console.log("func1")  }}func1()和全局作用域相反,局部作用域只在函数内部可以访问到。
        function func1() {
          var age = 20
          func1()
        
          function func1() {
            console.log("func1")
          }
        }
        func1()
        

        二、javascript的作用域链

        函数也是对象,在函数内部存在一个属性[[scope]],该属性包含可以访问属性的集合。决定了哪些属性在函数中可以访问到。
        
        下面我们以一个函数的例子来详细解说一下,函数作用域链。
        1、在函数函数创建出来时。代码如下所示
        function add(num1, num2) {
          return num1 + num2
        }
        

        函数初始化时,会将自己的作用域链中放入全局变量
        
        var total = add(10, 20)
        这里是函数执行时,当执行时会创建一个新的对象放入作用域链中,这个对象中包括
        arguments, 形参,this,以及返回值。
        

        active object是活跃对象,是函数执行时创建的对象,然后scope chain类似于栈结构,函数执行前压入栈中,函数执行结束就从栈中弹出。函数访问属性的过程就是沿着scope chain从上往下一次查找。
        

        三、作用域链和优化

        从上面的例子中,我们可以看出,访问全局作用域是最慢的,因为需要依次从上往下进行查找,应当尽可能少的使用全局变量,应该尽可能使用局部变量。如果在函数
        中,使用多次全局变量,我们可以将全局变量转化为局部变量,然后在使用局部变量。
        
        function changeColor(){
            document.getElementById("btnChange").onclick=function(){
                document.getElementById("targetCanvas").style.backgroundColor="red";
            };
        }
        上面代码我们使用了两次document,但是document作为全局变量,此时我们应该将其转化为局部变量来使用,所以下面为转化后的代码。
        function changeColor(){
            var doc=document;
            doc.getElementById("btnChange").onclick=function(){
                doc.getElementById("targetCanvas").style.backgroundColor="red";
            };
        }
        

        四、改变作用域链

        1、with语法改变作用域链

        with语法的作用就是为了解决代码重写问题,是对象快捷书写方式,但是这么好的方式,为什么不大力推广使用呢?因为性能存在一些问题。function initUI(){    with(document){        var bd=body,            links=getElementsByTagName("a"),            i=0,            len=links.length;        while(i < len){            update(links[i++]);        }        getElementById("btnInit").onclick=function(){            doSomething();        };    }}这里使用with语法省略了document。with语法的作用就是为了解决代码重写问题,是对象快捷书写方式,但是这么好的方式,为什么不大力推广使用呢?
        因为性能存在一些问题。
        function initUI(){
            with(document){
                var bd=body,
                    links=getElementsByTagName("a"),
                    i=0,
                    len=links.length;
                while(i < len){
                    update(links[i++]);
                }
                getElementById("btnInit").onclick=function(){
                    doSomething();
                };
            }
        }
        这里使用with语法省略了document。
        

        with传入的对象的属性放入最上层,剩余的都往下压,导致局部变量的访问代价增大,所以with的性能不好。
        

        2、catch语法

        我们在使用try--catch时,当代码执行错误时,会执行catch函数,catch函数中参数是错误对象,就是这个错误对象,会放到作用域链的头部。
        但是try--catch我们在必要的使用得使用,我们可以这样解决。
        try{
            doSomething();
        }catch(ex){
            alert(ex.message); //作用域链在此处改变
        }
        
        处理后:
        try{
            doSomething();
        }catch(ex){
            handleError(ex); //委托给处理器方法
        }
        解决方案是:将catch错误处理交给另外一个函数进行处理。
        

        总结

        本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!

        在线客服
        服务热线

        服务热线

        4008888355

        微信咨询
        二维码
        返回顶部
        ×二维码

        截屏,微信识别二维码

        打开微信

        微信号已复制,请打开微信添加咨询详情!