js實例教程-JavaScript中的閉包及應用場景介紹

发布时间:2018-11-23 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了js實例教程-JavaScript中的閉包及應用場景介紹脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小寶典致力於為廣大程序猿(媛)提供高品質的代碼服務,請大家多多光顧小站,小寶典在此謝過。
@H_777_1@對於前端開發工程師來講,閉包是一個很難弄懂而且十分難征服的一個概念!因為閉包的生成不僅僅與變量的作用域相關而且與變量的生命周期也有着密切的關係。最後我可以肯定的告訴你,閉包在實際開發的過程中應用十分廣泛,所以你必須要掌握它。

先來看一下關於閉包的定義:閉包是指有權訪問另一個函數作用域中的變量的函數。創建閉包的常見方式,就是在一個函數內部創建另一個函數。

//通過閉包可以獲得函數fn的局部變量user

function fn(){

    VAR user='zhang';

    return function(){

        return user;

    }//通過匿名函數返回局部變量user

}

console.LOG(fn()());//zhang  通過box()()來直接調用匿名函數返回值

var b=fn();

console.log(b());//zhang 另一種調用匿名函數返回值

通過閉包可以實現函數內的局部變量的累加:

function fn(){

    var num=100;

    return function(){

        num++;

        return num;

    }

}

var b=fn();//獲得函數

//你會發現局部變量num並沒有在內存當中消失

console.log(b());//調用匿名函數

console.log(b());//第二次調用匿名函數,實現累加

由於在閉包所在的作用域返回的局部變量不會被銷毀,所以會佔用內存。過度的使用閉包會迫使性能下降,因此建議大家在有必要的情況下再使用閉包。 

作用域鏈的機制會導致一個問題,在循環中里的匿名函數取得的任何變量都是最後一個值

function fn(){

    var arr=[];

    //i為fn函數中的局部變量。

    for(var i=0;i<3;i++){

        arr.push(function(){

            return i;

        });

    }

    return arr;

}

var b=fn();

for(var i=0;i<b.length;i++){

    console.log(b[i]());//3

}

以上示例輸出的結果均是3,也就是循環結束后i的值。這是因為在for循環的過程當中,數組中的匿名函數並沒有自我執行。當在調用匿名函數的時候,通過閉包獲得的i已經是3了,所以每次輸出的都是3。 

如果想要輸出的結果為0,1,2可以做如下的調整:

function fn(){

    var arr=[];

    for(var i=0;i<3;i++){

        arr.push((function(num){

            //將立即執行函數返回的匿名函數放到數組中。

            //因為num為函數的參數,因此有自己獨立的作用域

            return function(){

                return num;

            };

        })(i));

    }

    return arr;

}

var b=fn();

for(var i=0;i<b.length;i++){

    console.log(b[i]());//0,1,2

}

通過匿名函數的立即執行,將立即執行后返回的函數直接賦值給數組arr。每次循環即將i的值傳遞給num,又因為num在函數中,所以有自己的獨立作用域,因此num得到的值為每次循環傳遞進來的i值,即0,1,2

接下來看一下關於閉包當中的this對象:

this對象指的是什麼,這個要看函數所運行的環境。如果函數在全局範圍內調用 ,函數內的this指向的是window對象。對象中的方法,通過閉包如果運行的環境為window時,則this為window。因為閉包並不是該對象的方法。

var color="red";

function fn(){

    return this.color;

}

var obj={

    color:"yellow",

    fn:function(){

        return function(){//返回匿名函數

            return this.color;

        }

    }

}

console.log(fn());//red  在外部直接調用this為window

var b=obj.fn();//b為window下的變量,獲得的值為obj對象下的fn方法返回的匿名函數

console.log(b());//red  因為是在window環境下運行,所以this指缶的是window

//可以通過call或apply改變函數內的this指向

console.log(b.call(obj));//yellow

console.log(b.apply(obj));//yellow

console.log(fn.call(obj));//yellow

通過變量可以獲得上一個作用域中的this指向

var color="red";

function fn(){

    return this.color;

}

var obj={

    color:"yellow",

    fn:function(){

        var _this=this;//將this賦值給變量_this

        return function(){

            return _this.color;//通過_this獲得上一個作用域中的this指向

        }

    }

}

console.log(fn());//red

var b=obj.fn();

console.log(b());//yellow

可以通過構造方法傳參來訪問私有變量

function Desk(){

    var str="";//局部變量str,默認值為""

    this.getStr=function(){

        return str;

    }

    this.setStr=function(value){

        str=value;

    };

}

var desk=new Desk();

//為構造函數的局部變量寫入值。

