• 作用域与命名空间


    作用域

    无论如何,函数是唯一拥有自身作用域的结构,其它任何形式的结构都不支持作用域。代码如下所示

    var demo = function ()
    {
    	...
    };
    

    function demo ()
    {
    	...
    };

    JavaScript语言中没有显式命名空间定义,这意味着所有对象都定义在一个全局共享的命名空间下

    引用变量时,向上依次遍历当前作用域、全局作用域,直到发现该变量

    隐式全局变量与局部变量

    在函数的自身作用域内,如变量声明不使用var表达式,就会导致隐式全局变量产生。先看如下代码所示

    var demo = function ()
    {
    	number = 1;
    };
    demo();
    

    var demo = function ()
    {
    	for (number = 0; number < 5; number ++)
    	{
    		...
    	};
    };
    demo();

    运行结果都为声明了一个全局变量number;如不想声明或者覆盖一个全局作用域内的同名变量,就必须使用var表达式。代码如下所示

    var demo = function ()
    {
    	var number = 1;
    };
    demo();
    

    var demo = function ()
    {
    	for (var number = 0; number < 5; number ++)
    	{
    		...
    	};
    };
    demo();

    运行结果都为声明了一个仅在当前作用域内才有效的局部变量number

    变量声明提升(Hoisting)

    变量声明在JavaScript语言中会被提升,这意味着var表达式、function声明会被提升至当前作用域顶部。先看如下代码所示

    demo();
    var demo = function ()
    {
    	...
    };

    demo();
    function demo ()
    {
    	...
    };

    代码执行之前被转化为

    var demo;
    demo();
    demo = function ()
    {
    	...
    };
    

    function demo ()
    {
    	...
    };
    demo();
    

    运行结果为第一段代码执行失败,第二段代码执行成功;因为第一段代码执行时demo仅仅是声明了,但是依然缺省值为undefined

    非常有意思的是局部变量声明的提升。再看如下代码所示

    var number = 0;
    var demo = function ()
    {
    	if (true)
    	{
    		number = 1;
    	}
    	else
    	{
    		var number = 2;
    	};
    	console.log(number);
    };
    demo();
    console.log(number);
    

    代码执行之前被转化为

    var number, demo;
    number = 0;
    demo = function ()
    {
    	var number;
    	if (true)
    	{
    		number = 1;
    	}
    	else
    	{
    		number = 2;
    	};
    	console.log(number);
    };
    demo();
    console.log(number);
    

    输出结果为1、0;本该覆盖全局变量number的代码转为声明了一个局部变量number,如想覆盖全局变量number,就必须取消所有的var表达式。代码如下所示

    var number = 0;
    var demo = function ()
    {
    	if (true)
    	{
    		number = 1;
    	}
    	else
    	{
    		number = 2;
    	};
    	console.log(number);
    };
    demo();
    console.log(number);
    

    输出结果为1、1

    命名空间

    只有一个全局作用域会导致命名冲突,解决方案是匿名包装器,作用是通过匿名函数创建一个新的命名空间。先看如下代码所示

    (function (){
    	...
    })();
    

    由于匿名函数被认为是表达式,为了可调用性,需要先行执行,我们可以把自执行的匿名函数理解为匿名包装器。再看如下代码所示

    ( //小括号内函数先行执行
    function ()
    {
    	...
    }
    ) //返回函数对象
    (); //立即执行匿名函数,并调用以上执行结果即函数对象

    通过匿名包装器创建命名空间,不仅可以防止命名冲突,而且有利于程序的模块化

    还有一些其他的函数表达式调用方法。代码如下所示

    +function (){
    	...
    }();
    
    !function (){
    	...
    }();
    
    (function (){
    	...
    }());
    

    有意思的思考题

    var number = 0;
    (function (){
    	console.log(number); //猜猜输出是什么
    	var number = 1;
    })();
  • 相关阅读:
    Git:常用命令记录
    JS笔记(二):隐式转换
    vertical-align/line-height:水平垂直居中
    JS笔记(一):声明提升
    Array.prototype.sort():从一道面试题说起
    CSS笔记(一):选择器规范
    FreeCodeCamp:Profile Lookup
    tile_images_offset的简单使用
    vs2013快捷键等(转)
    Qt状态栏的使用(转)
  • 原文地址:https://www.cnblogs.com/johnl/p/4849826.html
Copyright © 2020-2023  润新知