摘要:是中的一個屬性解析函數調用位置函數在程序代碼中被調用的位置,清楚調用位置才能明確的指向確定函數的調用位置最關鍵是分析調用棧為達到當前指向位置所調用的所有函數。
關于this
this是JavaScript的一個關鍵字,自動定義在所有函數中,難點在于this的指向。
1 this的作用this的指向在函數調用時進行綁定,它的context取決于函數調用時的各種條件,與函數定義位置無關
this可以使不同的context對象重復使用已經存在、聲明的函數,無需針對每個對象編寫不同版本的函數
function identify() { return this.name.toUpperCase(); } function speak() { var greeting = "Hello, i"m " + identify.call( this ); console.log( greeting ); } var me = {name: "Kyle"}; var you = {name: "Reader"}; identify.call( me ); // KYLE identify.call( you ); // READER speak.call( me ); // "Hello, i"m KYLE" speak.call( you ); // "Hello, i"m READER"2 誤解
this并不是指向函數本身
在任何情況下,this都不指向函數的詞法作用域
3 this是什么?this是在函數被調用時發生綁定,其指向取決于函數調用的位置。
當一個函數被調用是,會創建一個執行上下文(context)。其中包含函數的調用位置(調用棧)、函數的調用方式和傳入的參數等信息。this是context中的一個屬性
4 this解析 4.1 函數調用位置函數在程序代碼中被調用的位置,清楚調用位置才能明確this的指向
確定函數的調用位置:最關鍵是分析調用棧(為達到當前指向位置所調用的所有函數)。分析調用棧,可以得出真正的調用位置
function baz() { // 當前調用棧是:baz // 所以當前調用位置時全局作用域 console.log("baz"); bar(); // <-- bar的調用位置 } function bar() { // 當前調用棧是:baz --> bar // bar的調用位置在baz中 console.log("bar"); foo(); // <-- bar的調用位置 } function foo() { // 當前調用棧是:baz --> bar --> foo // foo的調用位置在bar中 console.log("foo"); } baz(); // --> baz的調用位置4.2 this的綁定規則
在分析清楚調用位置后,根據this綁定的四條規則決定綁定對象。四條規則分別對應四種不同的函數調用方式
總共有四條綁定規則,其優先級是:默認綁定 < 隱式綁定 < 顯式綁定 < new綁定
默認綁定:作為獨立調用的函數
隱式綁定:作為對象的方法調用的函數
顯式綁定(硬綁定):使用call()、apply()和bind()方法,強制將對象綁定到函數的this上
new綁定:
4.2.1 默認綁定默認綁定指將函數作為獨立的函數來調用,默認綁定將this綁定到全局對象。
分析隱式綁定時,一個對象內部包含一個指向函數的屬性,并且通過對象的屬性間接引用函數,將this間接綁定到該對象上
function foo() { console.log(this.a); } var a = 2; foo(); // 2
a在全局作用域中聲明,是全局對象的一個屬性;
foo()使用不帶任何修飾的函數進行調用,只能使用默認綁定規則;此時,非嚴格模式下this指向全局對象,所有this.a被解析為全局變量a
在嚴格模式中,this不能綁定到全局對象,this只能綁定到undefined
function foo() { "use strict"; console.log(this.a); } var a = 2; foo(); // TypeError: this is undefined4.2.2 隱式綁定
判斷函數的調用位置是否有上下文對象,隱式綁定將this綁定到調用方法的上下文對象上。
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo }; obj.foo(); // 2 foo()的調用位置包含上下文對象obj,this隱式綁定到obj對象
對象屬性引用鏈中,只有最后一層會影響調用位置
function foo() { console.log(this.a); } var obj = { a: 2, obj2: obj2 }; var obj2 = { a: 42, foo: foo obj.obj2.foo(); // 42 實際是通過obj對象的obj2屬性對象來調用foo()函數,this指向obj2隱式丟失
被隱式綁定的函數會丟失綁定對象,然后應用默認綁定,非嚴格模式下將this綁定到全局對象。
隱式綁定丟失發生在將隱式綁定的函數賦值給另外的變量,通過改變了來調用函數
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函數別名,傳遞引用 var a = "global a"; bar(); // "global a",函數的調用位置,bar()其實是一個不帶任何修飾的函數調用,所以應用默認的綁定規則
在函數中將回調函數作為參數傳入時,參數傳遞是一種隱式賦值(傳遞引用),所以應用默認綁定規則
function foo() { console.log(this.a); } function doFoo(fn) { // fn是obj.foo函數本身的一個引用 fn(); // fn的調用位置 } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函數別名,傳遞引用 var a = "global a"; doFoo(obj.foo); // "global a",傳入的函數被隱式賦值,應用默認綁定規則 setTimeout(obj.foo, 100); //"global a",使用語言本身的內置函數時道理相同4.2.3 顯式綁定
在JavaScript中,函數是對象,每個函數對象都定義有call()、apply()和bind()方法,bind()在ES5中。
call()、apply()方法:
第一個方法是一個對象,將該對象綁定到this
可以直接指定綁定的對象,稱為顯示綁定
call()、apply()區別在于其他參數
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo }; foo.call(obj); // 2 通過foo.call(obj);,在調用foo()時強制將其this綁定到obj對象
顯式綁定仍然會有綁定丟失問題:可以使用顯示綁定的一個變形來解決這個問題;
硬綁定
創建一個函數bar(),在內部調用foo.call(obj),強制將foo的this綁定到obj對象上,無論怎樣調用bar()函數,都會手動在obj對象上調用foo,因此foo的this指向不會改變
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo }; var bar = function() { foo.call(obj); } bar(); // 2 setTimeout( bar, 100 ); // 2 // 硬綁定的bar不能再修改它的this指向 bar.call(window); // 2硬綁定的應用場景
創建一個包裹函數,傳入所有的參數,并返回接收到的所有值
function foo(sth) { return this.a + sth; } var obj = { a: 2 }; var bar = function() { // 將arguments傳入需要調用的函數 return foo.apply(obj, arguments); } bar(3); // 2 + 3 = 5
創建一個可以重復使用的函數
function foo(sth) { return this.a + sth; } var obj = { a: 2 }; // 簡單的輔助綁定函數 function bind(fn, obj) { return function() { return fn.apply(obj, arguments); } } var bar = bind(foo, obj); bar(3); // 2 + 3 = 5
硬綁定是一種非常常見的模式,ES5提供內置Function.prototype.bind方法:返回一個硬綁定的新函數,bind(obj)將參數obj設置為this的上下文,并調用原始函數。
function foo(sth) { return this.a + sth; } var obj = { a: 2 }; var bar = foo.bind(obj); bar(3); // 2 + 3 = 54.2.4 new綁定
JavaScript中的new機制與傳統面向對象語言不同。JavaScript中構造函數只是使用new操作符調用的函數,使用new操作符調用函數時:
創建一個全新對象;
新對象被執行__proto__鏈接
新創建的對象被綁定到函數調用時的this
如果函數沒有返回其他對象,new表達式中的函數調用自動返回新創建的對象
function foo(a) { this.a = a; } var bar = new foo(2); console.log(bar.a); // 24.3 優先級
判斷this的指向:找到函數的調用位置,并根據優先級判斷應用的規則,默認綁定的優先級最低
顯示綁定的優先級高于隱式綁定:在判斷時優先考慮顯示綁定
function foo(a) { this.a = a; } var obj1 = { a: 2; foo: foo }; var objb = { a: 4; foo: foo }; obj1.foo(); // 2 obj2.foo(); // 4 obj1.foo.call(obj2); // 4 obj2.foo.call(obj1); // 2
new綁定的優先級高于隱式綁定:
new綁定的優先級的高于顯示綁定:
bar被硬綁定到obj1對象上,但是new bar(3)并未將obj1.a修改為4;
new bar(3)修改了調用bar()中的this,得到一個新對象
function foo(a) { this.a = a; } obj1 = {}; var bar = foo.bind(obj1); bar(2); console.log(obj1.a); // 2 var baz = new bar(4); console.log(obj1.a); // 2 console.log(baz.a); // 44.4 根據優先級判斷函數調用位置應用的規則
函數是否在new中調用?如果是,this綁定新創建的對象
函數是否通過call()、apply()顯示綁定?或者bind()硬綁定?如果是,this指向綁定的對象。
函數是否在某個上下文對象中調用?如果是,this指向那個上下文對象
如果不是上述三種情況,使用默認綁定。嚴格模式下綁定到undefined,非嚴格模式下綁定到全局對象
4.5 綁定例外 4.5.1 被忽略的this將null或undefined作為this的綁定對象傳入call()、apply()和bind()方法,在調用時被忽略,實際應用默認綁定規則。
使用null來忽略this綁定可能產生副作用:安全的做法是傳入一個特殊對象,將this綁定到這個對象不會產生任何副作用。Object.create(null)。
5 this詞法ES6中的箭頭函數不能使用上述4種規則,而是根據外層(函數或全局)作用域來絕對this。箭頭函數常用于回調函數中。
function foo() { // 返回一個箭頭函數 return (a) => { // this繼承自foo() console.log(this.a); } } var obj = { a: 2 }; var obj2 = { a: 42 }; var bar = foo.call(obj1); bar.call(obj2); // 2, 不是42
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86855.html
摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...
摘要:第四點也要著重講下,記住構造函數被操作,要讓正常作用最好不能在構造函數里 4) this、new、call和apply的相關問題 講解this指針的原理是個很復雜的問題,如果我們從javascript里this的實現機制來說明this,很多朋友可能會越來越糊涂,因此本篇打算換一個思路從應用的角度來講解this指針,從這個角度理解this指針更加有現實意義。 下面我們看看在ja...
摘要:所以相同點是,在全局范圍內,全局變量終究是屬于老大的。只生效一次引入了。只生效一次在箭頭函數中,與封閉詞法環境的保持一致。我通常把這些原始函數叫做構造函數。在里面你可以嵌套函數,也就是你可以在函數里面定義函數。 showImg(https://img-blog.csdnimg.cn/20190522000008399.jpg?x-oss-process=image/watermark,...
摘要:中函數的調用有以下幾種方式作為對象方法調用,作為函數調用,作為構造函數調用,和使用或調用。作為構造函數調用中的構造函數也很特殊,構造函數,其實就是通過這個函數生成一個新對象,這時候的就會指向這個新對象如果不使用調用,則和普通函數一樣。 this 是 JavaScript 比較特殊的關鍵字,本文將深入淺出的分析其在不同情況下的含義,可以這樣說,正確掌握了 JavaScript 中的 th...
摘要:和類在開始時遇到類組件,只是需要有關類的基礎。畢竟,中的條件呈現僅再次顯示大多數是而不是特定的任何內容。 在我的研討會期間,更多的材料是關于JavaScript而不是React。其中大部分歸結為JavaScript ES6以及功能和語法,但也包括三元運算符,語言中的簡寫版本,此對象,JavaScript內置函數(map,reduce,filter)或更常識性的概念,如:可組合性,可重用...
閱讀 4233·2021-09-26 10:17
閱讀 877·2021-09-22 15:02
閱讀 3450·2021-09-06 15:00
閱讀 1059·2021-07-25 16:52
閱讀 2740·2019-08-29 16:16
閱讀 2519·2019-08-29 13:25
閱讀 1595·2019-08-26 13:51
閱讀 2189·2019-08-26 10:58