成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

聊一下JS中的作用域scope和閉包c(diǎn)losure

Alliot / 1638人閱讀

摘要:嚴(yán)格的說,在也存在塊級作用域。如果多帶帶調(diào)用函數(shù),比如,此時,該函數(shù)的指向全局對象,也就是??拥⌒∶髟诜椒▋?nèi)部一開始就捕獲用而不是小明指向參數(shù)為空另一個與類似的方法是,唯一區(qū)別是把參數(shù)打包成再傳入把參數(shù)按順序傳入。

先上幾道面試題練練手
    var bb = 1;
    function aa(bb) {
      bb = 2;
      alert(bb);
    }
    aa(bb);
    alert(bb);
    var a="undefined";
    var b="false";
    var c="";
    function assert(aVar){
        if(aVar)     
            alert(true);
        else  
            alert(false);
    }
    assert(a);
    assert(b);
    assert(c);
    function Foo() {
        var i = 0;
        return function() {
            console.log(i++);
        };
    }
    Foo();
    var f1 = Foo(), f2 = Foo();
    
    f1();
    f1();
    f2();
    var foo = true;
    if (foo) {
        let bar = foo * 2;
        bar = something( bar );
        console.log( bar );
    }
    console.log( bar );
    var foo = true;
    if (foo) {
        var a = 2;
        const b = 3; //僅存在于if的{}內(nèi)
        a = 3;
        b = 4; // 出錯,值不能修改
    }
    console.log( a ); // 3
    console.log( b ); // ReferenceError!
閉包的深度遞進(jìn)

在JavaScript中,作用域是基于函數(shù)來界定的。也就是說屬于一個函數(shù)內(nèi)部的代碼,函數(shù)內(nèi)部以及內(nèi)部嵌套的代碼都可以訪問函數(shù)的變量。

順便講講常見的兩種error,ReferenceError和TypeError。如上圖,如果在bar里使用了d,那么經(jīng)過查詢都沒查到,那么就會報一個ReferenceError;如果bar里使用了b,但是沒有正確引用,如b.abc(),這會導(dǎo)致TypeError。

嚴(yán)格的說,在JavaScript也存在塊級作用域。如下面幾種情況:

with

    var obj = {a: 2, b: 2, c: 2};
    with (obj) { //均作用于obj上
      a = 5;
      b = 5;
      c = 5;  
    }

let

let是ES6新增的定義變量的方法,其定義的變量僅存在于最近的{}之內(nèi)。如下

    var foo = true;
    if (foo) {
        let bar = foo * 2;
        bar = something( bar );
        console.log( bar );
    }
    console.log( bar ); // ReferenceError

const

與let一樣,唯一不同的是const定義的變量值不能修改。如下:

    var foo = true;
    if (foo) {
      var a = 2;
      const b = 3; //僅存在于if的{}內(nèi)
      a = 3;
      b = 4; // 出錯,值不能修改
    }
    console.log( a ); // 3
    console.log( b ); // ReferenceError!

了解這些了后,我們來聊聊閉包。什么叫閉包?簡單的說就是一個函數(shù)內(nèi)嵌套另一個函數(shù),這就會形成一個閉包。這樣說起來可能比較抽象,那么我們就舉例說明。但是在距離之前,我們再復(fù)習(xí)下這句話,來,跟著大聲讀一遍,“無論函數(shù)是在哪里調(diào)用,也無論函數(shù)是如何調(diào)用的,其確定的詞法作用域永遠(yuǎn)都是在函數(shù)被聲明的時候確定下來的”。
來,下面我們看一個經(jīng)典的閉包的例子:

     for (var i=1; i<=9; i++) {
         setTimeout( function timer(){
         console.log( i );
         },1000 );
     }

運(yùn)行的結(jié)果是啥捏?你可能期待每隔一秒出來1、2、3...10。那么試一下,按F12,打開console,將代碼粘貼,回車!咦???等一下,擦擦眼睛,怎么會運(yùn)行了10次10捏?這是腫么回事呢?咋眼睛還不好使了呢?不要著急,等我給你忽悠!
現(xiàn)在,再看看上面的代碼,由于setTimeout是異步的,那么在真正的1000ms結(jié)束前,其實10次循環(huán)都已經(jīng)結(jié)束了。我們可以將代碼分成兩部分分成兩部分,一部分處理i++,另一部分處理setTimeout函數(shù)。那么上面的代碼等同于下面的:

    // 第一個部分
    i++; 
    i++; // 總共做10次
              
    // 第二個部分
    setTimeout(function() {
        console.log(i);
    }, 1000);
    
    setTimeout(function() {
       console.log(i);
    }, 1000); // 總共做10次

看到這里,相信你已經(jīng)明白了為什么是上面的運(yùn)行結(jié)果了吧。那么,我們來找找如何解決這個問題,讓它運(yùn)行如我們所料!

因為setTimeout中的匿名函數(shù)沒有將i作為參數(shù)傳入來固定這個變量的值,讓其保留下來, 而是直接引用了外部作用域中的i, 因此i變化時,也影響到了匿名函數(shù)。其實要讓它運(yùn)行的跟我們料想的一樣很簡單,只需要將setTimeout函數(shù)定義在一個多帶帶的作用域里并將i傳進(jìn)來即可。如下:

    for (var i=1; i<=9; i++) {
         (function(){
          var j = i;
          setTimeout( function timer(){
               console.log( j );
          }, 1000 );
         })();
     }

不要激動,勇敢的去試一下,結(jié)果肯定如你所料。那么再看一個實現(xiàn)方案:

    for (var i=1; i<=9; i++) {
         (function(j){
             setTimeout( function timer(){
                 console.log( j );
             }, 1000 );
         })( i );
     }

