作用域及閉包

1、兩個(gè)不同的函數(shù)各自申明了同一個(gè)變量,那么該變量只在各自的函數(shù)體內(nèi)起作用。
2、由于JavaScript的函數(shù)可以嵌套,此時(shí),內(nèi)部函數(shù)可以訪問外部函數(shù)定義的變量,反過來則不行。
3、變量提升,
4、全局作用域( window )
5、局部作用域:for if else 不能創(chuàng)造作用域
eg:for循環(huán)中用var定義的i,在for循環(huán)外部,依舊能夠訪問到;相反,用 let 可以實(shí)現(xiàn)塊級(jí)作用域。
6、ES6中,表示常量的const也有塊級(jí)作用域
7、ES6解構(gòu):一個(gè)對(duì)象中取出若干屬性,一個(gè)數(shù)組中取出若干到元素
8、map():給數(shù)組的每一項(xiàng)進(jìn)行相同的操作,得到一個(gè)新數(shù)組,是操作后得到的數(shù)組

          把Array的所有數(shù)字轉(zhuǎn)為字符串:
          var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
          arr.map(String);   // ['1', '2', '3', '4', '5', '6', '7', '8', '9']

·
字符串轉(zhuǎn)成數(shù)字為什么不行?


        var arr = ['1', '2', '3'];
        arr.map(parseInt);  //  1,NaN,NaN

        正確解析:
        由于map()接收的回調(diào)函數(shù)可以有3個(gè)參數(shù):callback(currentValue, index, array),通常我們僅需要第一個(gè)參數(shù),而忽略了傳入的后面兩個(gè)參數(shù)。不幸的是,parseInt(string, radix)沒有忽略第二個(gè)參數(shù),導(dǎo)致實(shí)際執(zhí)行的函數(shù)分別是:
        parseInt('0', 0); // 0, 按十進(jìn)制轉(zhuǎn)換
        parseInt('1', 1); // NaN, 沒有一進(jìn)制
        parseInt('2', 2); // NaN, 按二進(jìn)制轉(zhuǎn)換不允許出現(xiàn)2
        可以改為:
        arr.map(Number);
        因?yàn)镹umber(value)函數(shù)僅接收一個(gè)參數(shù)。

        

9、reduce() : 把一個(gè)函數(shù)作用在一個(gè)Array的 [ x1, x2, x3... ] 上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù),reduce()把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算

       a ) 對(duì)一個(gè)Array求和,就可以用reduce實(shí)現(xiàn):
       var arr = [1, 3, 5, 7, 9];
        arr.reduce(function (x, y) {
              return x + y;
        }); // 25

        b) 要把[1, 3, 5, 7, 9]變換成整數(shù)13579,reduce()也能派上用場(chǎng):
        var arr = [1, 3, 5, 7, 9];
        arr.reduce(function (x, y) {
            return x * 10 + y;
        }); // 13579
 
        

10、filter() : 從數(shù)組中,篩選出想要的數(shù)據(jù),返回組成新的數(shù)組

        a)   數(shù)組去重
        arr.filter( function(element,index,self){
                return  self.indexOf(element) === index
        } )

11、sort():默認(rèn)轉(zhuǎn)成字符串后,再進(jìn)行比較。導(dǎo)致 [1,2,10,20] 的排序結(jié)果為【1,10,2,20】,解決如下:

      arr.sort(function(x,y){
            if(x>y){
                return 1;
            }  else  if(x==y){
                return 0;
            }  else{
                return -1;
            }  
      })

并且,sort() 會(huì)改變?cè)瓟?shù)組

12、閉包實(shí)例1:

 function outter(){
      var sky="blue";
      function inner(){
            console.log(sky);
      }
     return inner;
}
var result=outter();
result();    //"blue"

閉包:

閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù),創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),通過另一個(gè)函數(shù)訪問這個(gè)函數(shù)的局部變量,利用閉包可以突破作用鏈域,將函數(shù)內(nèi)部的變量和方法傳遞到外部。

閉包的特性:

1.函數(shù)內(nèi)再嵌套函數(shù)
2.內(nèi)部函數(shù)可以引用外層的參數(shù)和變量
3.參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收
上面代碼就包含一個(gè)簡(jiǎn)單的閉包:outter函數(shù)的返回值是一個(gè)函數(shù),即inner。inner在outter內(nèi)部,理所當(dāng)然能訪問到局部變量sky,但當(dāng)inner作為outter的返回值賦給outter外的全局變量時(shí),神奇的事情發(fā)生了:在全局作用域中訪問到了sky,這就是閉包。

原理:

