<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在理解this綁定之前,先要理解調用位置。 我們可以通過瀏覽器的調試工具來查看調用棧。 在第一行代碼錢插入一條debugger;語句,運行代碼,可以看到當前位置函數的調用列表(call stack),找到棧中的第二個元素,就是真正的調用位置。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603eede32f.jpg "") 聲明:下面很多內容使用的是《You Don’t Kown JavaScript》中的思想。 this的綁定對象———先找到函數的執行過程中調用位置,然后判斷應用了下面四條綁定規則的哪一條。 **this的四種綁定規則:** 1、默認綁定 2、隱式綁定 3、顯示綁定 4、new綁定 ### 默認綁定 首先從默認綁定開始,在無法應用其他規則時的默認規則,通常是獨立函數調用。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef013d0.jpg "") 在調用add()時,應用了默認綁定,this指向全局對象(非嚴格模式下),嚴格模式下,this指向undefined。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef15741.jpg "") ### 隱式綁定 調用位置是否有上下文對象/被某個對象“擁有”或“包含”(但不是真正的擁有) ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef26531.jpg "") add函數聲明在外部,嚴格來說并不屬于instance,但是在調用add時,調用位置會使用instance的上下文來引用函數,隱式綁定會把函數調用中的this(即此例add函數中的this)綁定到這個上下文對象(即此例中的instance) 需要注意的是:對象屬性鏈中只有最后一層會影響到調用位置。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef34f44.jpg "") 隱式綁定有一個問題,就是隱式丟失(在第一篇中提到過的綁定丟失的問題) ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef47374.jpg "") 綁定丟失的另一種情況發生在回調函數中。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef56fc6.jpg "") 我的理解是:fun(instance.add),做了一個隱式的賦值操作,var fn = instance.add,然后運行fn();這樣就跟上面的例子一樣了。 本來看書上說做了一個隱式賦值,自己并未理解,但是想努力地說清楚這個問題,于是自己思考,反而與書中不謀而合,本來沒明白他說得隱式賦值操作是什么。 到這個地方,就不得不提起setTimeout了。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603edad1d6.jpg "") setTimeout(person1.grow, 100); //undefined 實話說,我原本是一個似理解又不是很理解的一個狀態,現在算是豁然開朗了。 setTimeout(fn,delay){ fn(); } 與上面的例子其實是一樣的。 除了上面的兩種情況以外,還有一種情況this的行為會出乎我們意料:調用回調函數的函數可能會修改this,在一些流行的JS庫中事件處理器常會把毀掉函數的this強制綁定到觸發事件的DOM元素上。(關于這個問題,暫未研究,因此也不予舉例說明) ### 顯式綁定 顯式綁定就是通過call()或者apply()函數指定this的綁定對象。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef7e55f.jpg "") 不過顯式綁定還是未能解決綁定丟失的問題,如下面的代碼,結果依舊為50。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603ef8f9ae.jpg "") 因此我們引入“硬綁定”這個概念。注意下面例子中劃紅色橫線的部分,根據書中說硬綁定之后,無法再修改它的this值,應該是我紅色寫得部分,即(fn.call(instance))這種寫法,無論fun.call()第一個參數傳什么,都不能再改變它的this值,相反,我例子中的寫法,是需要和外圍配合的,即需要傳什么this值,就去指定它。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603efa0006.jpg "") **硬綁定**是能夠解決綁定丟失的問題的,如下: ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603efb05f7.jpg "") ES5中提供了內置的方法進行硬綁定,在第一篇this詞法的博文中也提及過,即bind. Function.prototype.bind,用法如下: ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603efd2b8f.jpg "") 上面的兩句代碼可以用那一句紅色的代碼代替,需要注意的是: bind是function對象的方法,千萬不能寫成add().bind(instance);因為這個add()函數中返回值是undefined,而undefined顯然是沒有bind方法的。 如果是下面這樣,那顯然又是不一樣的。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603efe3c34.jpg "") 這兒使用的是add().bind,原因也很簡單,因為add()返回的是一個函數。 **API調用的“上下文”** ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603eff2efc.jpg "") 順便了解一下forEach的用法。forEach是一個JavaScript擴展到ECMA-262標準;因此它可能不存在在標準的其他實現。為了使它工作,可以增加下面的代碼: ~~~ if(!Array.prototype.forEach) { Array.prototype.forEach = function(fun) { varlen = this.length; if(typeoffun != "function"){ thrownewTypeError(); } varself= arguments[1]; for(vari = 0; i < len; i++) { if(i inthis) fun.call(self, this[i], i, this); } }; } ~~~ 對每個函數成員執行callback函數,并且可以指定this的值。 ### new綁定 javaScript和C++不一樣,并沒有類,在javaScript中,構造函數只是使用new操作符時被調用的函數,這些函數和普通的函數并沒有什么不同,它不屬于某個類,也不可能實例化出一個類。任何一個函數都可以使用new來調用,因此其實并不存在構造函數,而只有對于函數的“構造調用”。 使用new來調用函數,會自動執行下面的操作: 1、創建一個新對象 2、這個新對象會被執行[[原型]]連接 3、這個新對象會綁定到函數調用的this 4、如果函數沒有返回其他對象,那么new表達式中的函數調用會自動返回這個新對象。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f00fdb0.jpg "") instance綁定到Add的this。 優先級 了解了函數調用中this綁定的四條規則之后,需要做的就是找到函數的調用位置并判斷應當應用哪條規則。當某個調用位置可以應用多條規則時,就需要了解這些綁定規則的優先級。 關于優先級的問題,不再細說,只給出結果,只說下顯式綁定和new綁定優先級。 默認綁定 < 隱式綁定 < 顯式綁定 < new綁定 new和call/apply無法一起使用,因此無法通過測試new add.call(obj)的方式來直接進行測試,但是可以使用硬綁定來測試他們的優先級 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f02112b.jpg "") 當硬綁定函數被new調用時,會使用新創建的this替換硬綁定的this。當然再次使用硬綁定,我們還是可以將this綁定在其它的對象上的。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f081656.jpg "") 總結一下,判斷this的步驟: 1.函數是否在new中調用,即是否是new綁定,如果是new綁定,那么this綁定的是新創建的對象。 2.函數是否是顯示綁定(call,apply,bind),如果是,那么this綁定的是指定的對象 3.函數是否在某個上下文對象中調用,即隱式綁定,較多的是在某個對象中調用,如果是的話,this綁定的是那個上下文對象。 4.如果以上規則都不能應用,那么就是默認綁定,在嚴格模式下,this被綁定到undefined,在非嚴格模式下,綁定到全局對象。 最后,我們來看下 ### 綁定例外 : **1、被忽略的this** 如果我們將null或者是undefined作為this的綁定對象傳入call、apply或者是bind,這些值在調用時會被忽略,實際應用的是默認綁定規則。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f099d06.jpg "") 實際應用的是默認綁定規則,add中的this被綁定到了全局對象(非嚴格模式) 在使用apply()來“展開”一個數組,并當做一個參數傳入一個函數,或使用bind()對參數進行柯里化(即預先設置好一些參數),bind和apply都需要傳入一個參數作為this的綁定對象,即使函數不關心this的值,仍然需要傳入一個占位值,這是null或者是undefined可能就是一個不錯的選擇。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f0ab07b.jpg "") 上面說可能是一個不錯的選擇,那么也就是說這其實并不是一個比較好的做法,因為如果某個函數確實使用了this,那默認綁定規則會把this綁定到全局對象,這就可能會產生難以預料的問題。 一個更安全的做法是傳入一個特殊的對象,把this綁定到這個對象則不會對程序產生副作用,即使某個函數中使用了this,也不會影響到全局對象。 首先創建一個空對象:Φ(數學中的空集符號,既能表達意思,而且不易重名) ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f0c17b7.jpg "") **2、間接引用** 可能會無意間創建一個函數的“間接引用”,在這種情況下,調用這個函數會引用默認綁定規則。間接引用最容易在賦值時發生。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f0d5f2a.jpg "") 這種情況下調用位置是add(),而不是example.add()或者是instance.add(),應用默認綁定。 想加個debugger看看,然后引發出了一個新問題,如下:期望得到解答。 ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f0e4dd2.jpg "") **3、軟綁定** 硬綁定可以將this的值強制綁定到指定的對象,防止函數調用應用默認綁定規則,但是,硬綁定同樣會帶來一個靈活性的問題,用硬綁定之后就無法使用隱式綁定或者顯式綁定去修改this的值,只能通過new或者重寫硬綁定。 如果給默認綁定指定一個全局對象和undefined/null以外的值,那就可以實現和硬綁定相同的效果,同時可以保留隱式綁定或者顯式綁定修改this的能力。 softBind()的原理和bind()類似,會對指定的函數進行封裝,首先檢查調用時的this,如果this綁定到全局對象或者是undefined,那么就把指定的默認對象的obj綁定到this,否則不會修改this. ~~~ if(!Function.prototype.softBind){ Function.prototype.softBind = function(obj){ var fn = this; var curried = [].slice.call( arguments,1); var bound = function(){ return fn.apply( (!this || this === (window || global)) ? obj : this, curried.concat.apply( curried, arguments ) ); }; bound.prototype = Object.create( fn.prototype ); return bound; }; } ~~~ ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f103f1c.jpg "") 最后簡單說下ES6中的箭頭函數,其實在第一篇關于this詞法的博文中已經提及過了,再鞏固一下吧。 前面所說的四種規則,只適用于普通的函數,對于ES6中的箭頭函數是不起作用的。箭頭函數不適用以上的規則,它根據外層的作用域來決定this. ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f12fb0b.jpg "") ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_570603f13f045.jpg "") 對比這兩個,應該能明顯得看出問題吧,箭頭函數的綁定是無法修改的,它被綁定到instance之后,即使我們通過call再去指定this的值,它也不會搭理我們,即使適用等級最高的new也是不行的,這里,適用new操作符,最終它只會華麗麗得返回給你一個undefined。 箭頭函數事實上和增加一句self = this效果基本一致。無論是self = this或者是箭頭函數,都想用替代this機制。 建議: 在編寫代碼時,應當: 1、只采用詞法作用域并完全拋棄this風格的代碼; 2、完全采用this風格,在必要的時候使用bind(),盡量避免使用self=this和箭頭函數(出自Kyle Simpson) 到此,this詞法就暫且告一段落,后續只會在有什么頓悟的時候再補充了。 本來已經看得有點崩潰,但是為了對讀到此文的讀者負責,還是看完了所有的關于這部分的內容,此前已經看了兩遍,希望本文對您理解JS的this詞法能有一點幫助。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看