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