摘要:是中很重要的一個(gè)指針。一起學(xué)習(xí)以下你不知道的中關(guān)于的介紹調(diào)用棧和調(diào)用位置每個(gè)函數(shù)的是在調(diào)用時(shí)被綁定的,完全取決于函數(shù)的調(diào)用位置也就是函數(shù)的調(diào)用方法。調(diào)用棧就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。
this 是js 中很重要的一個(gè)指針。但是往往也是最容易產(chǎn)生bug 的地方。一起學(xué)習(xí)以下《你不知道的JavaScript》中關(guān)于this的介紹;
調(diào)用棧 和 調(diào)用位置每個(gè)函數(shù)的this是在調(diào)用時(shí)被綁定的,完全取決于函數(shù)的調(diào)用位置(也就是函數(shù)的調(diào)用方法)。
在理解this的綁定過(guò)程之前,首先要理解調(diào)用位置和調(diào)用棧;因?yàn)?調(diào)用位置 就在 當(dāng)前正在執(zhí)行的函數(shù) 的 前一個(gè)調(diào)用 中。
什么是調(diào)用棧和調(diào)用位置
調(diào)用位置:調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置(而不是聲明的位置)。
調(diào)用棧:就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。
function baz() { // 當(dāng)前調(diào)用棧是:baz // 因此, 當(dāng)前調(diào)用位置是全局作用域 console.log( "baz" ); bar(); // <-- bar的調(diào)用位置 } function bar() { // 當(dāng)前調(diào)用棧是baz -> bar // 因此, 當(dāng)前調(diào)用位置在baz中 console.log( "bar" ); foo(); // <-- foo的調(diào)用位置 } function foo() { // 當(dāng)前調(diào)用棧是baz -> bar -> foo // 因此, 當(dāng)前調(diào)用位置在bar中 console.log( "foo" ); } baz(); // <-- baz的調(diào)用位置this綁定規(guī)則1:默認(rèn)模式
分析代碼:
function foo() { console.log( this.a ); //this通過(guò)默認(rèn)綁定指向全局對(duì)象 } var a = 2; foo(); // 2
和
function foo() { "use strict"; console.log( this.a ); //嚴(yán)格模式(strict mode)全局對(duì)象將無(wú)法使用默認(rèn)綁定 } var a = 2; foo(); // TypeError: this is undefined
解釋?zhuān)?/p>
可以把這條規(guī)則看作是無(wú)法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則。
當(dāng)調(diào)用foo()時(shí),this.a被解析成了全局變量a。為什么?因?yàn)樵诒纠?,函?shù)調(diào)用時(shí)應(yīng)用了this的默認(rèn)綁定,因此this指向全局對(duì)象。
foo()是直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用的,因此只能使用默認(rèn)綁定,無(wú)法應(yīng)用其他規(guī)則。
如果使用嚴(yán)格模式(strict mode),那么全局對(duì)象將無(wú)法使用默認(rèn)綁定,因此this會(huì)綁定到undefined
this綁定規(guī)則2:隱式綁定分析代碼:
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); // 2
解析:
無(wú)論是直接在obj中定義還是先定義再添加為引用屬性,foo嚴(yán)格來(lái)說(shuō)都不屬于obj對(duì)象。
調(diào)用位置會(huì)使用obj上下文來(lái)引用函數(shù),因此你可以說(shuō)函數(shù)被調(diào)用時(shí)obj對(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 }; var bar = obj.foo; // 函數(shù)別名! var a = "oops, global"; // a是全局對(duì)象的屬性 if(bar === obj.foo){ console.log("true"); //true console.log(typeof bar) //function console.log(typeof obj.foo) //function }else { console.log("false") } bar(); // "oops, global" obj.foo();// 2 //等價(jià)的兩個(gè)函數(shù),輸出不一樣的結(jié)果。為什么? //其實(shí)var bar === window.bar; 它隱式綁定了window 對(duì)象,所以它訪(fǎng)問(wèn)到的自然是 window.a
解析:雖然bar是obj.foo的一個(gè)引用,但是實(shí)際上,它引用的是foo函數(shù)本身,因此此時(shí)的bar()其實(shí)是一
個(gè)不帶任何修飾的函數(shù)調(diào)用,因此應(yīng)用了默認(rèn)綁定。這種情況是不可以預(yù)料的。
還有一種 this 丟失=》 回調(diào)函數(shù)
回調(diào)函數(shù)丟失this綁定是非常常見(jiàn)的
function foo() { console.log( this.a ); } function doFoo(fn) { // fn其實(shí)引用的是foo fn(); // <-- 調(diào)用位置! } var obj = { a: 2, foo: foo }; var a = "oops, global"; // a是全局對(duì)象的屬性 doFoo( obj.foo ); // "oops, global"this綁定規(guī)則3:顯式綁定
分析代碼:
function foo() { console.log( this.a ); } var obj = { a:2 }; foo.call( obj ); // 2
通過(guò)foo.call(..),我們可以在調(diào)用foo時(shí)強(qiáng)制把它的this綁定到obj上
硬綁定
function foo(something) { console.log( this.a, something ); return this.a + something; } var obj = { a:2 }; var bar = foo.bind( obj ); var b = bar( 3 ); // 2 3 console.log( b ); // 5
bind(..)會(huì)返回一個(gè)硬編碼的新函數(shù),它會(huì)把參數(shù)設(shè)置為this的上下文并調(diào)用原始函數(shù)。
this綁定規(guī)則4:new綁定JavaScript,構(gòu)造函數(shù)只是一些使用new操作符時(shí)被調(diào)用的函數(shù)。它們并不會(huì)屬于某個(gè)類(lèi),也不會(huì)實(shí)例化一個(gè)類(lèi)。實(shí)際上,它們甚至都不能說(shuō)是一種特殊的函數(shù)類(lèi)型,它們只是被new操作符調(diào)用的普通函數(shù)而已。
使用new來(lái)調(diào)用函數(shù)時(shí)的行為
創(chuàng)建(或者說(shuō)構(gòu)造)一個(gè)全新的對(duì)象
新對(duì)象會(huì)被執(zhí)行[[原型]]連接。
這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this。
如果函數(shù)沒(méi)有返回其他對(duì)象,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。
function foo(a) { this.a = a; } //new對(duì)普通函數(shù)的構(gòu)造調(diào)用,默認(rèn)行為:創(chuàng)建一個(gè)新對(duì)象,獲得對(duì)this的所有引用,返回新對(duì)象。 var bar = new foo(2); console.log( bar.a ); // 2 //以上函數(shù) 相當(dāng)于下面的函數(shù) function foo(a){ var obj = {}; obj.a = a; reture obj } var bar = foo(2); console.log( bar.a ); // 2
解析:使用new來(lái)調(diào)用foo(..)時(shí),我們會(huì)構(gòu)造一個(gè)新對(duì)象并把它綁定到foo(..)調(diào)用中的this上。
綁定優(yōu)先級(jí)顯式綁定 > 隱式綁定
bind硬綁定 > new綁定 > 隱式綁定
函數(shù)是否在new中調(diào)用(new綁定)?如果是的話(huà)this綁定的是新創(chuàng)建的對(duì)象。
var bar = new foo()
函數(shù)是否通過(guò)call、apply(顯式綁定)或者硬綁定調(diào)用?如果是的話(huà),this綁定的是指定的對(duì)象。
function foo(a) { this.a = a; } var obj = { a:2 } foo.call(obj,3); //因?yàn)閺?qiáng)制改變了foo 的上下文,this 顯示綁定 為 obj;所以改變的是obj.a 的值 console.log(obj.a); //3
函數(shù)是否在某個(gè)上下文對(duì)象中調(diào)用(隱式綁定)?如果是的話(huà),this綁定的是那個(gè)上下文對(duì)象。
var bar = obj1.foo()
如果都不是的話(huà),使用默認(rèn)綁定。如果在嚴(yán)格模式下,就綁定到undefined,否則綁定到全局對(duì)象。
var bar = foo()
在默認(rèn)綁定中容易被混淆的是 IIFE 自執(zhí)行函數(shù)的使用
var a = 3; var obj = { a:3, b:(function(){ console.log(this.a) })(), c:function(){ (function(){ console.log(this.a) })() } } obj.c(); //3 //3 this 都指向了window
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/89833.html
摘要:本文主要是對(duì)自己前端知識(shí)遺漏點(diǎn)的總結(jié)和歸納,希望對(duì)大家有用,會(huì)持續(xù)更新的解釋語(yǔ)言和編譯型語(yǔ)言解釋型語(yǔ)言與編譯型語(yǔ)言的區(qū)別翻譯時(shí)間的不同。命令會(huì)有變量聲明提前的效果。硬綁定參考不同是返回對(duì)應(yīng)函數(shù),便于稍后調(diào)用則是立即調(diào)用。 本文主要是對(duì)自己前端知識(shí)遺漏點(diǎn)的總結(jié)和歸納,希望對(duì)大家有用,會(huì)持續(xù)更新的~ 解釋語(yǔ)言和編譯型語(yǔ)言 解釋型語(yǔ)言與編譯型語(yǔ)言的區(qū)別翻譯時(shí)間的不同。編譯型語(yǔ)言在程序執(zhí)行之前...
摘要:本文主要是對(duì)自己前端知識(shí)遺漏點(diǎn)的總結(jié)和歸納,希望對(duì)大家有用,會(huì)持續(xù)更新的解釋語(yǔ)言和編譯型語(yǔ)言解釋型語(yǔ)言與編譯型語(yǔ)言的區(qū)別翻譯時(shí)間的不同。命令會(huì)有變量聲明提前的效果。硬綁定參考不同是返回對(duì)應(yīng)函數(shù),便于稍后調(diào)用則是立即調(diào)用。 本文主要是對(duì)自己前端知識(shí)遺漏點(diǎn)的總結(jié)和歸納,希望對(duì)大家有用,會(huì)持續(xù)更新的~ 解釋語(yǔ)言和編譯型語(yǔ)言 解釋型語(yǔ)言與編譯型語(yǔ)言的區(qū)別翻譯時(shí)間的不同。編譯型語(yǔ)言在程序執(zhí)行之前...
摘要:本文主要是對(duì)自己前端知識(shí)遺漏點(diǎn)的總結(jié)和歸納,希望對(duì)大家有用,會(huì)持續(xù)更新的解釋語(yǔ)言和編譯型語(yǔ)言解釋型語(yǔ)言與編譯型語(yǔ)言的區(qū)別翻譯時(shí)間的不同。命令會(huì)有變量聲明提前的效果。硬綁定參考不同是返回對(duì)應(yīng)函數(shù),便于稍后調(diào)用則是立即調(diào)用。 本文主要是對(duì)自己前端知識(shí)遺漏點(diǎn)的總結(jié)和歸納,希望對(duì)大家有用,會(huì)持續(xù)更新的~ 解釋語(yǔ)言和編譯型語(yǔ)言 解釋型語(yǔ)言與編譯型語(yǔ)言的區(qū)別翻譯時(shí)間的不同。編譯型語(yǔ)言在程序執(zhí)行之前...
摘要:?jiǎn)卧獪y(cè)試會(huì)體現(xiàn)出以上錯(cuò)誤處理程序的作用如果出現(xiàn)問(wèn)題,錯(cuò)誤處理程序就會(huì)返回。同時(shí)錯(cuò)誤會(huì)展開(kāi)堆棧,這對(duì)調(diào)試非常有幫助。展開(kāi)堆棧處理異常的一種方式是在調(diào)用堆棧的頂部加入。確保你的錯(cuò)誤處理處在相同域中,這樣會(huì)保留原始消息,堆棧和自定義錯(cuò)誤對(duì)象。 JavaScript的事件驅(qū)動(dòng)范式增添了豐富的語(yǔ)言,也是讓使用JavaScript編程變得更加多樣化。如果將瀏覽器設(shè)想為JavaScript的事件驅(qū)動(dòng)...
閱讀 2797·2021-11-24 09:39
閱讀 2558·2021-11-23 09:51
閱讀 1871·2021-11-17 09:33
閱讀 1752·2021-10-22 09:54
閱讀 1884·2021-08-16 11:00
閱讀 3436·2019-08-30 15:53
閱讀 1743·2019-08-30 13:19
閱讀 2915·2019-08-30 12:49