JavaScript:作用域:函数作用域/全局变量污染/命名空间


	JavaScript:作用域:函数作用域/全局变量污染/命名空间
[编程语言教程]

在C#中我们都基本上不讲作用域,因为一切都是自然而然的(用语言描述反而有些困难)。但JavaScript的作用域,让人非常头大!

 

局部变量

如果一个变量在函数体内部(用var)声明,则该变量的作用域为整个函数体,在函数体外不可引用该变量。(另见:let)

不同函数内部的同名变量互相独立,互不影响。

这样被声明的变量被称之为:局部变量。

function scope() {
    var sname = ‘李志博‘;
    console.log(‘in function:‘ + sname);
}
scope();
console.log(‘out function:‘ + sname);

 

全局变量“污染”

不在任何函数内定义的变量具有全局作用域,被称之为全局变量。

演示:

如果script只是在HTML页面中使用,全局变量还可以接受(而且比较方便);

但随着JavaScript规模扩大,一个项目可能引用多个(第三方/其他人写的)类库(js文件),各个文件间的名称冲突就越来越难以避免,给开发/维护带来极大的问题!这就被称之为“全局变量污染”。

词法作用域

观察以下代码:

        var sname = "飞哥";
        function smart() {      
            alert(`${sname}最帅`);
        }

        function reallySmart() {
            var sname = ‘子祥‘;   
            smart();
        }
        reallySmart();

reallySmart()调用smart(),smart()中需要sname但又没有声明sname,怎么办?

  • 使用reallySmart()中定义的‘子祥‘,还是
  • 全局变量”飞哥”

由var声明的变量的作用范围,其作用域由是由其源代码的书写位置,(而不是在哪里执行)决定的。

 

JavaScript的函数中不仅可以使用全局变量,还可以使用该函数外部的函数所声明的变量:

        function outFunc(sname) {
            var age = 100;
            function innerFunc() {
                alert(age);   //age定义在innerFunc()之外
            }
            innerFunc();
        }

这样就形成了一个作用域链:JavaScript会沿着这个链条由内向外查找,直到undefined。

@想一想@:如何剪切/粘贴第一个函数,才能显示:子祥最帅?

 

名称空间(namespace)

其他成熟的工程化语言内置了名称空间(namespace)来解决这个问题,比如:

//虽然都是“源栈”,但他们显然是不一样的:
China.Chongqing.Luckystack
China.Bejin.Luckystack
US.NewYork.Luckstack

JavaScript只能模拟:

  1. 先定义一个唯一的全局变量(对象)
  2. 其他变量都写出是上述全局变量的成员(属性和方法)
  3. 还可以多层嵌套,最后形成名称空间一样的“样式”
var China = {};
China.Chongqing = {};
China.Chongqing.LuckyStack = {};
China.Chongqing.LuckyStack.wpz = function () {

JQuery等类库就是这样做的。(演示)

 

strict模式(ES5)

把我们之前的代码稍作改动:

function scope() {
    /*var*/ sname = ‘李志博‘;   //注释掉var

@猜一猜@:会有什么结果?

 

如果在JavaScript的函数中声明变量,不使用var,该变量就具有全局作用域!——特性超级坑爹的一个“特性(bug)”,尤其是在代码review的时候,你根本不知道这是在:

  • 使用一个已声明的变量,还是
  • 要声明一个全局变量

所以从ES5开始,JavaScript就引入了所谓的“严格”模式,在代码顶部添加一行:

‘use strict‘;  -- 如果浏览器不支持?

使用严格模式,就能强制JavaScript声明变量时必须使用:var;否则会报错。(以及其他约束)

演示:调试窗口报错

 

 

官方推荐总是使用严格模式。但是,如果

  • a.js 文件上声明了‘use strict‘
  • b.js 文件没有声明‘use strict‘且没有按照严格模式书写代码

  • 在html文件中先引用了a.js,然后再引用了 b.js

@想一想@:会出现什么情况?

所以,更多时候,我们不得不把‘use strict‘声明在函数顶部。

 

体会:JavaScript在处理大型项目,进行工程化开发方面先天不足!由此诞生了很多“奇巧淫技”,以及不断进化的ES标准。

但你以为这样就结束了?too young too simple啊!作为一个“先天严重不足,后天各种补丁”的语言,这一切才刚刚开始……

技术图片

 

 

作业

    1. 使用“模拟名称空间”技术,构建一个函数函数yz.fei.get(number);

    2. yz.fei.get(number)除number以外,还可以接受任意多个回调函数做参数
      1. 这些回调函数能对number进行运算,并返回bool值的,比如has9()/has8()/has6()
      2. get()函数依次运行它的回调函数,只要回调函数运行结果为真,就累加计数
      3. 最后返回累加值

      让yz.fei.get(number)调用has9()/has8()/has6(),实现之前“统计含9/8/6数字个数”的作业

JavaScript:作用域:函数作用域/全局变量污染/命名空间

原文地址:https://www.cnblogs.com/nntisn351/p/14174958.html

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » JavaScript:作用域:函数作用域/全局变量污染/命名空间