JavaScript的因為所以

huang發表於2016-12-09

  各位看官,樓主開始說過寫幾篇部落格,這是這個系列的最後一集。吾以為:瞭解JavaScript的身世之謎,掌握其近乎心想事成的變數系統,瞭解其解析執行的偷樑換柱之法,熟悉布大師迂迴曲折的OOP實現。那你離height level也不遠了。當然,要想height level還要再掌握兩個常常被各位園友掛在嘴邊的東西:this與閉包。this是什麼鬼?閉包又是什麼鬼?照本宣科的概念,這裡不說,我們只聊“因為所以”。廢話少說,開聊!

this是什麼鬼?

  this這玩兒稱呼為鬼一點不為過,好多小白一看滿屏都是this的指令碼瞬間眩暈。看樣子有點像Java、C#之類的this,但憑直覺好像又超越了Java、C#的this,看得是隱隱約約、似懂非懂。各種度娘、G哥大部分得到的都是照本宣科的解析。用心的會記下並研究的,無心的大大咧咧過目而已。於是乎,好多老鳥都沒徹底搞清楚this是什麼鬼。要想了解this是什麼鬼,那得先了解這鬼是怎麼來的。

  話說JavaScript的設計初衷是過程式的,後面布大師為了緊跟時代潮流,迂迴曲折地實現OOP,為此引入了this來表示例項物件。OOP是實現,但是JavaScript的世界從此多了一個this。this在應用於JavaScript的OOP時候,表示的是例項本身。但是如果我寫的JavaScript並不需要new物件,而是隨意到處寫了this,那這個時候this代表什麼?真所謂填一坑挖一坑啊!有坑得填啊,於是,布大師又想摺子給這個this賦予意義了:當this應用於OOP的時候,它表示例項本身;而當this應用於非OOP的時候則表示this所在元素的歸屬物件。這話說來說去還是有點抽象,看程式碼最實在:

1)當this在function中,但是funciton只是過程式函式

    <script>
        /**解析:
         *test在這裡只是個過程式的函式,沒有玩OOP
         *呼叫test函式列印this,那這裡的this指的就是test函式的歸屬
         *而test函式是歸屬到當前Window物件上的
         * ****/
       function test(){
           console.log(this); //結果是 Window物件
       }
       test();
    </script>

2)當this在某個非例項化的物件中

   <script>
        /**解析:
         *這裡的this被定義一個名為f的函式中
         *f函式歸屬的是obj物件
         *結果:this代表obj物件
         * ****/
        var obj={
            a:123,
            f:function(){
                console.log(this);//結果 是obj物件
                console.log(this.a);//結果是123
            }
        };
        console.log(obj.f());//結果
    </script>

3)當this應用於OOP的玩法中

    <script>
        /**解析:
         *clazz是一個類的建構函式,用於建立clazz的例項物件
         *this在這裡就表示每一個new出來的物件
         * ****/
        function clazz(a,b){
            this.a=a;
            this.b=b;
            this.print=function(){
                console.log(this.a+this.b);
            };
        }
        var c1=new clazz(1,1);
        c1.print(); //列印:2
        var c2=new clazz(2,2);
        c1.print(); //列印:4
    </script>

4)當this被偷樑換柱

    <script>
        /**解析:
         *利用call或者apply讓f函式執行期間的this指向另一個物件
         * ****/
        var obj={
            a:123,
            f:function(){
                console.log(this);//結果 是obj物件
                console.log(this.a);//結果是 undefined
            }
        };
        //利用call或者apply讓f函式執行期間,將this換成當前window
        obj.f.call(this);
    </script>

閉包是什麼鬼?

  我們們還是廢話少說,按套路,先了解這個所謂的閉包是怎麼來的。全世界(寫程式碼的人)都知道,像c、java、c++這些言語都有一套一套嚴格的語法,特別像資料型別、函式的定義都有自己規則,不是你想怎麼寫就寫的。但是JavaScript這玩兒,被布大師設計得你想怎麼寫就怎麼寫,竟然可以函式裡面再定義函式,可見自由度之大。你再看看java、c++能這樣幹嘛?自由是自由了,但是這玩法引出了一個問題:但凡大學裡認真念過點書的鞋同都知道,函式是基於棧執行的,如果函式巢狀函式,子函式又引用了父函式裡定義的成員,當父函式已經over的時候,按常規套路,父函式出棧了,它定義的成員也應該被Over了,如果此時子函式還活著,那它引用的父函式變數又不見了,那子函式就沒法用了。於是乎,布大師又不得不給這個bug做補丁,閉包這玩兒就出生了。那我們們通俗給閉包來個定義吧:

  閉包:活著的人從死去的人那裡偷來了東西,讓那些東西不隨死去的人而消失。活著的人擁有了這些東西,這些東西的壽命也因此邊長了。這是JavaScript為了應對天馬行空的自由度產生的bug而打的補丁!

  這比如雖然有點不雅,但也只是為了看官便於理解,請勿介意。好,我們們還是看看程式碼分析:

    <script>
        function oldMan(){
            var money=999999;// 老人的財富
            //老人有一個年輕的兒子
            return function young(){
                console.log("兒子要花老子的錢"+money+"美刀");
            }
        }
        var y=oldMan();//老人將兒子放出來之後就掛了,oldMan函式執行完成,出棧了!!
        y();//兒子開始活動了,兒子竟然有老人的錢
    </script>

  看官,不知道你看了這寥寥幾十字的通俗解法,是否還對那個所謂的閉包還懷抱敬畏呢!

  

  如果你認真看這寥寥幾篇的通俗博文,我相信你對JavaScript的認識肯定是另一個階梯。當然要想在前端立足,僅僅掌握JavaScript還不足以混飯,你還得懂HTML、CSS。樓主打算接下來就這兩個知識再聊上幾篇。如有興趣,請留意!其他JavaScript的問題,也歡迎一起學習探討!

 

相關文章