啊,居然這么簡單啊,你肯定在這么想了!那么,看一個更優(yōu)雅的實現(xiàn)方案:

    for (let i=1; i<=9; i++) {
         setTimeout( function timer(){
             console.log( i );
         }, 1000 );
     }

咦?!腫么回事呢?是不是出錯了,不著急,我這里也出錯了。這是因為let需要在strict mode中執(zhí)行。具體如何使用strict mode模式,自行谷歌吧

再整理一些面試題吧
    var x = 1;
    var y = 0;
    var z = 0;
    function add(n){n=n+1;}
    y = add(x);
    function add(n){n=n+3;}
    z = add(x);
    console.log(x,y,z);
    //兩個函數(shù)沒有返回值,打印1 undefined undefined
    function getAge() {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
    
    var xiaoming = {
        name: "小明",
        birth: 1990,
        age: getAge
    };
    
    xiaoming.age(); // 25, 正常結(jié)果
    getAge(); // NaN

多帶帶調(diào)用函數(shù)getAge怎么返回了NaN?請注意,我們已經(jīng)進(jìn)入到了JavaScript的一個大坑里。JavaScript的函數(shù)內(nèi)部如果調(diào)用了this,那么這個this到底指向誰?

答案是,視情況而定!如果以對象的方法形式調(diào)用,比如xiaoming.age(),該函數(shù)的this指向被調(diào)用的對象,也就是xiaoming,這是符合我們預(yù)期的。

如果多帶帶調(diào)用函數(shù),比如getAge(),此時,該函數(shù)的this指向全局對象,也就是window。
坑爹啊!

    var xiaoming = {
        name: "小明",
        birth: 1990,
        age: function () {
            var that = this; // 在方法內(nèi)部一開始就捕獲this
            function getAgeFromBirth() {
                var y = new Date().getFullYear();
                return y - that.birth; // 用that而不是this
            }
            return getAgeFromBirth();
        }
    };
    
    xiaoming.age(); // 25
    function getAge() {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
    
    var xiaoming = {
        name: "小明",
        birth: 1990,
        age: getAge
    };
    
    xiaoming.age(); // 25
    getAge.apply(xiaoming, []); // 25, this指向xiaoming, 參數(shù)為空

另一個與apply()類似的方法是call(),唯一區(qū)別是:

apply()把參數(shù)打包成Array再傳入;

call()把參數(shù)按順序傳入。

    function foo() {
        var x = "Hello, " + y;
        alert(x);//hello,undefined
        var y = "Bob";
    }
    foo();

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80067.html

相關(guān)文章

  • JavaScript中的閉包

    摘要:閉包引起的內(nèi)存泄漏總結(jié)從理論的角度將由于作用域鏈的特性中所有函數(shù)都是閉包但是從應(yīng)用的角度來說只有當(dāng)函數(shù)以返回值返回或者當(dāng)函數(shù)以參數(shù)形式使用或者當(dāng)函數(shù)中自由變量在函數(shù)外被引用時才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經(jīng)典書籍等書中給出的概念,這些概念雖然...

    HmyBmny 評論0 收藏0
  • JavaScript基礎(chǔ)系列---閉包及其應(yīng)用

    摘要:所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實體。所以本文中將以維基百科中的定義為準(zhǔn)即在計算機(jī)科學(xué)中,閉包,又稱詞法閉包或函數(shù)閉包,是引用了自由變量的函數(shù)。 閉包(closure)是JavaScript中一個神秘的概念,許多人都對它難以理解,我也一直處于似懂非懂的狀態(tài),前幾天深入了解了一下執(zhí)行環(huán)境以及作用域鏈,可戳查看詳情,而閉包與作用域及作用域鏈的關(guān)系密不可分,所...

    leoperfect 評論0 收藏0
  • 老生常談之閉包(你不可不知的若干知識點(diǎn))

    摘要:閉包是什么這是一個在面試的過程中出現(xiàn)的概率為以上的問題,也是我們張口就來的問題。文章推薦我們面試中在被問到閉包這個問題是要注意的幾點(diǎn)閉包的延伸,讓面試變得 閉包是什么?這是一個在面試的過程中出現(xiàn)的概率為60%以上的問題,也是我們張口就來的問題。但是我們往往發(fā)現(xiàn),在面試的過程中我們的回答并不那么讓面試官滿意,我們雖然能張口說出一些但是卻不能系統(tǒng)的對這個問題進(jìn)行回答。面試官希望加入自己團(tuán)隊...

    daydream 評論0 收藏0
  • 【闖關(guān)模式】作用、鏈閉包

    摘要:前言這個系列是翻譯自中的直接闖關(guān)作用域鏈和閉包作用域,作用域鏈,閉包和垃圾回收機(jī)制都有一個共同點(diǎn)學(xué)了就忘閉包到底是干啥的啥時候發(fā)生垃圾回收機(jī)制作用域鏈到底是啥這個教程讓你發(fā)現(xiàn)這些都是小意思。 前言 這個系列是翻譯自 nodeschool.io中的 scope-chains-closures 直接闖關(guān): npm install -g scope-chains-closures scope...

    shinezejian 評論0 收藏0
  • javaScript作用閉包

    摘要:閉包里面保存的變量只有被方法引用了的變量這個例子里,閉包里只有并沒有。那最后來說說的問題閉包到底是什么閉包是一個作用域。鑒于在的調(diào)試窗口,是放在下面的那閉包這個作用域是個什么范圍被后代方法子方法,孫子方法。。。 首先給js的作用域這個話題打標(biāo)簽:2,var, 全局變量,局部變量,函數(shù),undefined, 作用域提升,賦值不會提升,ReferenceError, 同名覆蓋。打完標(biāo)簽之后...

    Reducto 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<