JavaScript学习-1 函数-1.2 变量作用域

首先,var声明的变量只有函数级作用域和全局作用域,没有块级作用域,要想实现块级作用域,要用let。

1.2.1 作用域链

当使用一个变量时,js首先在当前作用域找这个变量,如果找不到,到上一级去找。我们通过一个例子说明。

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title></title>

    <script>

        n0 = 0;

        function Test1() {

            var n1 = 1;

            function Test2() {

                var n2 = 2;

                alert(n0);  //一直找到全局作用域

                alert(n1);  //找到上一级Test1的作用域

                alert(n2);  //当前作用域

            }

            Test2();

        }

       Test1();

    </script>

</head>

<body>

</body>

</html>

分别打印0,1,2,其实没啥不好理解的,一层层往上找呗。

1.2.2 变量提升

简单说,就是变量声明同一提前到当前作用域开始的地方,但是赋值操作不会提升。

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title></title>

    <script>

        function Test1() {

            var n1 = 1;

            alert(n1);

            alert(n2);

            //var n2 = 2;

        }

       Test1();

    </script>

</head>

<body>

</body>

</html>

这段代码执行到alert(n2)时会报错,如果放开注释,会打印undefined,原因就是变量提升。放开注释后类似于下面的代码

        function Test1() {

            var n1 = 1;

            var n2;

            alert(n1);

            alert(n2);

            n2 = 2;

        }

个人理解变量提升是为了服务于变量作用域这个机制,但是我觉得这个机制让代码可读性下降,为了规避这个问题,变量声明在作用域头部我觉得更容易理解。

1.2.3 命名空间

因为全局变量会绑定到window作用域,假设一个页面引用了两个js文件,这两个js文件定义了同名的全局变量名,就会造成冲突,如下:

文件js1.js

var str = "js1";

文件js2.js

var str = "js2";

 

执行下面代码时:

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title></title>

    <script src="js2.js"></script>

    <script src="js1.js"></script>

    <script>

        alert(str);

    </script>

</head>

<body>

</body>

</html>

打印结果时最后引用js文件的str,本案例是js1;这个使得变量管理十分混乱,下面

我们用命名空间解决变量冲突问题

文件js1.js

var ns1 = {};

ns1.str = "js1";

文件js2.js

var ns2 = {};

ns2.str = "js2";

 

执行下面代码时:

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title></title>

    <script src="js2.js"></script>

    <script src="js1.js"></script>

    <script>

        alert(ns1.str);

        alert(ns2.str)

    </script>

</head>

<body>

</body>

</html>

可以正常打印了,其实这个也很好理解,就是把每个js文件的的变量追加到一个不重名的对象上。至于js对象这个概念,我们会在[2 面向对象]在讨论。

1.2.4 块级作用域

所谓块级作用域,在c#里面就是说出了大括号,声明的变量会释放掉。但是在js里面,var只有函数和全局作用域,块级作用域要用let实现。废话不多说,直接上例子:

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title></title>

    <script>

        function Test(n1) {

            if (n1 > 0) {

                var str = "More than 0";

                alert(str);

            } else {

                str = "Less than 0"  //这里没声明str,但是可以正常使用

                alert(str);

            }

        }

        Test(10);

        Test(-1);

    </script>

</head>

<body>

</body>

</html>

分别打印["More than 0"]和["Less than 0"],str出了if大括号依然可以使用,原因其实就是变量提升造成的,str的声明提升到了函数Test的头部。

那么我们就想实现大括号的块级作用域怎么办?let声明变量+[ use strict]就好了。

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title></title>

    <script>

        'use strict'//要在strict模式下

        function Test(n1) {

            if (n1 > 0) {

                let str = "More than 0";

                alert(str);

            } else {

                str = "Less than 0"  //执行这一不,报错,变量未定义,加let就好了

                alert(str);

            }

        }

        Test(10);

        Test(-1);

    </script>

</head>

<body>

</body>

</html>

发布了51 篇原创文章 · 获赞 4 · 访问量 4247

猜你喜欢

转载自blog.csdn.net/songjian1104/article/details/99639656