摘要:是中很重要的一個指針。一起學習以下你不知道的中關于的介紹調用棧和調用位置每個函數的是在調用時被綁定的,完全取決于函數的調用位置也就是函數的調用方法。調用棧就是為了到達當前執行位置所調用的所有函數。
this 是js 中很重要的一個指針。但是往往也是最容易產生bug 的地方。一起學習以下《你不知道的JavaScript》中關于this的介紹;
調用棧 和 調用位置每個函數的this是在調用時被綁定的,完全取決于函數的調用位置(也就是函數的調用方法)。
在理解this的綁定過程之前,首先要理解調用位置和調用棧;因為 調用位置 就在 當前正在執行的函數 的 前一個調用 中。
什么是調用棧和調用位置
調用位置:調用位置就是函數在代碼中被調用的位置(而不是聲明的位置)。
調用棧:就是為了到達當前執行位置所調用的所有函數。
function baz() { // 當前調用棧是:baz // 因此, 當前調用位置是全局作用域 console.log( "baz" ); bar(); // <-- bar的調用位置 } function bar() { // 當前調用棧是baz -> bar // 因此, 當前調用位置在baz中 console.log( "bar" ); foo(); // <-- foo的調用位置 } function foo() { // 當前調用棧是baz -> bar -> foo // 因此, 當前調用位置在bar中 console.log( "foo" ); } baz(); // <-- baz的調用位置this綁定規則1:默認模式
分析代碼:
function foo() { console.log( this.a ); //this通過默認綁定指向全局對象 } var a = 2; foo(); // 2
和
function foo() { "use strict"; console.log( this.a ); //嚴格模式(strict mode)全局對象將無法使用默認綁定 } var a = 2; foo(); // TypeError: this is undefined
解釋:
可以把這條規則看作是無法應用其他規則時的默認規則。
當調用foo()時,this.a被解析成了全局變量a。為什么?因為在本例中,函數調用時應用了this的默認綁定,因此this指向全局對象。
foo()是直接使用不帶任何修飾的函數引用進行調用的,因此只能使用默認綁定,無法應用其他規則。
如果使用嚴格模式(strict mode),那么全局對象將無法使用默認綁定,因此this會綁定到undefined
this綁定規則2:隱式綁定分析代碼:
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); // 2
解析:
無論是直接在obj中定義還是先定義再添加為引用屬性,foo嚴格來說都不屬于obj對象。
調用位置會使用obj上下文來引用函數,因此你可以說函數被調用時obj對象“擁有”或者“包含”它。
當函數引用有上下文對象時,隱式綁定規則會把函數調用中的this綁定到這個上下文對象。
對象屬性引用鏈中只有最接近(包含層)會影響調用位置。
隱式丟失
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函數別名! var a = "oops, global"; // a是全局對象的屬性 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 //等價的兩個函數,輸出不一樣的結果。為什么? //其實var bar === window.bar; 它隱式綁定了window 對象,所以它訪問到的自然是 window.a
解析:雖然bar是obj.foo的一個引用,但是實際上,它引用的是foo函數本身,因此此時的bar()其實是一
個不帶任何修飾的函數調用,因此應用了默認綁定。這種情況是不可以預料的。
還有一種 this 丟失=》 回調函數
回調函數丟失this綁定是非常常見的
function foo() { console.log( this.a ); } function doFoo(fn) { // fn其實引用的是foo fn(); // <-- 調用位置! } var obj = { a: 2, foo: foo }; var a = "oops, global"; // a是全局對象的屬性 doFoo( obj.foo ); // "oops, global"this綁定規則3:顯式綁定
分析代碼:
function foo() { console.log( this.a ); } var obj = { a:2 }; foo.call( obj ); // 2
通過foo.call(..),我們可以在調用foo時強制把它的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(..)會返回一個硬編碼的新函數,它會把參數設置為this的上下文并調用原始函數。
this綁定規則4:new綁定JavaScript,構造函數只是一些使用new操作符時被調用的函數。它們并不會屬于某個類,也不會實例化一個類。實際上,它們甚至都不能說是一種特殊的函數類型,它們只是被new操作符調用的普通函數而已。
使用new來調用函數時的行為
創建(或者說構造)一個全新的對象
新對象會被執行[[原型]]連接。
這個新對象會綁定到函數調用的this。
如果函數沒有返回其他對象,那么new表達式中的函數調用會自動返回這個新對象。
function foo(a) { this.a = a; } //new對普通函數的構造調用,默認行為:創建一個新對象,獲得對this的所有引用,返回新對象。 var bar = new foo(2); console.log( bar.a ); // 2 //以上函數 相當于下面的函數 function foo(a){ var obj = {}; obj.a = a; reture obj } var bar = foo(2); console.log( bar.a ); // 2
解析:使用new來調用foo(..)時,我們會構造一個新對象并把它綁定到foo(..)調用中的this上。
綁定優先級顯式綁定 > 隱式綁定
bind硬綁定 > new綁定 > 隱式綁定
函數是否在new中調用(new綁定)?如果是的話this綁定的是新創建的對象。
var bar = new foo()
函數是否通過call、apply(顯式綁定)或者硬綁定調用?如果是的話,this綁定的是指定的對象。
function foo(a) { this.a = a; } var obj = { a:2 } foo.call(obj,3); //因為強制改變了foo 的上下文,this 顯示綁定 為 obj;所以改變的是obj.a 的值 console.log(obj.a); //3
函數是否在某個上下文對象中調用(隱式綁定)?如果是的話,this綁定的是那個上下文對象。
var bar = obj1.foo()
如果都不是的話,使用默認綁定。如果在嚴格模式下,就綁定到undefined,否則綁定到全局對象。
var bar = foo()
在默認綁定中容易被混淆的是 IIFE 自執行函數的使用
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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89833.html
摘要:單元測試會體現出以上錯誤處理程序的作用如果出現問題,錯誤處理程序就會返回。同時錯誤會展開堆棧,這對調試非常有幫助。展開堆棧處理異常的一種方式是在調用堆棧的頂部加入。確保你的錯誤處理處在相同域中,這樣會保留原始消息,堆棧和自定義錯誤對象。 JavaScript的事件驅動范式增添了豐富的語言,也是讓使用JavaScript編程變得更加多樣化。如果將瀏覽器設想為JavaScript的事件驅動...
閱讀 2793·2021-11-24 09:39
閱讀 2553·2021-11-23 09:51
閱讀 1838·2021-11-17 09:33
閱讀 1744·2021-10-22 09:54
閱讀 1878·2021-08-16 11:00
閱讀 3428·2019-08-30 15:53
閱讀 1737·2019-08-30 13:19
閱讀 2908·2019-08-30 12:49