關(guān)于this的深入認(rèn)識(shí)

從學(xué)習(xí)前端開始已經(jīng)大概要兩個(gè)月了亮垫,這幾天突然發(fā)現(xiàn)this并沒有想想中這么簡(jiǎn)單,之前很長(zhǎng)一段時(shí)間對(duì)于this的認(rèn)識(shí)停留在它的指向方法上。

  • 當(dāng)以方法的形式調(diào)用時(shí),this指向調(diào)用者
  • 當(dāng)以函數(shù)的形式調(diào)用時(shí)做个,this指向window
  • 當(dāng)以構(gòu)造函數(shù)的形式調(diào)用時(shí),this就是新創(chuàng)建的那個(gè)函數(shù)
  • 而改變this指向的方法有兩種:apply和call

那時(shí)對(duì)this只是一個(gè)簡(jiǎn)單的認(rèn)識(shí)滚局,這么說來也沒有任何理解上的問題居暖。但是學(xué)到后來,發(fā)現(xiàn)this的應(yīng)用光靠這些基礎(chǔ)已經(jīng)遠(yuǎn)遠(yuǎn)不夠了藤肢。

從綁定方式上我姑且把它分為4種方式膝但。

默認(rèn)綁定

  • 獨(dú)立函數(shù)調(diào)用:可以把這條規(guī)則看作是無法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則
  • 獨(dú)立函數(shù)調(diào)用:如果使用了非嚴(yán)格模式,this 會(huì)綁定到全局對(duì)象(window)
  • 獨(dú)立函數(shù)調(diào)用:如果使用嚴(yán)格模式( strict mode ),this 會(huì)綁定到 undefined
  • 這里有一個(gè)微妙但是非常重要的細(xì)節(jié)谤草,雖然 this 的綁定規(guī)則完全取決于調(diào)用位置。
    • 但是只有 foo()運(yùn)行在非 strict mode 下時(shí)莺奸,默認(rèn)綁定才能綁定到全局對(duì)象丑孩;
    • 在嚴(yán)格模式底下foo()會(huì)綁給undefined

多說無用,下面來看代碼.

      var a = 2;
      function foo() {
          console.log( this.a );
      }

      (function(){
        "use strict";
        foo();
      })()

這個(gè)時(shí)候嚴(yán)格模式不會(huì)影響默認(rèn)綁定規(guī)則灭贷,此時(shí)輸出的是2

        function foo() {
          "use strict";
          console.log( this.a );
        }
        var a = 2;
        foo(); 

現(xiàn)在這個(gè)時(shí)候會(huì)報(bào)錯(cuò)温学,a為undefined.

隱式綁定

  • 隱式綁定的規(guī)則是調(diào)用位置是否有上下文對(duì)象,或者說是否被某個(gè)對(duì)象擁有或者包含甚疟。當(dāng)函數(shù)引用有上下文對(duì)象時(shí)仗岖,隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的 this 綁定到這個(gè)上下文對(duì)象

  • 對(duì)象屬性引用鏈中只有最頂層或者說最后一層會(huì)影響調(diào)用位置

      function foo() {
        console.log( this.a );
        }
        var obj = {
            a: 2,
            foo: foo
        };
        obj.foo(); 

毋庸置疑this指向調(diào)用者obj,輸出2

    function foo() {
            console.log( this.a );
        }
        var obj2 = {
            a: 42,
            foo: foo
        };
        var obj1 = {
            a: 2,
            obj2: obj2
        };
        obj1.obj2.foo(); 

這個(gè)時(shí)候this指向obj2览妖,輸出42

  • 一個(gè)最常見的 this 綁定問題就是被隱式綁定的函數(shù)會(huì)丟失綁定對(duì)象轧拄,也就是說它會(huì)應(yīng)用默認(rèn)綁定,從而把 this 綁定到全局對(duì)象或者 undefined 上.(取決于是否是嚴(yán)格模式)
    function foo() {
            console.log( this.a );
        }
        var a = "hello word"; 
        var obj = {
            a: 2,
            foo: foo
        };
        
        var bar = obj.foo; 
        bar(); 

