• 《JavaScript高级程序设计》笔记:函数表达式(七)


    递归

    function factorial(num){
        if(num<=1){
            return 1;
        }else {
            return num * arguments.callee(num-1);
        }
    }
    
    console.log(factorial(4));

    但是如果代码是在严格模式下开发:

    "use strict";
    function factorial(num){
        if(num<=1){
            return 1;
        }else {
            return num * arguments.callee(num-1);
        }
    }
    
    console.log(factorial(4));

    结果:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

    在严格模式下不能通过脚本访问arguments.callee,访问这个属性会报错,那么可以使用命名函数表达式来达到相同的结果:

    "use strict";
    var factorial = (function f(num){
         if(num<=1){
            return 1;
        }else {
            return num * f(num-1);
        }
    })
    
    console.log(factorial(4)); //24

    以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial,即是把函数赋值给另外一个变量,函数的名字仍然有效。

    闭包

    闭包是指有权访问另一个函数作用域中的变量的函数。

    闭包与变量

    作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。

    function createFunctions(){
        var result = new Array();
    
        for (var i=0; i<10; i++){
            result[i] = function(){
                return i;
            }
        }
    
        return result;
    }

    我们可以通过创建另一个匿名函数强制让闭包的行为符合预期。

    function createFunctions(){
        var result = new Array();
    
        for (var i=0; i<10; i++){
            result[i] = function(num){
                return function(){
                    return num;
                };
            }(i);
        }
    
        return result;
    }

    关于this对象

    在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window。

    var name = "The window";
    
    var object = {
        name: "My Object",
        getNameFunc: function(){
            return function(){
                return this.name;
            };
        }
    };
    
    console.log(object.getNameFunc()()); // The window

    不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

    var name = "The window";
    
    var object = {
        name: "My Object",
        getNameFunc: function(){
            var that = this;
            return function(){
                return that.name;
            };
        }
    };
    
    console.log(object.getNameFunc()()); // My Object 

    看下面代码:

    var name = "The window";
    var object = {
        name: "My Object",
        getName: function(){
            console.log(this.name);
        }
    }
    
    object.getName(); // My Object 
    (object.getName)(); // My Object 
    (object.getName = object.getName)(); // The window

    来分析下调用的结果:

    第一行代码跟平常一样调用了object.getName()返回了My Object ,因为this.name就是object.name。

    第二行代码在调用这个方法之前给它加了一个括号。虽然加了一个括号后,就好像只是在引用一个函数,但是this的值得到了维持,因为object.getName(object.getName)的定义是相同的。

    第三行代码先执行了一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值不能得到维持,结果就返回了The window

    当然你不大可能像第二行和第三行代码一样调用这个方法。这个例子只是说明了一个细微的语法变化,都有可能意外的改变this的值。

    内存泄露

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

    上述代码它所占用的内存不会永远消失。修改一下代码如下解决:

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

    模仿块级作用域

    用块级作用域(通常称为私用作用域)的匿名函数的语法如下所示:

    (function(){
    })();

    私有变量

    function add(num1,num2){
        var sum=num1+num2;
        return sum;
    }

    在这个函数内部,有三个私有变量:sum,num1,num2。在函数内部可以访问这几个变量。但是在函数外部则不能访问它们。如果在这个函数内部创建一个闭包,那么闭包可以通过自己的作用域链也可以访问这些变量。而利用这一点,就可以创建用于访问私有变量的公有方法。

    我们把有权访问私有变量和私有函数的公有方法称为特权方法。有两种在对象上创建特权方法的方式。第一种是在构造函数中定义特权方法。基本模式如下:

    function myObejct(){
        //私有变量和私有函数
        var privateVariable=10;
    
        function privateFunction(){
            return false;
        }
    
        //特权方法
        this.publicMethod=function(){
            privateVariable++;
            return privateFunction();
        }
    }

    利用私有和特权成员,可以隐藏那些不应该被直接修改的数据,例如:

    function Person(name){
        this.getName=function(){
            return name;
        }
        this.setName=function(value){
            name=value;
        }
    }
    var person=new Person("Nicholas");
    alert(person.getName());//Nicholas
    person.setName("Greg");
    alert(person.getName());//Greg

    静态私有变量

    通过在私有作用域中定义私有变量或函数,同样也可以创建特权方法。其基本模式如下:

    (function(){
        //私有变量和私有函数
        var privateVariable=10;
    
        function privateFunction(){
            return false;
        }
        //构造函数
        MyObject=function(){
    
        };
        //公有/特权方法
        MyObject.prototype.publicMethod=function(){
            privateVariable++;
            return privateFunction();
        }
        
    })();

    再看一个例子:

    (function(){
        var name = "";
        Person = function(value){
            name = value;
        };
        
        Person.prototype.getName = function(){
            return name;
        };
    
        Person.prototype.setName = function(value){
            name = value;
        };
    })();
    
    var person1 = new Person("Nicholas");
    console.log(person1.getName()); //Nicholas
    person1.setName('Grey');
    console.log(person1.getName()); //Grey
    
    var person2 = new Person("Michael");
    console.log(person1.getName()); //Michael
    console.log(person2.getName()); //Michael

    在一个实例上调用setName()会影响所有的实例。

    模块模式

    模块模式是为单例创建私有变量和特权方法。所谓单例,指的就是只有一个实例的对象。按照惯例,js是以对象字面量的方式来创建单例对象的。

    var singleton={
        name:value,
        method:function(){
            //这里是方法的代码
        }
    };

    模块模式通过为单例添加私有变量和特权方法能够使其得到增强。其语法形式如下:

    var singleton=function(){
        //私有变量和私有函数
        var privateVariable=10;
    
        function privateFunction(){
            return false;
        }
        //特权/公有属性和方法
        return {
            publicProperty:true,
            publicMethod:function(){
                privateVariable++;
                return privateFunction();
            }
        }
    }();

    增强的模块模式

    var singleton=function(){
    
        //私有变量和私有函数
        var privateVariable=10;
    
        function privateFunction(){
            return false;
        }
    
        //创建对象
        var object=new CustomType();
    
        //添加特权/公有属性和方法
        object.publicProperty=true;
    
        object.publicMethod=function(){
            privateVariable++;
            return privateFunction();
        }
    
        //返回这个对象
        return object;
    }();
  • 相关阅读:
    块级标签与预格式化文本标签----------大多数XHTML可以表示为两种类型的标签:块标签(block tag)和内联标签(inline tag)
    下拉框与下拉框之间的联动效果
    下拉框与文本框之间的转换
    设置密码是否为可见
    html表单
    HTML基础2——综合案例3——创建考试报名表格
    HTML基础2——综合案例2——复杂的嵌套列表
    java配置、IntelliJ IDEA Ultimate激活、
    字节流转字符流OutputStreamWriter、InputStreamReader,关闭流的方法
    文件字节流、字符流、缓冲字节流、缓冲字符流、数据流
  • 原文地址:https://www.cnblogs.com/moqiutao/p/10107536.html
Copyright © 2020-2023  润新知