desk.setStr("zhangPEiYue");

//獲取構造函數的局部變量

console.log(desk.getStr());//zhangPeiYue

閉包常見的作用

1、模擬塊級作用域(匿名自執行函數)

if(){}for(){}等沒有作用域,所以在其塊內聲明的變量,在外部是可以使用的。

//javaScript沒有塊級作用域的概念

function fn(num){

    for(var i=0;i<num;i++){}

    console.log(i);//在for外部i不會失敗

}

fn(2);

if(true){

    var a=13;

}

console.log(a);//在if定義的變量在外部可以訪問

通過匿名自執行函數可以模擬塊級作用域

 (function(){

        //i在外部就不認識啦

        for(var i=0;i<count;i++){}

  })();

  console.log(i);//報錯,無法訪問

由於外部無法訪問自執行函數內的變量,因此在函數執行完後會立刻被銷毀,在外部無法訪問。從而可有效避免在多人開發時由於全局變量過多而造成的命名衝突問題。另外由於作用域鏈的機制,局部變量要比全局變量的訪問速度更快,可以提升程序的運行速度!

2、對結果進行緩存

寫一個用於實現所有參數和的函數:

var fn=function(){

    var sum=0;

    for(var i=0;i<arguments.length;i++){

        sum+=arguments[i];

    }

    return sum;

}

console.log(fn(1,2));//3

以上函數接收一些number類型的參數,並返回這些參數之和。由於每次傳遞的參數相同,所以返回的結果是一樣的。這樣勢必會造成了一種浪費,在此時咱們可以通過緩存機制來提高這個函數的性能。

var fn=(function(){

    var cache={}//將結果緩存到該對象中

    return function(){

        var str=JSON.stringify(arguments);

        if(cache[str]){//判斷緩存中是否存在傳遞過來的參數,存在直接返回結果,無需計算

            return cache[str];

        }else{//進行計算並返回結果

            var sum=0;

            for(var i=0;i<arguments.length;i++){

                sum+=arguments[i];

            }

            return cache[str]=sum;

        }

    }

})()

上面的示例將計算后的結果緩存到局部變量cache當中,在調用這個函數時,先在緩存中查找,如果找不到,則進行計算,然後將結果放到緩存中並返回,如果找到了,直接返回查找到的值。 

對於前端開發工程師來講,閉包是一個很難弄懂而且十分難征服的一個概念!因為閉包的生成不僅僅與變量的作用域相關而且與變量的生命周期也有着密切的關係。最後我可以肯定的告訴你,閉包在實際開發的過程中應用十分廣泛,所以你必須要掌握它。

先來看一下關於閉包的定義:閉包是指有權訪問另一個函數作用域中的變量的函數。創建閉包的常見方式,就是在一個函數內部創建另一個函數。

//通過閉包可以獲得函數fn的局部變量user

function fn(){

    var user='zhang';

    return function(){

        return user;

    }//通過匿名函數返回局部變量user

}

console.log(fn()());//zhang  通過box()()來直接調用匿名函數返回值

var b=fn();

console.log(b());//zhang 另一種調用匿名函數返回值

通過閉包可以實現函數內的局部變量的累加:

function fn(){

    var num=100;

    return function(){

        num++;

        return num;

    }

}

var b=fn();//獲得函數

//你會發現局部變量num並沒有在內存當中消失

console.log(b());//調用匿名函數

console.log(b());//第二次調用匿名函數,實現累加

由於在閉包所在的作用域返回的局部變量不會被銷毀,所以會佔用內存。過度的使用閉包會迫使性能下降,因此建議大家在有必要的情況下再使用閉包。 

作用域鏈的機制會導致一個問題,在循環中里的匿名函數取得的任何變量都是最後一個值

function fn(){

    var arr=[];

    //i為fn函數中的局部變量。

    for(var i=0;i<3;i++){

        arr.push(function(){

            return i;

        });

    }

    return arr;

}

var b=fn();

for(var i=0;i<b.length;i++){

    console.log(b[i]());//3

}

以上示例輸出的結果均是3,也就是循環結束后i的值。這是因為在for循環的過程當中,數組中的匿名函數並沒有自我執行。當在調用匿名函數的時候,通過閉包獲得的i已經是3了,所以每次輸出的都是3。 

如果想要輸出的結果為0,1,2可以做如下的調整:

function fn(){

    var arr=[];

    for(var i=0;i<3;i++){

        arr.push((function(num){

            //將立即執行函數返回的匿名函數放到數組中。

            //因為num為函數的參數,因此有自己獨立的作用域

            return function(){

                return num;

            };

        })(i));

    }

    return arr;

}