這個(gè)時(shí)候會(huì)發(fā)生隱式丟失讽膏,this指向全局對(duì)象:hello word

  • 參數(shù)傳遞其實(shí)也是一種隱式賦值檩电,因此我們傳入函數(shù)時(shí)也會(huì)被隱式賦值
        function foo() {
            console.log( this.a );
        }

        function doFoo(fn) {
            fn(); 
        }

        var a = "hello word"; 
        var obj = {
            a: 2,
            foo: foo
        };
        
        doFoo( obj.foo ); 

這個(gè)時(shí)候會(huì)發(fā)生隱式丟失,this指向全局對(duì)象:hello word

如果你把函數(shù)傳入語(yǔ)言內(nèi)置的函數(shù)而不是傳入你自己聲明的函數(shù),你會(huì)發(fā)現(xiàn)結(jié)果是一樣的俐末,沒有區(qū)別,比如定時(shí)器的內(nèi)置函數(shù):

        function foo() {
            console.log( this.a );
        }
        
        var a = "hello word"; 
        var obj = {
            a: 2,
            foo: foo
        };
        
        setTimeout( obj.foo, 1000 );  

結(jié)果輸出的仍然是:hello word

顯示綁定

  • 我們不想在對(duì)象內(nèi)部包含函數(shù)引用料按,而想在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù),具體點(diǎn)說,可以使用函數(shù)的 call(..) 和 apply(..) 方法來實(shí)現(xiàn)顯示綁定.
        var a =0;
        function foo() {
            console.log( this.a );
        }
        var obj = {
            a:1
        };
        var obj2 = {
            a:2
        };
        var obj3 = {
            a:3
        };
        foo();
        foo.call( obj );
        foo.apply( obj2 );
        foo.call( obj3 );

如果沒有給foo使用call方法卓箫,foo使用的就是默認(rèn)綁定载矿,foo()輸出0,。使用call apply方法烹卒,輸出分別為1闷盔,2,3

  • 什么是硬綁定:一種顯示綁定的變種
    • 我們來看看這個(gè)顯式綁定變種到底是怎樣工作的甫题。我們創(chuàng)建了函數(shù) bar() ,并在它的內(nèi)部手動(dòng)調(diào)用了 foo.call(obj) ,因此強(qiáng)制把 foo 的 this 綁定到了 obj 馁筐。無論之后如何調(diào)用函數(shù) bar ,它總會(huì)手動(dòng),在 obj 上調(diào)用 foo 坠非。這種綁定是一種顯式的強(qiáng)制綁定敏沉,因此我們稱之為硬綁定。
        var a =1;
        function foo() {
            console.log( this.a );
        }

        var obj = {
            a:2
        };

        var obj_test = {
            a:"test"
        };

        var bar = function() {
            foo.call( obj );
        };
        
        bar(); //2
        setTimeout( bar, 1000 ); // 2
        bar.call( obj_test ); //2   

硬綁定的bar不可能再修改它的this(指的是foo中的this),是不是解決了之前的隱式丟失炎码。(定時(shí)器內(nèi)部this的調(diào)用是獨(dú)立調(diào)用)

-簡(jiǎn)單的輔助綁定函數(shù)bind函數(shù)的作用:返回一個(gè)新的函數(shù)盟迟,并且指定該新函數(shù)的this指向

        function bind(fn, obj) {
            return function() {
                    return fn.apply( obj, arguments );
                };
        }
        
        var obj = {
            a:2
        };
        var obj_test = {
            a:22
        };
        
        
        var bar = bind( foo, obj);
        var b = bar(3); // 2 3 undefined
        console.log( b ); // 5
        bar.call(obj_test,3);//2 3 undefined

有了bind函數(shù),我們可以把經(jīng)過綁定的函數(shù)拿去使用(這樣它就有默認(rèn)值了)

