(1)Javascript之作用域链

来源:互联网 发布:酷家乐在线装修软件 编辑:程序博客网 时间:2024/05/17 06:56

  • 引言
  • javascrpt的作用域前言
  • Javascript的Demo
    • 1demo1代码
    • 2demo2代码
    • 3demo3代码
    • 4 demo4代码
    • 5demo5代码
    • 6demo6代码
    • 7demo7代码
    • 8demo8代码
    • 9demo9代码
  • 总结

1.引言

      大家在初学javascript中,总感觉js和一些后台语言(例如C#,Java)太像了,除了js的类型是弱类型,其他感觉没有什么区别啊,好像语法都是一样的呢,其实这是不对的,js还是有很多它自己的特性,接下来我们就着重说一下js语言一些特别之处,其中一处便是javascript的作用域问题。

2.javascrpt的作用域前言

      在js中是不存在封闭作用域的。比如下面这个例子:

for(var i=0;i<10;i++){}alert(i);//此处弹出10

在上面这个例子中,弹出i为10,而不是undefined,如果这行代码是用Java语言写的,那么i肯定是未定义的(不信的同学可以去试一试),那么js的作用域到底是怎么回事呢?接下来我们用几个demo来介绍一下,在介绍demo之前,我们首先记住三句话:

  • 在JavaScript中函数是一个对象。
  • 函数对象会创建一个新的作用域。(很重要)
  • 一级作用域链是共享的,标签下面为一级作用域链(不理解没问题,先记住)

3.Javascript的Demo

3.1demo1代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><script>    var a=0;    var click1=function(){         alert(a);        }   </script><body><button onclick="click1();">弹框</button></body></html>
  • demo1图片
    这里写图片描述

首先大家都能看出来,此时点击按钮弹出0,此时我们从作用域链的角度去解释一下为什么弹出0.
解释:

  • 我们在一级作用域链中定义了变量 var a=0(在script标签下面),还定义了一个变量var click1
  • 当我们点击按钮时,因为按钮是标签(标签下面的为一级作用域),所以在一级作用域中查找函数对象click1,然后触发click1
  • 当函数被触发时,在click1的内部(注意是内部)执行代码alert(a)(函数对象会创建一个新的作用域,我们叫做click1二级作用域,注意我们叫做click1二级作用域),因为click1二级作用域没有对象a,然后他就会向上查找,查找到一级作用域有一个a=0,所以弹出0.

3.2demo2代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    var a=0;    function click1(){        var a=6;        alert(a);    }    document.getElementById("btn").onclick=click1;</script></html>
  • demo2图片

这里写图片描述

点击按钮弹出 6

解释

*demo2和demo1的区别在于在二级作用域中定义一了一个变量var a=6,当执行click1函数时,它先从 click1二级作用域查找,查找到了a,所以弹出对话框6.

3.3demo3代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    var a=0;    function click1(){        alert(a);        var a=4;    }    document.getElementById("btn").onclick=click1;</script></html>
  • demo3图片

这里写图片描述

弹出undefined

解释:

  • 我们在click1二级作用域下面执行了alert(a),它会首先在二级作用域下面找,发现二级作用域有变量a,但是在alert(a)的时候,a还没有赋值,所以弹出undefined,这也叫做变量名提升。代码和下面等价
function click1(){        alert(a);        var a=4;    }//等价于function click1(){        var a;        alert(a);        a=4;    }

3.4 demo4代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    function click1(){        var b=6;        function click2(){            var b=4;            alert(b);        };        click2();        alert(b);    }    document.getElementById("btn").onclick=click1;</script></html>
  • demo4图片

这里写图片描述

结果先弹出4,在弹出6

解释:

  • 在一级作用域下面定义了一个click1,在click1二级作用域下面定义了b=6,click2,在click2三级作用域下面定义了b=4.(函数对象创建一个新的作用域,因为click1是二级作用域了,所以新创建的作用域是click2三级作用域)
  • 当我们执行click1的时候,在click1里面调用了click2,然后alert(b)
  • 在click2 我们首先alert(b),因为我们在三级作用域定义了一个b=4,所以弹出4。在click1中的alert(b),因为我们在二级作用域定义了b=4,所以弹出4(注意:二级作用域不能访问三级作用域)

3.5demo5代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    function click1(){        var b=6;        function click2(){            b=4;            alert(b);              };        click2();        alert(b);    }    document.getElementById("btn").onclick=click1;</script></html>
  • demo5图片

这里写图片描述

先弹出4,然后又弹出4

解释:

  • demo5和demo4 的区别在于在click2三级作用域链中没有定义b,所以当b=4时它会向上查找,查找到二级作用域有b的定义,所以将二级作用域中的b修改为4,所以弹出4,当执行click1中的alert(b)时,b已经被修改成了4,所以第二次弹出的也是4.

3.6demo6代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    function click1(){        var b=6;        function click2(){            alert(b);        };    }    document.getElementById("btn").onclick=click2;</script></html>
  • demo6图片

这里写图片描述

显示click2未定义

解释:

  • 因为script标签下面为一级作用域,click2在二级作用域下面,作用域链可以向上查找,但是不能向下查找,所以在执行代码document.getElementById("btn").onclick=click2;,当触发点击事件时,显示click2未定义。

3.7demo7代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    function click1(){        var b=6;        function click2(){            var b=5        };        function click3(){            alert(b);        }        click3();    }    document.getElementById("btn").onclick=click1;</script></html>
  • demo7图片解释

这里写图片描述

弹出6

解释:

  • 在这个demo中有两个三级作用域链(注意只有一级作用域链是共享的),一个是click2三级作用域,一个是click3三级作用域,当alert(b)的时候,作用域链是向上查找的,找到了click1二级作用域中b=6,所以弹出了6

3.8demo8代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><button id="btn">弹框</button></body><script>    function click1(){        var b=6;        function click2(){            var b=5        };        function click3(){            var b=4;            alert(b);        }        click3();    }    document.getElementById("btn").onclick=click1;</script></html>
  • demo8图片

这里写图片描述

弹出4

解释:

  • demo8与demo7的区别就是在click3里面定义了b=4,所以直接在它本身作用域中拿到了b,所以弹出4.

3.9demo9代码

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title>    <script>    window.onload=function(){        click4=function(){            alert(6)        }}</script></head><body><button id="btn" onclick="click4();">弹框</button></body></html>

弹出 6

解释:

  • 大家可能疑问,为什么不是未定义呢?标签下面为一级作用域,所以代码<button id="btn" onclick="click4();">弹框</button>应该会在一级作用域中查找click4,但是click4明明在二级作用域中啊?注意我写的是click4=function(){},此处并没有用var ,所以这里不是定义是赋值,当执行click4=function(){}时,它首先会在2j级作用域中查找是否有click4,没有查找到,所以去一级作用域中查找,也没有查找到,所以就会在一级作用域中声明一个var click4,上面的代码与下面等价:
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title>    <script>    var click4;    window.onload=function(){        click4=function(){            alert(6)        }}</script></head><body><button id="btn" onclick="click4();">弹框</button></body></html>
  • 当我们把我们的代码修改为这样时,就会显示未定义了
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title>    <script>    window.onload=function(){        var click4=function(){            alert(6)        }}</script></head><body><button id="btn" onclick="click4();">弹框</button></body></html>

click4未定义

4.总结

然后我们在看一看我们开头说的几句话

  • 在JavaScript中函数是一个对象。
  • 函数对象会创建一个新的作用域。
  • 一级作用域链是共享的,标签下面为一级作用域链
  • 作用域链向上查找,不可能向下查找

在看这几个特点,关于js的作用域链你懂了吗?

1 0