var b=fn();

for(var i=0;i<b.length;i++){

    console.log(b[i]());//0,1,2

}

通過匿名函數的立即執行,將立即執行后返回的函數直接賦值給數組arr。每次循環即將i的值傳遞給num,又因為num在函數中,所以有自己的獨立作用域,因此num得到的值為每次循環傳遞進來的i值,即0,1,2

接下來看一下關於閉包當中的this對象:

this對象指的是什麼,這個要看函數所運行的環境。如果函數在全局範圍內調用 ,函數內的this指向的是window對象。對象中的方法,通過閉包如果運行的環境為window時,則this為window。因為閉包並不是該對象的方法。

var color="red";

function fn(){

    return this.color;

}

var obj={

    color:"yellow",

    fn:function(){

        return function(){//返回匿名函數

            return this.color;

        }

    }

}

console.log(fn());//red  在外部直接調用this為window

var b=obj.fn();//b為window下的變量,獲得的值為obj對象下的fn方法返回的匿名函數

console.log(b());//red  因為是在window環境下運行,所以this指缶的是window

//可以通過call或apply改變函數內的this指向

console.log(b.call(obj));//yellow

console.log(b.apply(obj));//yellow

console.log(fn.call(obj));//yellow

通過變量可以獲得上一個作用域中的this指向

var color="red";

function fn(){

    return this.color;

}

var obj={

    color:"yellow",

    fn:function(){

        var _this=this;//將this賦值給變量_this

        return function(){

            return _this.color;//通過_this獲得上一個作用域中的this指向

        }

    }

}

console.log(fn());//red

var b=obj.fn();

console.log(b());//yellow

可以通過構造方法傳參來訪問私有變量

function Desk(){

    var str="";//局部變量str,默認值為""

    this.getStr=function(){

        return str;

    }

    this.setStr=function(value){

        str=value;

    };

}

var desk=new Desk();

//為構造函數的局部變量寫入值。

desk.setStr("zhangPeiYue");

//獲取構造函數的局部變量

console.log(desk.getStr());//zhangPeiYue

閉包常見的作用

1、模擬塊級作用域(匿名自執行函數)

if(){}for(){}等沒有作用域,所以在其塊內聲明的變量,在外部是可以使用的。

//javaScript沒有塊級作用域的概念

function fn(num){

    for(var i=0;i<num;i++){}

    console.log(i);//在for外部i不會失敗

}

fn(2);

if(true){

    var a=13;

}

console.log(a);//在if定義的變量在外部可以訪問

通過匿名自執行函數可以模擬塊級作用域

 (function(){

        //i在外部就不認識啦

        for(var i=0;i<count;i++){}

  })();

  console.log(i);//報錯,無法訪問

由於外部無法訪問自執行函數內的變量,因此在函數執行完後會立刻被銷毀,在外部無法訪問。從而可有效避免在多人開發時由於全局變量過多而造成的命名衝突問題。另外由於作用域鏈的機制,局部變量要比全局變量的訪問速度更快,可以提升程序的運行速度!

2、對結果進行緩存

寫一個用於實現所有參數和的函數:

var fn=function(){

    var sum=0;

    for(var i=0;i<arguments.length;i++){

        sum+=arguments[i];

    }

    return sum;

}

console.log(fn(1,2));//3

以上函數接收一些number類型的參數,並返回這些參數之和。由於每次傳遞的參數相同,所以返回的結果是一樣的。這樣勢必會造成了一種浪費,在此時咱們可以通過緩存機制來提高這個函數的性能。

var fn=(function(){

    var cache={}//將結果緩存到該對象中

    return function(){

        var str=JSON.stringify(arguments);

        if(cache[str]){//判斷緩存中是否存在傳遞過來的參數,存在直接返回結果,無需計算

            return cache[str];

        }else{//進行計算並返回結果

            var sum=0;

            for(var i=0;i<arguments.length;i++){

                sum+=arguments[i];

            }

            return cache[str]=sum;

        }

    }

})()

上面的示例將計算后的結果緩存到局部變量cache當中,在調用這個函數時,先在緩存中查找,如果找不到,則進行計算,然後將結果放到緩存中並返回,如果找到了,直接返回查找到的值。 

覺得可用,就經常來吧!Javascript技巧 腳本寶典 歡迎評論哦! js技巧,巧奪天工,精雕玉琢。小寶典獻醜了!

脚本宝典总结

以上是脚本宝典为你收集整理的js實例教程-JavaScript中的閉包及應用場景介紹全部内容,希望文章能够帮你解决js實例教程-JavaScript中的閉包及應用場景介紹所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。