《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;
}();
    原文作者:风雨后见彩虹
    原文地址: https://segmentfault.com/a/1190000000733242
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