每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境,當(dāng)一個(gè)函數(shù)被執(zhí)行時(shí),它的執(zhí)行環(huán)境就會(huì)被推入環(huán)境棧,其活動(dòng)對(duì)象(存儲(chǔ)環(huán)境中定義的變量及函數(shù))加入作用域鏈中,一旦函數(shù)執(zhí)行完,棧將其環(huán)境彈出,活動(dòng)對(duì)象被銷毀。·

對(duì)于上面的例子來說,outter執(zhí)行完之后將返回inner給了result,outter的執(zhí)行環(huán)境從環(huán)境棧彈出,控制權(quán)交給全局環(huán)境,outter的活動(dòng)對(duì)象理應(yīng)被銷毀。但此時(shí)inner已經(jīng)存儲(chǔ)在全局活動(dòng)對(duì)象中了,同時(shí)inner需要訪問sky,所以outter的活動(dòng)對(duì)象沒有被銷毀,即使result執(zhí)行完畢,outter的活動(dòng)對(duì)象依然存在于作用域鏈中,只有當(dāng)result被銷毀

閉包優(yōu)點(diǎn):

能在一個(gè)函數(shù)外訪問函數(shù)中的局部變量,把這些變量用閉包的形式放在函數(shù)中便能避免全局作用域污染。

閉包缺點(diǎn):

  • 閉包將函數(shù)的活動(dòng)對(duì)象維持在內(nèi)存中,過度使用閉包會(huì)導(dǎo)致內(nèi)存占用過多;
  • 閉包只能取得外部函數(shù)中任何變量的最后一個(gè)值,在使用循環(huán)且返回的函數(shù)中帶有循環(huán)變量時(shí)會(huì)得到錯(cuò)誤結(jié)果;
  • 當(dāng)返回的函數(shù)為匿名函數(shù)時(shí),注意匿名函數(shù)中的this指的是window對(duì)象。
    function counter () {  
        var n = 0;  
        return {  
            count:function(){return n++;},  
            reset:function(){n = 0;}  
        }  
     }  
    var c = counter();
    var d = counter();  // 每創(chuàng)建一個(gè)實(shí)例,他們的n都互不影響
    c.count()    //0  
    d.count()    //0  
    c.reset()      //reset()和count()共享  
    d.count()     //1  
    c.count()     //0  
<script>
    function A(){
        var x = 1;
        return function(){
            x++;
            console.log(x);
        }
    }
    var m1 = A();//第一次執(zhí)行A函數(shù)
    m1();//2
    m1();//3
    var m2 = A();//第二次執(zhí)行A函數(shù)
    m2();//2
    m1();//4
</script>

常見的內(nèi)存泄漏方式:

1、意外的全局變量

a)函數(shù)里未用var/let來聲明變量
b)在函數(shù)中通過this賦予變量,在函數(shù)中,this指向window

2、定時(shí)器setTimeout setInterval以及回調(diào)函數(shù)

當(dāng)不需要setInterval或者setTimeout時(shí),定時(shí)器沒有被clear,定時(shí)器的回調(diào)函數(shù)以及內(nèi)部依賴的變量都不能被回收,造成內(nèi)存泄漏。
比如:vue使用了定時(shí)器,需要在beforeDestroy 中做對(duì)應(yīng)銷毀處理。js也是一樣的。

3、閉包(在全局作用域上保留著閉包局部變量的引用)
4、循環(huán)引用的變量或者對(duì)象
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、引言 最近在刷leetcode題的時(shí)候,遇到一個(gè)求最長回文子串的題目,于是,我寫了如下的代碼: 哎呀,寫了兩個(gè)...
    文哥的學(xué)習(xí)日記閱讀 14,514評(píng)論 6 32
  • 這次主要用例子解釋一下什么是作用域,什么是自由變量,什么是閉包,因?yàn)橛靡痪湓捀爬▽?shí)在是概括不出來,歡迎有大神可以一...
    石燕平_Leo閱讀 872評(píng)論 2 2
  • still, 你的不知道的js里講的很清楚了 如果查找的目的是對(duì)變量進(jìn)行賦值,則進(jìn)行LHS查詢;如果查找的目的是獲...
    葉子是會(huì)飛翔的翅膀閱讀 239評(píng)論 0 0
  • 作用域:1. 全局 作用域鏈:函數(shù)嵌套 閉包(Closure)函數(shù)嵌套,在內(nèi)嵌函數(shù)中使用到外部函數(shù)的局部變量(即內(nèi)...
    dwy_interesting閱讀 223評(píng)論 0 0
  • 來談一下我的舍友小蛇吧。 小蛇是我大學(xué)四年的舍友,畢業(yè)之后也一直和她合租著房子,我們倆也算有緣吧,都是一個(gè)星座的,...
    不安分的菠蘿閱讀 197評(píng)論 0 0

友情鏈接更多精彩內(nèi)容