下一篇:《你不知道的javascript》筆記_對象&原型
寫在前面上一篇博客我們知道詞法作用域是由變量書寫的位置決定的,那this又是在哪里確定的呢?如何能夠精準的判斷this的指向?這篇博客會逐條闡述
書中有這樣幾句話:
this是在運行時進行綁定的,并不是在編寫時綁定,它的上下文取決于函數調用時的各種條件
this的綁定和函數聲明的位置沒有任何關系,只取決于函數的調用方式當一個函數被調用時,會創建一個活動記錄(有時候也稱為執行上下文)。這個記錄會包含函數在哪里被調用(調用棧)、函數的調用方法、傳入的參數等信息。this 就是記錄的其中一個屬性,會在函數執行的過程中用到。
關于執行上下文,可以參考《javascript高級程序設計》筆記:內存與執行環境
一、 綁定規則 1.1 默認綁定最常用的函數調用類型——獨立函數調用,使用的即為默認綁定規則,在非strict mode下,this指向全局對象
function foo1() { console.log(this.a); } var a = 10; foo1(); // 10 // 即使函數嵌套比較深 function foo2() { foo1(); } function foo3() { foo2(); } foo3();
當然,我們實際使用中,難以判別的并不是直接型的默認綁定模式,而是隱式綁定丟失型的默認綁定(下面會著重說明)
1.2 隱式綁定【重點】調用的位置是否有上下文對象,或者說被某個對象擁有或包含
// 基本形式 function foo() { console.log(this.a); } var obj = { a: 10, foo }; obj.foo(); // 10
隱式綁定中的幾個雷區:
1. 多個對象嵌套引用時,只有最后一層在調用位置中起作用
function foo() { console.log(this.a); } var obj2 = { a: 42, foo }; var obj1 = { a: 10, obj2 }; obj1.obj2.foo(); // 42
2.【隱式丟失】當調用函數被重新賦值為新變量,調用新變量時this指向會有不同
// 共用部分 function foo(){ console.log(this.a); } var obj = { a: 10, foo }; var a = "opps, global"; // 直接賦值 var bar = obj.foo; bar(); // "oops, global" // 回調間接賦值1 function doFoo(fn) { fn(); } doFoo(obj.foo); // "oops, global" 相當于間接賦值 // 回調間接賦值2 setTimeout(obj.foo, 100); // "oops, global" 內置的setTimeout也相當于間接賦值
經典綜合案例:
var length = 10; function fn(){ console.log(this.length); } var obj = { length: 5, method: function (fn) { fn(); arguments[0](); } }; obj.method(fn, 123);
分析:fn()為函數fn的引用,默認綁定,指向全局;arguments[0]();相當于下面的引用,數據隱式綁定,綁定對象為arguments,其屬性length值為參數數量2
arguments: { "0": function fn(){ console.log(this.length); } }
答案:10 2
1.3 顯式綁定call()/apply()/bind()能夠顯式修改this指向
通過上述方法調用的方式為顯示綁定,它們第一個參數是一個對象,在調用函數時,綁定在this中。
關于三者的基本用法和說明在之前博客《javascript高級程序設計》函數調用模式 & this深度理解中已作說明,在此不做嘮述
兩點注意:
1. 通過顯式綁定的不能再修改它的this指向
function foo() { console.log(this.a); } var obj = { a: 2 }; var bar = function() { foo.call(obj); } bar(); // 2 setTimeout(bar, 200); // 2 bar.call(window); // 2
2. 將null/undefined作為第一個參數時,調用會忽略這些值,采用默認綁定規則
function foo() { console.log(this.a); } var a = 2; foo.call(null); // 21.4 new綁定
使用關鍵字new執行函數,當函數無返回值或返回值非對象時,this指向為實例對象
new關鍵字執行函數流程:
創建一個全新的對象
這個新對象會被執行[[prototype]]連接
這個新對象會綁定到函數調用的this上
如果函數沒有返回其他對象,所執行函數會自動返回這個新的對象
須知:構造函數與普通函數無異,作為區分,我們一般講通過new調用的函數稱為構造函數,并大寫第一個單詞。所有函數均可由關鍵字new調用
function foo(a) { this.a = a; } var bar = new foo(2); console.log(bar.a); // 2二、優先級&判斷規則 2.1 優先級
new綁定 --> 顯式綁定 --> 隱式綁定 --> 默認綁定
2.2. 判斷規則【重點】【new綁定】函數是否在new中調用?如果是,this綁定的是新創建的對象
【顯式綁定】函數是否在call/aplly/bind中調用?如果是,this綁定的是指定對象
【隱式綁定】函數是否在某個上下文中調用?如果是,this綁定到那個上下文對象
【默認綁定】如果都不是,this綁定嚴格模式下為undefined,非嚴格模式下為全局對象
三、箭頭函數中的thisES6中箭頭函數不使用上面this的四種標準規格,而是根據外層(函數或者全局)作用域來決定this指向
下面是一個普通函數和箭頭函數的對比:
function foo1() { setTimeout(() => { console.log(this.a) }, 100) } function foo2() { setTimeout(function() { console.log(this.a) }, 100) } var a = 10; var obj = { a: 2 }; foo1.call(obj); // 2 箭頭函數this指向外層(obj) foo2.call(obj); // 10 隱式丟失,默認綁定
【利用閉包】理解箭頭函數中的this:
// 上例中的箭頭函數相當于 function foo1() { var self = this; setTimeout(function() { console.log(self.a) }, 100) }
上一篇:《你不知道的javascript》筆記_作用域與閉包
下一篇:《你不知道的javascript》筆記_對象&原型
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100381.html
摘要:上一篇你不知道的筆記寫在前面這是年第一篇博客,回顧去年年初列的學習清單,發現僅有部分完成了。當然,這并不影響年是向上的一年在新的城市穩定連續堅持健身三個月早睡早起游戲時間大大縮減,學會生活。 上一篇:《你不知道的javascript》筆記_this 寫在前面 這是2019年第一篇博客,回顧去年年初列的學習清單,發現僅有部分完成了。當然,這并不影響2018年是向上的一年:在新的城市穩定、...
摘要:建筑的頂層代表全局作用域。實際的塊級作用域遠不止如此塊級作用域函數作用域早期盛行的立即執行函數就是為了形成塊級作用域,不污染全局。這便是閉包的特點吧經典面試題下面的代碼輸出內容答案個如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫在前面 這一系列的筆記是在《javascript高級程序設計》讀書筆記系列的升華版本,旨在將零碎...
摘要:本書屬于基礎類書籍,會有比較多的基礎知識,所以這里僅記錄平常不怎么容易注意到的知識點,不會全記,供大家和自己翻閱不錯,下冊的知識點就這么少,非常不推介看下冊上中下三本的讀書筆記你不知道的上讀書筆記你不知道的中讀書筆記你不知道的下讀書筆記第三 本書屬于基礎類書籍,會有比較多的基礎知識,所以這里僅記錄平常不怎么容易注意到的知識點,不會全記,供大家和自己翻閱; 不錯,下冊的知識點就這么少,非...
摘要:但是如果非全局的變量如果被遮蔽了,無論如何都無法被訪問到。但是如果引擎在代碼中找到,就會完全不做任何優化。結構的分句中具有塊級作用域。第四章提升編譯器函數聲明會被提升,而函數表達式不會被提升。 本書屬于基礎類書籍,會有比較多的基礎知識,所以這里僅記錄平常不怎么容易注意到的知識點,不會全記,供大家和自己翻閱; 上中下三本的讀書筆記: 《你不知道的JavaScript》 (上) 讀書筆記...
摘要:隱式綁定即綁定到最頂層或最近調用對象上顯式綁定即用或手動進行綁定方法實現綁定構造函數不存在其實在中不存在構造函數,我們所說的構造函數其實就是普通的函數,它只是用被構造調用而已。 JS是編譯型語言 編譯發生在代碼執行前幾微秒,簡單來說就是js在執行前要進行編譯,編譯過程發生在代碼執行前幾微妙,甚至更短。 編譯的步驟 詞法分析以var a = 2 為例,詞法分析會將其分成三個有意義的代碼...
閱讀 2731·2021-11-24 09:39
閱讀 1647·2021-09-28 09:35
閱讀 1119·2021-09-06 15:02
閱讀 1306·2021-07-25 21:37
閱讀 2726·2019-08-30 15:53
閱讀 3643·2019-08-30 14:07
閱讀 714·2019-08-30 11:07
閱讀 3512·2019-08-29 18:36