new綁定

  • 我們重新定義一下JS中的“構(gòu)造函數(shù)”潦闲。JavaScript攒菠,構(gòu)造函數(shù)只是一些使用 new 操作符時(shí)被調(diào)用的函數(shù)。它們并不會(huì)屬于某個(gè)類歉闰,也不會(huì)實(shí)例化一個(gè)類辖众。實(shí)際上,它們甚至都不能說是一種特殊的函數(shù)類型和敬,它們只是被 new 操作符調(diào)用的普通函數(shù)而已凹炸。

  • 實(shí)際上并不存在所謂的“構(gòu)造函數(shù)”,只有對(duì)于函數(shù)的“構(gòu)造調(diào)用”

  • 使用 new 來調(diào)用函數(shù)昼弟,或者說發(fā)生構(gòu)造函數(shù)調(diào)用時(shí)啤它,對(duì)于我們的this來說。這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的 this 舱痘。

      function foo(a) {
            this.a = a;
        }
        var bar = new foo(2);
        console.log( bar.a ); // 2

使用 new 來調(diào)用 foo(..) 時(shí)变骡,我們會(huì)構(gòu)造一個(gè)新對(duì)象并把它綁定到 foo(..) 調(diào)用中的 this 上。new 是最后一種可以影響函數(shù)調(diào)用時(shí) this 綁定行為的方法芭逝,我們稱之為 new 綁定塌碌。

綁定的優(yōu)先級(jí)

最后我們來說一說綁定的優(yōu)先級(jí)

new綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定

綁定例外

es6中胖箭頭this指向與我們現(xiàn)在的規(guī)則不一樣

被忽略的this:apply call bind(null) this----> window

柯里化:為函數(shù)去預(yù)綁定參數(shù)

var obj = Object.create(null)

之后如果有機(jī)會(huì)我會(huì)在下面繼續(xù)補(bǔ)充的。铝耻。誊爹。蹬刷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市频丘,隨后出現(xiàn)的幾起案子办成,更是在濱河造成了極大的恐慌,老刑警劉巖搂漠,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迂卢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡桐汤,警方通過查閱死者的電腦和手機(jī)而克,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怔毛,“玉大人员萍,你說我怎么就攤上這事〖鸲龋” “怎么了碎绎?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)抗果。 經(jīng)常有香客問我筋帖,道長(zhǎng),這世上最難降的妖魔是什么冤馏? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任日麸,我火速辦了婚禮,結(jié)果婚禮上逮光,老公的妹妹穿的比我還像新娘代箭。我一直安慰自己,他們只是感情好涕刚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布梢卸。 她就那樣靜靜地躺著,像睡著了一般副女。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚣旱,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天碑幅,我揣著相機(jī)與錄音,去河邊找鬼塞绿。 笑死沟涨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的异吻。 我是一名探鬼主播裹赴,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼喜庞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了棋返?” 一聲冷哼從身側(cè)響起延都,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎睛竣,沒想到半個(gè)月后晰房,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡射沟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年殊者,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片验夯。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猖吴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挥转,到底是詐尸還是另有隱情海蔽,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布扁位,位于F島的核電站准潭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏域仇。R本人自食惡果不足惜刑然,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望暇务。 院中可真熱鬧泼掠,春花似錦、人聲如沸垦细。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)括改。三九已至腻豌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘱能,已是汗流浹背吝梅。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惹骂,地道東北人苏携。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像对粪,于是被迫代替她去往敵國(guó)和親右冻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子装蓬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持牍帚,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠跪但,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 6,926評(píng)論 15 54
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理履羞,服務(wù)發(fā)現(xiàn),斷路器屡久,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 1. this之謎 在JavaScript中忆首,this是當(dāng)前執(zhí)行函數(shù)的上下文。因?yàn)镴avaScript有4種不同的...
    百里少龍閱讀 994評(píng)論 0 3
  • 特別說明,為便于查閱筛欢,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 690評(píng)論 0 1
  • 與其他語(yǔ)言相比浸锨,函數(shù)的this關(guān)鍵字在JavaScript中的表現(xiàn)略有不同,此外版姑,在嚴(yán)格模式和非嚴(yán)格模式之間也會(huì)有...
    codingC閱讀 572評(píng)論 0 0