摘要:本文總結(jié)了的各種情況,并從規(guī)范的角度探討了的具體實(shí)現(xiàn),希望對(duì)大家理解有所幫助。規(guī)范規(guī)范里面詳細(xì)介紹了的實(shí)現(xiàn)細(xì)節(jié),通過閱讀規(guī)范,我們可以更準(zhǔn)確的理解上述四種情況到底是怎么回事。由于本人能力有限,如有理解錯(cuò)誤的地方還望指出。
this是面向?qū)ο缶幊讨械囊粋€(gè)概念,它一般指向當(dāng)前方法調(diào)用所在的對(duì)象,這一點(diǎn)在java、c++這類比較嚴(yán)格的面向?qū)ο缶幊陶Z言里是非常明確的。但是在javascript中,this的定義要靈活許多,如果未準(zhǔn)確掌握,非常容易混淆。本人在面試過程中也發(fā)現(xiàn),面試者很少有由能夠回答得非常全面的。本文總結(jié)了this的各種情況,并從Ecma規(guī)范的角度探討了this的具體實(shí)現(xiàn),希望對(duì)大家理解this有所幫助。
this指向的四中情況在javascript里面,this的指向可以歸納為以下四種情況。只要能牢記這四種情況,大部分情況下就已經(jīng)夠用了。
1.在全局代碼或者普通的函數(shù)調(diào)用中,this指向全局對(duì)象,在瀏覽器里面既為window對(duì)象。
console.log(this);//輸出window function foo(){ console.log(this); } foo();//輸出window
在瀏覽器環(huán)境里運(yùn)行上述代碼,兩處輸出結(jié)果均為window對(duì)象。
2.通過call或apply方法調(diào)用函數(shù),this指向方法調(diào)用的第一個(gè)參數(shù)。
var obj = {name:"test"}; function foo(){ console.log(this); } foo.call(obj);//輸出obj foo.apply(obj);//輸出obj
在瀏覽器環(huán)境里執(zhí)行以上代碼,輸出結(jié)果均為對(duì)象obj。call和apply除了參數(shù)形式不一樣外其他都一樣,call采用逗號(hào)分割,apply采用數(shù)組。說到這里,順便介紹一個(gè)小技巧。如何在不生成新數(shù)組的情況下實(shí)現(xiàn)兩個(gè)數(shù)組的連接?請(qǐng)看下面的代碼。
var arr1 = [1, 2 , 3], arr2 = [4, 5, 6]; Array.prototype.push.apply(arr1, arr2); console.log(arr1);//輸出[1, 2, 3, 4, 5, 6]
執(zhí)行上述代碼后,輸出結(jié)果為[1, 2, 3, 4, 5, 6]。這是一個(gè)非常實(shí)用的小技巧,由于apply第二個(gè)參數(shù)為數(shù)組形式,所以我們可以把push方法“借”過來,從而實(shí)現(xiàn)兩個(gè)數(shù)組的連接。
3.調(diào)用對(duì)象的方法,this指向該對(duì)象。
var obj = {name:"test"}; function foo(){ console.log(this); } obj.foo = foo; obj.foo();//輸出obj
執(zhí)行以上代碼后,控制臺(tái)輸出為obj對(duì)象。這就是我們常說的“誰調(diào)用,指向誰”。
4.構(gòu)造方法中的this,指向新構(gòu)造的對(duì)象。
function C(){ this.name = "test"; this.age = 18; console.log(this); } var c = new C();//輸出 c console.log(c);//輸出 c
執(zhí)行以上代碼后,控制臺(tái)輸出均為c所指向的對(duì)象。當(dāng)new操作符用于函數(shù)時(shí),會(huì)創(chuàng)建一個(gè)新對(duì)象,并用this指向它。
Ecma規(guī)范Ecma規(guī)范里面詳細(xì)介紹了this的實(shí)現(xiàn)細(xì)節(jié),通過閱讀規(guī)范,我們可以更準(zhǔn)確的理解上述四種情況到底是怎么回事。
函數(shù)對(duì)象有一個(gè)叫[[Call]]內(nèi)部方法,函數(shù)的執(zhí)行其實(shí)是通過[[Call]]方法來執(zhí)行的。[[Call]]方法接收兩個(gè)參數(shù)thisArg和argumentList,thisArg和this的指向有直接關(guān)系,argumentList為函數(shù)的實(shí)參列表。thisArg又是怎么來的呢?我們可以和前面討論的四種情況對(duì)應(yīng)起來:
普通方法調(diào)用thisArg為undefined。
通過call或apply調(diào)用,thisArg既為第一個(gè)參數(shù)。
通過對(duì)象調(diào)用,thisArg指向該對(duì)象。
在構(gòu)造方法中,thisArg為新構(gòu)造的對(duì)象。
thisArg和this是什么關(guān)系?規(guī)范里的描述是這樣的:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
Else set the ThisBinding to thisArg.
在嚴(yán)格模式下,thisArg和this是一一對(duì)應(yīng)的。
function foo(){ "use strict"; console.log(this); } foo();//輸出undefined
該示例輸出的結(jié)果為undefined。
第二點(diǎn)是說如果thisArg為null或者undefined則this指向全局對(duì)象。
function foo(){ console.log(this); } foo.call(null);//輸出window
該示例的輸出結(jié)果為window。
第三點(diǎn)說如果thisArg為非對(duì)象類型,則會(huì)強(qiáng)制轉(zhuǎn)型成對(duì)象類型。
function foo(){ console.log(this); } var aa = 2; console.log(aa);//輸出2 foo.call(aa);//輸出 Number
這里的輸出結(jié)果分別為2和Number,它將基本類型轉(zhuǎn)型成了對(duì)象包裝類型。
第四點(diǎn)說明剩下的情況thisArg和this為一一對(duì)應(yīng)的關(guān)系。
規(guī)范里面對(duì)this指向的描述還是比較明確的。只要你搞清楚thisArg怎么確定,thisArg和this的對(duì)應(yīng)關(guān)系,那么你就能搞定所有this的情況了。
確保this的指向在實(shí)際使用this的過程中,遇到得最多得一個(gè)問題可能就是上下文丟失的問題了。因?yàn)閖avascript中的函數(shù)是可以作為參數(shù)傳遞的,那么其他對(duì)象在執(zhí)行回調(diào)函數(shù)時(shí)就可能造成回調(diào)函數(shù)原來的上下文丟失,也就是this的指向改變了。
var C = function(){ this.name = "test"; this.greet = function(){ console.log("Hello,I am "+this.name+"!"); }; } var obj = new C(); obj.greet();//輸出 Hello,I am test! setTimeout(obj.greet, 1000);//輸出 Hello,I am !
可見第二條輸出中this的值改變了,其實(shí)我們是希望this能夠指向obj的。解決該問題的方法有兩種。
1.bind方法。
bind方法通過閉包巧妙地實(shí)現(xiàn)了上下文的綁定,它實(shí)際上是將原方法包裝成了一個(gè)新方法。一般的實(shí)現(xiàn)如下:
Function.prototype.bind = function(){ var args = arguments, thisArg = arguments[0], func = this; return function(){ var arg = Array.prototype.slice.call(args, 1); Array.prototype.push.apply(args, arguments); return func.apply(thisArg, arg); } }
前面的示例代碼我們只需要加上bind,就能夠得到我們希望的結(jié)果了。
... setTimeout(obj.greet.bind(obj), 1000);//輸出 Hello,I am test! ...
2.es6箭頭函數(shù)。
es6里面提供了一個(gè)新的語法糖,箭頭函數(shù)。箭頭函數(shù)的this不再變幻莫測(cè),它永遠(yuǎn)指向函數(shù)定義時(shí)的this值。
var C = function(){ this.name = "test"; this.greet = ()=>{ console.log("Hello,I am "+this.name+"!"); }; } var obj = new C(); obj.greet();//輸出 Hello,I am test! setTimeout(obj.greet, 1000);//輸出 Hello,I am test!
我們將前面的示例該成箭頭函數(shù)后,兩處的輸出結(jié)果一樣了。this的值不再改變了,這是我們想要的。
小結(jié)this看起來是個(gè)非常小的知識(shí)點(diǎn),其實(shí)挖起來還是有很多細(xì)節(jié)的,特別是規(guī)范里面的一些定義,本人覺得對(duì)于一個(gè)js程序員來說是非常重要的。本人后面也準(zhǔn)備找些ecma規(guī)范里面的知識(shí)點(diǎn)和大家分享,希望能對(duì)大家有所幫助。由于本人能力有限,如有理解錯(cuò)誤的地方還望指出。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/91544.html
摘要:不包括作為其嵌套函數(shù)的被解析的源代碼。作用域鏈當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。棧結(jié)構(gòu)最頂層的執(zhí)行環(huán)境稱為當(dāng)前運(yùn)行的執(zhí)行環(huán)境,最底層是全局執(zhí)行環(huán)境。無限制函數(shù)上下文?;蛘邟伋霎惓M顺鲆粋€(gè)執(zhí)行環(huán)境。 前言 其實(shí)規(guī)范這東西不是給人看的,它更多的是給語言實(shí)現(xiàn)者提供參考。但是當(dāng)碰到問題找不到答案時(shí),規(guī)范往往能提供想要的答案 。偶爾讀一下能夠帶來很大的啟發(fā)和思考,如果只讀一...
摘要:本文不是標(biāo)準(zhǔn)的中文翻譯,也不是的入門教程,本文雖然以的常見問題切入,但并不適合想要快速了解這些問題的人才是快速了解問題的正解。盡量以英文原版為基礎(chǔ),為了流暢,可能會(huì)使用某些名詞的中文翻譯,但會(huì)將匹配的英文名詞以此種樣式中出現(xiàn)一次以避免誤解。 簡(jiǎn)單易懂的ECMA規(guī)范導(dǎo)讀1 序 最近混SF,恰巧又逢工作方面有了NodeJS的機(jī)會(huì),迫切地有教別人怎么寫JS的需求, 我發(fā)現(xiàn)JS這個(gè)東西其實(shí)...
摘要:另一方面,我不建議初次接觸的開發(fā)人員閱讀規(guī)范。在維護(hù)語言的最新規(guī)范。在這一點(diǎn)上,我想指出的是,絕對(duì)沒有人從上到下閱讀規(guī)范。拓展閱讀由于的定義,中的細(xì)節(jié)如冒泡錯(cuò)誤,直到塊在規(guī)范中不存在。換句話說,會(huì)轉(zhuǎn)發(fā)中拋出的錯(cuò)誤,并終止其余的步驟。 翻譯自:How to Read the ECMAScript Specification Ecmascript 語言規(guī)范 The ECMAScr...
摘要:不同執(zhí)行上下文中的變量對(duì)象對(duì)于所有的執(zhí)行上下文類型,變量對(duì)象的一些操作比如變量實(shí)例化和行為是共通的。從這點(diǎn)看,將變量對(duì)象看作是抽象的基礎(chǔ)的東西很便利。全局上下文的變量對(duì)象現(xiàn)在,應(yīng)該先給出全局對(duì)象的定義。 原文地址 作者的話 有很多文章已經(jīng)對(duì)ECMAScript的核心概念做了詳盡解讀。本系列文章翻譯自Dmitry Soshnikov的個(gè)人網(wǎng)站,相信不少人已經(jīng)看過原文或者譯文。原文簡(jiǎn)潔易懂...
摘要:如下所示在規(guī)范中,已經(jīng)正式把屬性添加到規(guī)范中也可以通過設(shè)置和獲取對(duì)象的原型對(duì)象對(duì)象之間的關(guān)系可以用下圖來表示但規(guī)范主要介紹了如何利用構(gòu)造函數(shù)去構(gòu)建原型關(guān)系。 前言 在軟件工程中,代碼重用的模式極為重要,因?yàn)樗麄兛梢燥@著地減少軟件開發(fā)的成本。在那些主流的基于類的語言(比如Java,C++)中都是通過繼承(extend)來實(shí)現(xiàn)代碼復(fù)用,同時(shí)類繼承引入了一套類型規(guī)范。而JavaScript是...
閱讀 2112·2023-04-25 17:23
閱讀 2924·2021-11-17 09:33
閱讀 2518·2021-08-21 14:09
閱讀 3602·2019-08-30 15:56
閱讀 2610·2019-08-30 15:54
閱讀 1630·2019-08-30 15:53
閱讀 2136·2019-08-29 13:53
閱讀 1152·2019-08-29 12:31