zoukankan      html  css  js  c++  java
  • 《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;
    }();
  • 相关阅读:
    Count and Say leetcode
    Find Minimum in Rotated Sorted Array II leetcode
    Find Minimum in Rotated Sorted Array leetcode
    Search in Rotated Sorted Array II leetcode
    search in rotated sorted array leetcode
    Substring with Concatenation of All Words
    Subsets 子集系列问题 leetcode
    Sudoku Solver Backtracking
    Valid Sudoku leetcode
    《如何求解问题》-现代启发式方法
  • 原文地址:https://www.cnblogs.com/moqiutao/p/10107536.html
Copyright © 2011-2022 走看看