JavaScript进阶系列01,函数的声明,函数参数,函数闭包

时间:2021-01-07 22:44:24

本篇主要体验JavaScript函数的声明、函数参数以及函数闭包。

 

□ 函数的声明

※ 声明全局函数

通常这样声明函数:

        function doSth() {
            alert("可以在任何时候调用我");
        }

通过这种方式声明的函数属于Window对象,可以在任何地方调用,即在doSth方法的之前和之后都可以调用。

 

可以在doSth方法之前调用:

        doSth();
        function doSth() {
            alert("可以在任何时候调用我");
        }

 

可以在doSth方法之后调用:

        function doSth() {
            alert("可以在任何时候调用我");
        }
        doSth();

 

※ 把函数赋值给变量

        var doSomething = function() {
            alert("只能在声明我之后再调用");
        };

 

不可以在doSomething方法之前调用:

        doSomething();
        var doSomething = function() {
            alert("只能在声明我之后再调用");
        };

以上,报"undefined funciton ..."错。

 

可以在doSomething方法之后调用:  

        var doSomething = function() {
            alert("只能在声明我之后再调用");
        };
        doSomething();   
 

□ 函数参数

※ 即使声明的函数没有参数,也可以在调用时传入参数

        doSth("你好");
        function doSth() {
            alert(arguments[0]);
        }

输出结果:你好

 

※ arguments.callee属性表示函数引用

        doSth("你好");
        function doSth() {
            alert(arguments.callee);
        }

JavaScript进阶系列01,函数的声明,函数参数,函数闭包
以上,在函数内部使用arguments.callee属性表示的是函数本身。

 

※ arguments.callee()方法递归调用函数

        doSth();
        function doSth() {
            alert("你好");
            arguments.callee();          
        }
输出结果:不断显示"你好"    


□ 函数闭包

※ 闭包的形成

先看下面代码:

        function doSth(val) {
            return function() {
                alert(val);
            };
        }
        var fn = doSth("hello");
        fn();

输出结果:hello

在doSth方法内部返回一个匿名函数,通过fn()执行匿名函数,把doSth方法的参数变量val打印了出来。在这里,doSth方法内部的匿名函数被称作"闭包"。换句话说,我们在内存上创建了一个匿名对象。   


※ 闭包的释放

如果在调用fn方法之后,通过fn=null,把fn设置为null,首先匿名函数所占内存被释放,接着,由于变量val不再被引用,val所占内存被释放,最后释放doSth所占内存。

 

※ 过多的"闭包"会增加内存开销

        function doSth(val) {
            return function() {
                alert(val);
            };
        }
        var fn = doSth("hello");
        var fn2 = doSth("hello2");
        fn();
        fn2();
        fn();

输出结果:依次显示hello, hello2, hello

无论是调用fn方法,还是fn2方法,都会在内存上创建匿名对象,消耗更多的内存。

 

※ 使用"闭包"创建module

举例:声明一个函数用来创建唯一的ID

        var i = 0;
        function CreateUniqueName() {
            var name = "name" + i;
            i = i + 1;
            return name;
        }
        var name1 = CreateUniqueName();
        var name2 = CreateUniqueName();
        alert(name1 + " " + name2);

输出结果:name0 name1

 

以上存在几个问题:
1、创建的函数不是全局的,只能在当前页使用
2、变量i和方法CreateUnqiueName都是全局的,这可能会造成与第三方代码的名称冲突 

 

所以,我们应该把以上的逻辑写成全局,并做成一个module,并自定义名称。

       var myUtilty = (function() {
           var i = 0;
           return {
               CreateUniqueName: function() {
                   var name = "name" + i;
                   i = i + 1;
                   return name;
               }
           };
        }());
        
        var name1 = myUtilty.CreateUniqueName();
        var name2 = myUtilty.CreateUniqueName();
        alert(name1 + " " + name2);

○ (function(){}());被称作是匿名、自触发函数,返回一个json对象,并且只执行一次
○ 正因为匿名、自触发函数只被执行一次,所有全局只有一个myUtitly对象,不会过多消耗内存
○ json对象的键CreateUniqueName对应一个匿名方法  
○ 匿名、自触发函数可以被看作是全局的、唯一的"闭包" 

 

“JavaScript进阶系列”包括:

JavaScript进阶系列01,函数的声明,函数参数,函数闭包

JavaScript进阶系列02,函数作为参数以及在数组中的应用

JavaScript进阶系列03,通过硬编码、工厂模式、构造函数创建JavaScript对象

JavaScript进阶系列04,函数参数个数不确定情况下的解决方案

JavaScript进阶系列05,事件的执行时机, 使用addEventListener为元素同时注册多个事件,事件参数

JavaScript进阶系列06,事件委托

JavaScript进阶系列07,鼠标事件