1 Star 0 Fork 0

PaddyWang / summarize

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
15 闭包.md 5.27 KB
一键复制 编辑 原始数据 按行查看 历史
PaddyWang 提交于 2016-04-04 18:47 . updata

闭包

从字面上来理解闭包就是封闭的包裹

可以理解为受到保护的区域

即: 函数内部定义的变量,函数外部无法访问

产生闭包的原因:js的词法作用域

有时候往往在一个作用域中需要访问另一作用域中的变量

即:跨链访问

闭包的作用的就是进行跨链访问

走一个demo:

function fn(){
    var num = Math.random();
}

现在需要在函数外部获取num的值,该怎么做呢???

可以改一下函数:

function fn(){
    var num = Math.random();
    return num;
}
var a = fn();
console.log(a);  // => 0.23493962781503797

那么如果在函数外部需要获取两次或多次num的值呢???

function fn(){
    var num = Math.random();
    return num;
}
var a = fn();
var b = fn();
console.log(a);  // => 0.059904436115175486
console.log(b);  // => 0.8948184980545193

很明显调用了两次fn函数所有获取了两个不一样的值

如果需要多次获取num的并且需要值统一又该怎么做呢???

function fn(){
    var num = Math.random();
    return function(){
        return num;
    };
}
var f = fn();
var a = f();
var b = f();
console.log(a);  // => 0.36699223099276423
console.log(b);  // => 0.36699223099276423

实现原理:

通过调用fn函数,让其返回一个匿名函数

该匿名函数在fn函数内部,有权访问num

让匿名函数返回num

在每次需要获取num的值时只需要调用匿名函数

fn没有被再次调用即num的值不会改变

那么如果在fn函数中有两个值或多个值,该怎么获取???

function fn(){
    var num1 = Math.random();
    var num2 = Math.random();
    return {
        num1: function(){
            return num1;
        },
        num2: function(){
            return num2;
        }
    };
}
var f = fn();
var a1 = f.num1();
var a2 = f.num2();
var b1 = f.num1();
var b2 = f.num2();
console.log(a1);  // => 0.859178748447448
console.log(b1);  // => 0.859178748447448
console.log(a2);  // => 0.18789607286453247
console.log(b2);  // => 0.18789607286453247

那么如果既要可以获取又要可以修改fn中的值该怎么做呢???

function fn(){
    var num;
    return {
        getNum: function(){
            return num;
        },
        setNum: function(n){
            num = n;
        }
    };
}
var f = fn();
var get1 = f.getNum();
console.log(get1);  // => undefined
f.setNum(123);
var get2 = f.getNum();
console.log(get2);  // => 123

通过返回一个对象,该对象包含不同的操作函数,来实现复杂的闭包

也可以直接返回匿名函数,通过匿名函数再返回一个对象,来实现闭包

function fn(){
    var num;
    var o = {
        oNum: num
    };
    num = o.oNum;
    return function(){
        return o;
    };
}
var f = fn();
var get1 = f().oNum;
console.log(get1);  // => undefined
f().oNum = 123;
var get2 = f().oNum;
console.log(get2);  // => 123

这个实现闭包的方法是通过值类型和引用类型的特性来实现的

即:将num和对象ooNum的属性链接在一起

通过闭包可以解决什么呢???

利用闭包的特点可以实现数据缓存

接下来通过闭包来实现斐波那契数列(兔子数列):

// 0, 1, 2, 3, 4, 5, 6...n
// 1, 1, 2, 3, 5, 8, 13...

var count1 = 0;
var count2 = 0;
// 首先用递归思想实现
function fn(n){
    count1 ++;
    if(n < 0) return ;
    if(n === 1 || n === 0) return 1;
    return arguments.callee(n - 2) + arguments.callee(n - 1);
}
console.log(fn(5) + ',执行了' + count1 + '次');  // => 8,执行了15次

// 采用闭包来实现:
var foo = (function(){
    var arr = [];  // 用于缓存数据
    return function(n){
        count2 ++;
        var res = arr[n];
        if(n < 0) return ;
        if(res){
            return res;
        }else{
             if(n === 1 || n === 0){
                res = 1;
             }else{
                res = arguments.callee(n - 2) + arguments.callee(n - 1);
             }
            arr[n] = res;
            return res;
            }
        }
    })();
console.log(foo(5) + ',执行了' + count2 + '次');  // => 8,执行了9次

通过闭包缓存数据的效率明显比递归高多了

extend:

再介绍一种通过函数名缓存数据,来实现斐波那契数列

function fib(n){
    var res = [];
    res = fib[n];
    if(res){
        return res;
    }else{
        if(n === 1 || n === 0){
            res = 1;
        }else{
            res = arguments.callee(n - 2) + arguments.callee(n - 1);
        }
        fib[n] = res;
        return res;
    }
}
console.log(fib(5));  // => 8

summarize:

实现闭包可以通过返回一个函数或是一个对象(对象中包含功能函数)来实现

闭包解决了跨链访问问题

闭包可以实现数据缓存

HTML
1
https://gitee.com/paddywang/summarize.git
git@gitee.com:paddywang/summarize.git
paddywang
summarize
summarize
master

搜索帮助