第七章 函数表达式

定义函数的两种方式:函数声明函数表达式

    "use strct";
        // 函数声明,指定函数名
        function functionName(arg0,arg1,arg2){
            // 函数体
        }
        // 函数声明提升,即执行代码之前会先读取函数声明
        sayHi(); //再调用
        function sayHi(){ //先读声明
            alert("hello world");  // hello worold
        }

匿名函数

       "use strct";
       // 函数表达式
       // 匿名函数,即创建一个函数并将它赋值给变量functionName
       // 没有函数提升
       var functionName = function(arg0,arg1,arg2){
        //函数体
       };

递归

递归函数是一个在函数通过名字调用自身的情况下构成。

        //经典的递归阶乘函数
        function factorial(num){
            if(num<=1){
                return 1;
            }else{
                return num*factorial(num-1);
            }
        }
        var anotherFactorial = factorial;
        // 存在弊端
        //如果factorial=null;anotherFactorial //error
        alert(anotherFactorial(3));

        // argument.callee 指向正在执行的函数指针
        "use strict"; // 存在弊端 严格模式无法运行
        function factorial(num){
            if(num<=1){
                return 1;
            }else{
                return num*arguments.callee(num-1);
            }
        }
        var anotherFactorial=factorial; 
        factorial=null;

        //命名函数表达式,在严格模式也能正常运行
        "use strict";
        var factorial=(function f(num){
            if(num<=1){
                return 1;
            }else{
                return num*f(num-1);
            }
        })
        var anotherFactorial= factorial;
        factorial=null;
        alert(anotherFactorial(3));

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

        function createComparisonFunction(propertyName){
            return function(obj1,obj2){
                var val1=obj1[propertyName];
                var val2=obj2[propertyName];
                if(val1<val2){
                    return -1
                }else if(val1>val2){
                    return 1;
                }else{
                    return 0;
                }
            };
        }

createComparisonFunction() 函数执行完毕之后,其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。
即createComparisonFunction() 函数返回后,其执行环境环境的作用域链会被销毁,但它活动对象仍然会留在内存中;知道匿名函数被销毁后。
销毁匿名函数 compareName=null

作用域链查找对象

            if(value1<value2){
                return -1;
            }else if(value1>value2){
                return 1;
            }else{
                return 0;
            }
        }
        var result = compare(5,10);

这里写图片描述

闭包与变量

闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊变量

        //每个函数的作用域链中都保存着createFunction() 函数的活动对象,引用都是同一变量i
        function createFunction(){
            var result = new Array();
            for(var i=0;i<10;i++){
                result[i] = function(){
                    return i;
                };
            }
            return result;
        }
    //创建另一个匿名函数强制让闭包的行为符合预期
    //重写createFunction() 函数后,每个函数就会返回不同的索引值
    //没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组
        function createFunction(){
            var result = new Array();
            for(var i=0;i<10;i++){
                result[i]=function(num){
                    return function(){
                        return num;
                    }
                }(i);  
        }
        return result;
    }

关于this 对象

在闭包中使用this 对象可能会导致一些问题。this 对象是运行时基于函数执行环境绑定的:在全局函数中,this 等于window,而当函数被作为某个对象方法调用时,this 等于那个对象。
匿名函数的执行环境具有全局性,因此this 通常指向window(通过call() 或apply() 改变函数的环境下,this会指向其他对象)

        var num=15;
        function num1(){
            var num=2;
            return function(){
                return this.num;
            }
        }
        alert(num1()());
            //把外部作用域中的this 对象保存在一个闭包能够访问的变量里,就可以让闭包访问该对象
    var name = "The Window";
    var object={
        name:"My Object",
        getNameFunc : function(){
            var that =this;
            return function(){
                return that.name;
            };
        }
    };
    alert(object.getNameFunc()()); //My Object

内存泄漏

        function assignHandler(){
            var element=document.getElementById("someElement");
            var id=element.id;
            element.onclick=function(){
                alert(id);
            };
            element=null;
        }

模仿块级作用域

    <script>
        //JavaScript 没有块级作用域。
        //意味着在块级语句中定义的变量,实际上是包含函数中而非语句中创建的。
        //在Java、C++语句中,变量i只会在for 循环的语句块中有定义,循环一旦结束,变量i就会被销毁
        "use strict";
        function outputNumbers(count){
            for(var i=0;i<count;i++){
                document.write(i);
            }
            document.write(i);
        }
        outputNumbers(5);
    </script>
            // JavaScript 不会告诉是否多次声明同一个变量;
            // 遇到这种情况,它只会对后续的声明视而不见
            var i;
            document.write(i);

匿名函数可以用来模仿块级作用域并避免重新声明变量这个问题。

    <script>
        "use strict";
        //块级作用域(通常称为私有作用域)的匿名函数的语法如下
        //代码定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对括号会立即调用这个函数。
        (function(){
            //这里是块级作用域
        })();
    </script>

理解步骤:

    <script>
        "use strict";
        var count =5;
        outputNumbers(count);
        //把值直接传递给函数
        outputNumbers(5); // 变量只不过是值的另一种表现形式,因此可以用实际值替换
        //定义一个匿名函数,并把匿名函数赋值给变量someFunction。
        //调用函数的方式是在函数名称后面添加一对圆括号,即someFunction()
        var someFunction=function(){
            // 这里是块级作用域
        };
        someFunction();
        //通过上面例子,可以使用实际值来替代变量count
        //那是否可以用函数值直接取代函数名?
        function(){
            //这里是块级作用域
        }(); //出错
        //上面代码会导致语法错误,因为JavaScript 将function 关键字当作一个函数声明的开始
        //函数声明后面不能跟圆括号,而函数表达式可以跟圆括号
        //将函数声明转换成函数表达式,只需要象下面给它加一对圆括号即可
        (function(){
            //这里是块级作用域
        })();
    </script>

    <script>
        //无论什么地方,只要临时需要一些变量,就可以使用私有作用域
        //匿名函数中定义的任何变量,都会在执行结束时被销毁
        function outputNumbers(count){
            (function () {
                for(var i=0;i<count;i++){

                    document.write(i);
                }
            })();
        }
        outputNumbers(5);
    </script>   

这种做法可以减少闭包占用内存的问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用链。

私有变量

严格讲,JavaScript 中没有私有成员的概念;所有对象属性都是公有的。但有一个私有变量概念,任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量

    <script>
        //私有变量包括函数参数、局部变量和在函数内部定义的其他函数
        function add(num1,num2){
            var sum = sum1+sum2;
            return sum;
        }
    </script>

访问私有变量共有办法:通过函数内部创建一个闭包,闭包可以通过作用域链访问。
把有权访问私有变量和私有函数的共有方式称为特权方式

猜你喜欢

转载自blog.csdn.net/yana_loo/article/details/76599908