编程go之Javascript

Javascript 基础之闭包(Closure)

2017-03-21  本文已影响12人  编程go

闭包,在函数内部定义了一个函数,然后这个函数调用到了父函数内的相关临时变量,这些相关的临时变量就会存入闭包作用域里面。

function Count(param) {
    var x = param || 0;
    return {
        addValue: function () {
            x = x + 1;
            return x;
        }   
    }
}
var count = new Count();
console.log(count.addValue());  // 1
console.log(count.addValue());  // 2
console.log(count.addValue());  // 3
console.log(count.addValue());  // 4
闭包示意图
延迟执行(懒函数)

由于闭包可以调用父函数相关临时变量存入闭包作用域内,这个特性可以实现懒函数,可以用来优化程序性能。

function lazySum(arr) {
    return function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    };
}
var sum = lazySum([1,3,5,7,9]);
// 只有在调用sum 函数时,才会执行加法运算。
var result = sum();
console.log(result);

由于相关变量保留在闭包作用域内的特性,如果父函数的变量时循环变量,这样就有可能在执行懒函数时出现意料之外的问题。下面的代码预期的结果是4,实际的结果却是25。

function Count(param) {
    var arr = [];
    for(var i = 0; i < param; i ++) {
        arr.push(function() {
            return i * i;
        });
    }
    return arr
}
var count = new Count(5);
var f = count[2];
console.log(f())  // 25

可以通过立即执行函数(指定义完了立即调用的匿名函数,往往用它来开辟一个独立的作用域),对方法体进行修改,从而达到预期的效果。

function Count(param) {
    var arr = [];
    for(var i = 0; i < param; i ++) {
        arr.push((function(n) {
            return n * n;
        }) (i));
    }
    return arr
}
var count = new Count(5);
var f = count;
console.log(f)   // [0, 1, 4, 9, 16]
外部读取局部变量

由于Javascript 具有特殊的作用域链,外部函数很难访问到局部变量。详细介绍请转到Javascript 基础之作用域

function Student() {
    var name = "Spursyy";

    return function() {
        return name;
    };
}
var student = new Student();
var name = student();
console.log(name);  // "Spursyy"
模拟私有成员变量

保护私有成员变量,隐藏私有成员的方法

function Student() {
    var name;
    return {
        set: function(name) {
            this.name = name;
        },
        get: function() {
            return this.name;
        }
    }
}

var student = new Student();
student.set("Spursy");
var name = student.get();
console.log(name);  // "Spursy"
模块化

闭包有益于模块化编程。它能以简单方式开发较小的模块,从而提高开发速度和程序的可复用性。与没有使用闭包的程序相比,使用闭包可将模块划分得更小。

var each = function (object, callback, args) {
    var name;
    var i = 0;

    var length = object.length;
    var isObj = length === undefined || typeof (object) == "function";
    if (args) {
        if (isObj) {
            for (name in object) {
                if (callback.apply(object[name], args) === false) {
                    break;
                }
            }
        }
        else {
            for (; i < length; ) {
                if (callback.apply(object[i++], args) === false) {
                    break;
                }
            }
        }
    } 
    else {  
        if (isObj) {  
            for (name in object) {
                if (callback.call(object[name], name, object[name]) === false) {
                    break;
                }
            }
        }
        else {
            for (var value = object[0]; i < length && callback.call(value, i, value) !== false; value = object[++i]) {
            }
        }
    }
    return object;
}
 
var arr = [1, 2, 3, 4, 5];
each(arr, function (index, value) {
    console.log(index + ':' + value);
}); 
上一篇 下一篇

猜你喜欢

热点阅读