摘要:所以相同點(diǎn)是,在全局范圍內(nèi),全局變量終究是屬于老大的。只生效一次引入了。只生效一次在箭頭函數(shù)中,與封閉詞法環(huán)境的保持一致。我通常把這些原始函數(shù)叫做構(gòu)造函數(shù)。在里面你可以嵌套函數(shù),也就是你可以在函數(shù)里面定義函數(shù)。
只有掌握了JavaScript中的this操作符你才算正式邁入JavaScript這門語言的門檻!我們一直都在用這個(gè)框架,那個(gè)框架,但往往忽視掉了js最基礎(chǔ)的東西,筆者認(rèn)為這些基礎(chǔ)往往才是走下去,走深,最不可或缺的東西.那我們就一起來學(xué)習(xí)一下js中神奇的this吧--------筆者查看了大量有關(guān)this的文章,有些是按照自己思路寫的,有些是直接引用其他作者成熟的思路的文章1.什么是this?
學(xué)習(xí)一個(gè)知識首先要理解他的字面含義,通過翻譯我們知道,this的含義是這,這個(gè)(指較近的人或事物)的意思。那么我們結(jié)合現(xiàn)實(shí),我們說的“這”在不同的環(huán)境所指的事物是不一樣的。那么在JavaScript中this在不同的環(huán)境調(diào)用所表達(dá)的含義也是非常豐富的。如果你覺得JavaScript中的this和其他面向?qū)ο笳Z言Java一樣,是指存儲在實(shí)例屬性中的值,那你就大錯(cuò)特錯(cuò)了。JavaScript中的this有著在這門語言中不可或缺魔力。
2.運(yùn)行的宿主(環(huán)境)不同this含義也是不一樣宿主(環(huán)境)解釋
JS的運(yùn)行環(huán)境一般由宿主環(huán)境和執(zhí)行期環(huán)境共同構(gòu)成,宿主環(huán)境是由外殼程序(如web瀏覽器就是一個(gè)外殼程序)生成,執(zhí)行期環(huán)境是由嵌入到外殼程序中的JS引擎(/JS解釋器)生成的,在執(zhí)行期環(huán)境JS可以生成內(nèi)置靜態(tài)對象、初始化執(zhí)行環(huán)境等。
對于JavaScript,宿主環(huán)境最常見的是web瀏覽器,瀏覽器提供了一個(gè)JavaScript運(yùn)行的環(huán)境,這個(gè)環(huán)境里面,需要提供一些接口,好讓JavaScript引擎能夠和宿主環(huán)境對接。JavaScript引擎才是真正執(zhí)行JavaScript代碼的地方,常見的引擎有V8(目前最快JavaScript引擎、Google生產(chǎn))、JavaScript core
但是環(huán)境不是唯一的,也就是JavaScript不僅僅能夠在瀏覽器里面跑,也能在其他提供了宿主環(huán)境的程序里面跑,最常見的就是nodejs。同樣作為一個(gè)宿主環(huán)境,nodejs也有自己的JavaScript引擎--V8。根據(jù)官方的定義:
Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications
在瀏覽器里,在全局范圍內(nèi),this等價(jià)于window對象。用var聲明一個(gè)變量和給this或者window添加屬性是等價(jià)的
說明:在瀏覽器中,window對象同時(shí)也是全局對象
在node環(huán)境里,如果使用REPL(Read-Eval-Print Loop,簡稱REPL:讀取-求值-輸出,是一個(gè)簡單的,交互式的編程環(huán)境)來執(zhí)行程序,this并不是最高級的命名空間,最高級的是global.
> this === global true
但在node環(huán)境里,如果執(zhí)行一個(gè)js腳本,在全局范圍內(nèi),this以一個(gè)空對象開始作為最高級的命名空間,這個(gè)時(shí)候,它和global不是等價(jià)的。
index.js 文件在node環(huán)境中執(zhí)行 console.log(this) //Object {} console.log(this === global); //false
在node環(huán)境里,在全局范圍內(nèi),如果你用REPL執(zhí)行一個(gè)腳本文件,用var聲明一個(gè)變量并不會和在瀏覽器里面一樣將這個(gè)變量添加給this。
index.js 文件在node環(huán)境中執(zhí)行 var foo = "bar"; console.log(this.foo);//undefined
但是如果你不是用REPL執(zhí)行腳本文件,而是直接執(zhí)行代碼,結(jié)果和在瀏覽器里面是一樣的(神坑)
> var foo = "bar"; > this.foo bar > global.foo bar
在node環(huán)境里,用REPL運(yùn)行腳本文件的時(shí)候,如果在聲明變量的時(shí)候沒有使用var或者let,這個(gè)變量會自動添加到global對象,但是不會自動添加給this對象。如果是直接執(zhí)行代碼,則會同時(shí)添加給global和this
index.js 文件在node環(huán)境中執(zhí)行 foo = "bar"; console.log(this.foo);//undefined console.log(global.foo);//bar
上面的幾種種情況可能大家已經(jīng)繞暈了,總結(jié)起來就是:在瀏覽器里面this是老大,它等價(jià)于window對象,如果你聲明一些全局變量(不管在任何地方),這些變量都會作為this的屬性。在node里面,有兩種執(zhí)行JavaScript代碼的方式,一種是直接執(zhí)行寫好的JavaScript文件,另外一種是直接在里面執(zhí)行一行行代碼。對于直接運(yùn)行一行行JavaScript代碼的方式,global才是老大,this和它是等價(jià)的。在這種情況下,和瀏覽器比較相似,也就是聲明一些全局變量會自動添加給老大global,順帶也會添加給this。但是在node里面直接腳本文件就不一樣了,你聲明的全局變量不會自動添加到this,但是會添加到global對象。所以相同點(diǎn)是,在全局范圍內(nèi),全局變量終究是屬于老大的。4.函數(shù)(function)中的this
說明:在函數(shù)內(nèi)部,this的值取決于函數(shù)被調(diào)用的方式
無論是在瀏覽器環(huán)境還是node環(huán)境,除了在DOM事件處理程序里或者給出了thisArg(接下來會講到)外,如果不是用new調(diào)用,在函數(shù)里面使用this都是指代全局范圍的this。
index.js 文件在node環(huán)境中執(zhí)行 foo = "bar"; function testThis () { this.foo = "foo"; } console.log(global.foo);//bar testThis(); console.log(global.foo);//foo
說明:因?yàn)樯厦娲a不在嚴(yán)格模式下,且this的值不是由該調(diào)用設(shè)置的,所以this的值默認(rèn)指向全局對象。
除非你使用嚴(yán)格模式,這時(shí)候this就會變成undefined。
說明:然而,在嚴(yán)格模式下,this將保持他進(jìn)入執(zhí)行環(huán)境時(shí)的值,所以下面的this將會默認(rèn)為undefined,所以,在嚴(yán)格模式下,如果 this 沒有被執(zhí)行環(huán)境(execution context)定義,那它將保持為 undefined。
如果你在調(diào)用函數(shù)的時(shí)候在前面使用了new,this就會變成一個(gè)新的值,和global的this脫離干系。
函數(shù)里面的this其實(shí)相對比較好理解,如果我們在一個(gè)函數(shù)里面使用this,需要注意的就是我們調(diào)用函數(shù)的方式,如果是正常的方式調(diào)用函數(shù),this指代全局的this,如果我們加一個(gè)new,這個(gè)函數(shù)就變成了一個(gè)構(gòu)造函數(shù),我們就創(chuàng)建了一個(gè)實(shí)例,this指代這個(gè)實(shí)例,這個(gè)和其他面向?qū)ο蟮恼Z言很像。另外,寫JavaScript很常做的一件事就是綁定事件處理程序,也就是諸如button.addEventListener(‘click’, fn, false)之類的,如果在fn里面需要使用this,this指代事件處理程序?qū)?yīng)的對象,也就是button。
如果想把this的值從一個(gè)環(huán)境傳到另一個(gè)環(huán)境,就要用到call或者apply的方法。
說明:使用 call 和 apply 函數(shù)的時(shí)候要注意,如果傳遞給 this 的值不是一個(gè)對象,JavaScript 會嘗試使用內(nèi)部 ToObject 操作將其轉(zhuǎn)換為對象。因此,如果傳遞的值是一個(gè)原始值比如 7 或 "foo",那么就會使用相關(guān)構(gòu)造函數(shù)將它轉(zhuǎn)換為對象,所以原始值 7 會被轉(zhuǎn)換為對象,像 new Number(7) 這樣,而字符串 "foo" 轉(zhuǎn)化成 new String("foo") 這樣,例如:下面代碼
ECMAScript 5 引入了 Function.prototype.bind。調(diào)用f.bind(someObject)會創(chuàng)建一個(gè)與f具有相同函數(shù)體和作用域的函數(shù),但是在這個(gè)新函數(shù)中,this將永久地被綁定到了bind的第一個(gè)參數(shù),無論這個(gè)函數(shù)是如何被調(diào)用的。
ECMAScript 5 引入了 Function.prototype.bind。調(diào)用f.bind(someObject)會創(chuàng)建一個(gè)與f具有相同函數(shù)體和作用域的函數(shù),但是在這個(gè)新函數(shù)中,this將永久地被綁定到了bind的第一個(gè)參數(shù),無論這個(gè)函數(shù)是如何被調(diào)用的。
在箭頭函數(shù)中,this與封閉詞法環(huán)境的this保持一致。在全局代碼中,它將被設(shè)置為全局對象:
5.原型(prototype)中的this你創(chuàng)建的每一個(gè)函數(shù)都是函數(shù)對象,他們會自動獲取一個(gè)特殊的屬性prototype,你可以給這個(gè)屬性賦值。當(dāng)你用new的方式調(diào)用一個(gè)函數(shù)的時(shí)候,你就能通過this訪問你給prototype賦的值了。
當(dāng)你使用new為你的函數(shù)創(chuàng)建多個(gè)實(shí)例的時(shí)候,這些實(shí)例會共享你給prototype設(shè)定的值。對于下面的例子,當(dāng)你調(diào)用this.foo的時(shí)候,都會返回相同的值,除非你在某個(gè)實(shí)例里面重寫了自己的this.foo
實(shí)例里面的this是一個(gè)特殊的對象。你可以把this想成一種獲取prototype的值的一種方式。當(dāng)你在一個(gè)實(shí)例里面直接給this添加屬性的時(shí)候,會隱藏prototype中與之同名的屬性。如果你想訪問prototype中的這個(gè)屬性值而不是你自己設(shè)定的屬性值,你可以通過在實(shí)例里面刪除你自己添加的屬性的方式來實(shí)現(xiàn)。
或者你也能直接通過引用函數(shù)對象的prototype 來獲得你需要的值。
此時(shí)的this是指,構(gòu)造函數(shù)的原型上的方法至于為什么看下面
通過一個(gè)函數(shù)創(chuàng)建的實(shí)例會共享這個(gè)函數(shù)的prototype屬性的值,如果你給這個(gè)函數(shù)的prototype賦值一個(gè)Array,那么所有的實(shí)例都會共享這個(gè)Array,除非你在實(shí)例里面重寫了這個(gè)Array,這種情況下,函數(shù)的prototype的Array就會被隱藏掉。
實(shí)際上你可以通過把多個(gè)函數(shù)的prototype鏈接起來的從而形成一個(gè)原型鏈,因此this就會魔法般地沿著這條原型鏈往上查找直到找你你需要引用的值。
一些人利用原型鏈的特性來在JavaScript模仿經(jīng)典的面向?qū)ο蟮睦^承方式。任何給用于構(gòu)建原型鏈的函數(shù)的this的賦值的語句都會隱藏原型鏈上游的相同的屬性。
我喜歡把被賦值給prototype的函數(shù)叫做方法。在上面的例子中,我已經(jīng)使用過方法了,如logFoo。這些方法有著相同的prototype,即創(chuàng)建這些實(shí)力的原始函數(shù)。我通常把這些原始函數(shù)叫做構(gòu)造函數(shù)。在prototype里面定義的方法里面使用this會影響到當(dāng)前實(shí)例的原型鏈的上游的this。這意味著你直接給this賦值的時(shí)候,隱藏了原型鏈上游的相同的屬性值。這個(gè)實(shí)例的任何方法都會使用這個(gè)最新的值而不是原型里面定義的這個(gè)相同的值。
在JavaScript里面你可以嵌套函數(shù),也就是你可以在函數(shù)里面定義函數(shù)。嵌套函數(shù)可以通過閉包捕獲父函數(shù)的變量,但是這個(gè)函數(shù)沒有繼承this
在doIt里面的this是global對象或者在嚴(yán)格模式下面是undefined。這是造成很多不熟悉JavaScript的人深陷 this陷阱的根源。在這種情況下事情變得非常糟糕,就像你把一個(gè)實(shí)例的方法當(dāng)作一個(gè)值,把這個(gè)值當(dāng)作函數(shù)參數(shù)傳遞給另外一個(gè)函數(shù)但是卻不把這個(gè)實(shí)例傳遞給這個(gè)函數(shù)一樣。在這種情況下,一個(gè)方法里面的環(huán)境變成了全局范圍,或者在嚴(yán)格模式下面的undefined。
一些人喜歡先把this捕獲到一個(gè)變量里面,通常這個(gè)變量叫做self,來避免上面這種情況的發(fā)生
但是當(dāng)你需要把一個(gè)方法作為一個(gè)值傳遞給一個(gè)函數(shù)的時(shí)候并不管用。
你可以通過bind將實(shí)例和方法一切傳遞給函數(shù)來解決這個(gè)問題,bind是一個(gè)函數(shù)定義在所有函數(shù)和方法的函數(shù)對象上面
你同樣可以使用apply和call來在新的上下文中調(diào)用方法或函數(shù)。
你可以用bind來代替任何一個(gè)函數(shù)或者方法的this,即便它沒有賦值給實(shí)例的初始prototype。
你應(yīng)該避免在構(gòu)造函數(shù)里面返回任何東西,因?yàn)檫@可能代替本來應(yīng)該返回的實(shí)例。
怪的是,如果你在構(gòu)造函數(shù)里面返回了一個(gè)原始值,上面所述的情況并不會發(fā)生并且返回語句被忽略了。最好不要在你將通過new調(diào)用的構(gòu)造函數(shù)里面返回任何類型的數(shù)據(jù),即便你知道自己正在做什么。如果你想創(chuàng)建一個(gè)工廠模式,通過一個(gè)函數(shù)來創(chuàng)建一個(gè)實(shí)例,這個(gè)時(shí)候不要使用new來調(diào)用函數(shù)。當(dāng)然這個(gè)建議是可選的。
你可以通過使用Object.create來避免使用new,這樣同樣能夠創(chuàng)建一個(gè)實(shí)例。
在這種情況下并不會調(diào)用構(gòu)造函數(shù)
因?yàn)镺bject.create不會調(diào)用構(gòu)造函數(shù)的特性在你繼承模式下你想通過原型鏈重寫構(gòu)造函數(shù)的時(shí)候非常有用。
6.對象(object )中的this在一個(gè)對象的一個(gè)函數(shù)里,你可以通過this來引用這個(gè)對象的其他屬性。這個(gè)用new來新建一個(gè)實(shí)例是不一樣的。
注意,沒有使用new,沒有使用Object.create,也沒有使用函數(shù)調(diào)用創(chuàng)建一個(gè)對象。你也可以將對象當(dāng)作一個(gè)實(shí)例將函數(shù)綁定到上面。
當(dāng)你用這種方式使用this的時(shí)候,并不會越出當(dāng)前的對象。只有有相同直接父元素的屬性才能通過this共享變量
你可以直接通過對象引用你需要的屬性
7.DOM(event)中的this在一個(gè)HTML DOM事件處理程序里面,this始終指向這個(gè)處理程序被所綁定到的HTML DOM節(jié)點(diǎn)
除非你自己通過bind切換了上下文
8.HTML 中的this在HTML節(jié)點(diǎn)的屬性里面,你可以放置JavaScript代碼,this指向了這個(gè)元素
到此結(jié)束~~~~~~~~~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/105551.html
摘要:本期推薦文章類內(nèi)存泄漏及如何避免,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。四種常見的內(nèi)存泄漏劃重點(diǎn)這是個(gè)考點(diǎn)意外的全局變量未定義的變量會在全局對象創(chuàng)建一個(gè)新變量,如下。因?yàn)槔习姹镜氖菬o法檢測節(jié)點(diǎn)與代碼之間的循環(huán)引用,會導(dǎo)致內(nèi)存泄漏。 (關(guān)注福利,關(guān)注本公眾號回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第一期,本周的主題...
摘要:首次運(yùn)行代碼時(shí),會創(chuàng)建一個(gè)全局執(zhí)行上下文并到當(dāng)前的執(zhí)行棧中。執(zhí)行上下文的創(chuàng)建執(zhí)行上下文分兩個(gè)階段創(chuàng)建創(chuàng)建階段執(zhí)行階段創(chuàng)建階段確定的值,也被稱為。 (關(guān)注福利,關(guān)注本公眾號回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,,今天是第一天 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)...
摘要:使用上一篇文章的例子來說明下自由變量進(jìn)階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第7天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)...
摘要:箭頭函數(shù)的尋值行為與普通變量相同,在作用域中逐級尋找。題目這次通過構(gòu)造函數(shù)來創(chuàng)建一個(gè)對象,并執(zhí)行相同的個(gè)方法。 我們知道this綁定規(guī)則一共有5種情況: 1、默認(rèn)綁定(嚴(yán)格/非嚴(yán)格模式) 2、隱式綁定 3、顯式綁定 4、new綁定 5、箭頭函數(shù)綁定 其實(shí)大部分情況下可以用一句話來概括,this總是指向調(diào)用該函數(shù)的對象。 但是對于箭頭函數(shù)并不是這樣,是根據(jù)外層(函數(shù)或者全局)作用域(...
摘要:本計(jì)劃一共期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)劃,點(diǎn)擊查看前端進(jìn)階的破冰之旅本期推薦文章深入之執(zhí)行上下文棧和深入之變量對象,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。 (關(guān)注福利,關(guān)注本公眾號回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第一期,本周的主題是調(diào)用堆棧,今天是第二天。 本計(jì)劃一共28期,每期...
摘要:之前文章詳細(xì)介紹了的使用,不了解的查看進(jìn)階期。不同的引擎有不同的限制,核心限制在,有些引擎會拋出異常,有些不拋出異常但丟失多余參數(shù)。存儲的對象能動態(tài)增多和減少,并且可以存儲任何值。這邊采用方法來實(shí)現(xiàn),拼成一個(gè)函數(shù)。 之前文章詳細(xì)介紹了 this 的使用,不了解的查看【進(jìn)階3-1期】。 call() 和 apply() call() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的 this 值和分...
閱讀 1380·2021-10-19 11:42
閱讀 723·2021-09-22 16:04
閱讀 1872·2021-09-10 11:23
閱讀 1849·2021-07-29 14:48
閱讀 1251·2021-07-26 23:38
閱讀 2817·2019-08-30 15:54
閱讀 1029·2019-08-30 11:25
閱讀 1701·2019-08-29 17:23