摘要:原文鏈接參考深入理解原型和閉包完結(jié)王福朋博客園中的作用域詳解博客園
前言
王福朋老師的 JavaScript原型和閉包系列 文章看了不下三遍了,最為一個(gè)初學(xué)者,每次看的時(shí)候都會(huì)有一種 "大徹大悟" 的感覺,而看完之后卻總是一臉懵逼。原型與閉包 可以說是 JavaScirpt 中理解起來最難的部分了,當(dāng)然,我也只是了解到了一些皮毛,對(duì)于 JavaScript OOP 更是缺乏經(jīng)驗(yàn)。這里我想總結(jié)一下 Javascript 中的 this 關(guān)鍵字,王福朋老師的在文章里也花了大量的篇幅來講解 this 關(guān)鍵字的使用,可以說 this 關(guān)鍵字也是值得重視的。
我們都知道,每一個(gè) "代碼段" 都會(huì)執(zhí)行在某一個(gè) 上下文環(huán)境 當(dāng)中,而在每一個(gè)代碼執(zhí)行之前,都會(huì)做一項(xiàng) "準(zhǔn)備工作",也就是生成相應(yīng)的 上下文環(huán)境,所以每一個(gè) 上下文環(huán)境 都可能會(huì)不一樣。
上下文環(huán)境 是什么?我們可以去看王福朋老師的文章(鏈接在文末),講解的很清楚了,這里不贅述了。
"代碼段" 可以分為三種:
全局代碼
函數(shù)體
eval 代碼
與之對(duì)應(yīng)的 上下文環(huán)境 就有:
全局上下文
函數(shù)上下文
(elav 就不討論了,不推薦使用)
當(dāng)然,這和 this 又有什么關(guān)系呢?this 的值就是在為代碼段做 "準(zhǔn)備工作" 時(shí)賦值的,可以說 this 就是 上下文環(huán)境 的一部分,而每一個(gè)不同的 上下文環(huán)境 可能會(huì)有不一樣的 this值。
每次在尋找一個(gè)問題的解決方案或總結(jié)一個(gè)問題的時(shí)候,我總會(huì)去嘗試將這個(gè)問題進(jìn)行合適的分類,而從不同的方面去思考問題。
所以,這里我大膽的將 this 關(guān)鍵字的使用分為兩種情況:
全局上下文的 this
函數(shù)上下文的 this
(你也可以選擇其他的方式分類。當(dāng)然,這也不重要了)
全局上下文中的 this在全局執(zhí)行上下文中(在任何函數(shù)體外部),this 都指向全局對(duì)象:
// 在瀏覽器中, 全局對(duì)象是 window console.log(this === window) // true var a = "Zavier Tang" console.log(a) // "Zavier Tang" console.log(window.a) // "Zavier Tang" console.log(this.a) // "Zavier Tang" this.b = 18 console.log(b) // 18 console.log(window.b) // 18 console.log(this.b) // 18 // 在 node 環(huán)境中,this 指向global console.log(this === global) // true函數(shù)上下文中的 this
在函數(shù)內(nèi)部,this 的值取決與函數(shù)被調(diào)用的方式。
this 的值在函數(shù)定義的時(shí)候是確定不了的,只有函數(shù)調(diào)用的時(shí)候才能確定 this 的指向。實(shí)際上 this 的最終指向的是那個(gè)調(diào)用它的對(duì)象。(也不一定正確)
1. 全局函數(shù)對(duì)于全局的方法調(diào)用,this 指向 window 對(duì)象(node下為 global ):
var foo = function () { return this } // 在瀏覽器中 foo() === window // true // 在 node 中 foo() === global //true
但值得注意的是,以上代碼是在 非嚴(yán)格模式 下。然而,在 嚴(yán)格模式 下,this 的值將保持它進(jìn)入執(zhí)行上下文的值:
var foo = function () { "use strict" return this } f2() // undefined
即在嚴(yán)格模式下,如果 this 沒有被執(zhí)行上下文定義,那它為 undefined。
在生成 上下文環(huán)境 時(shí):
若方法被 window(或 global )對(duì)象調(diào)用,即執(zhí)行 window.foo(),那 this 將會(huì)被定義為 window(或 global );
若被普通對(duì)象調(diào)用,即執(zhí)行 obj.foo(),那 this 將會(huì)被定義為 obj 對(duì)象;(在后面會(huì)討論)
但若未被對(duì)象調(diào)用,即直接執(zhí)行 foo(),在非嚴(yán)格模式下,this 的值默認(rèn)指向全局對(duì)象 window(或 global ),在嚴(yán)格模式下,this 將保持為 undefined。
通過 this 調(diào)用全局變量:
var a = "global this" var foo = function () { console.log(this.a) } foo() // "global this"
var a = "global this" var foo = function () { this.a = "rename global this" // 修改全局變量 a console.log(this.a) } foo() // "rename global this"
所以,對(duì)于全局的方法調(diào)用,this 指向的是全局對(duì)象 window (或global ),即調(diào)用方法的對(duì)象。(注意嚴(yán)格模式的不同)
2. 作為對(duì)象的方法當(dāng)函數(shù)作為對(duì)象的方法調(diào)用時(shí),它的 this 值是調(diào)用該函數(shù)的對(duì)象。也就是說,函數(shù)的 this 值是在函數(shù)被調(diào)用時(shí)確定的,在定義函數(shù)時(shí)確定不了(箭頭函數(shù)除外)。
var obj = { name: "Zavier Tang", foo: function () { console.log(this) console.log(this.name) } } obj.foo() // Object {name: "Zavier Tang", foo: function} // "Zavier Tang" //foo函數(shù)不是作為obj的方法調(diào)用 var fn = obj.foo // 這里foo函數(shù)并沒有執(zhí)行 fn() // Window {...} // undefined
this 的值同時(shí)也只受最靠近的成員引用的影響:
//接上面代碼 var o = { name: "Zavier Tang in object o", fn: fn, obj: obj } o.fn() // Object {name: "Zavier Tang in object o", fn: fn, obj: obj} // "Zavier Tang in object o" o.obj.foo() // Object {name: "Zavier Tang", foo: function} // "Zavier Tang"
在原型鏈中,this 的值為當(dāng)前對(duì)象:
var Foo = function () { this.name = "Zavier Tang" this.age = 20 } Foo.prototype.getInfo = function () { console.log(this.name) console.log(this.age) } var tang = new Foo() tang.getInfo() // "Zavier Tang" // 20
雖然這里調(diào)用的是一個(gè)繼承方法,但 this 所指向的依然是 tang 對(duì)象。
參考:《Object-Oriented JavaScript》(Second Edition)
3. 作為構(gòu)造函數(shù)如果函數(shù)作為構(gòu)造函數(shù),那函數(shù)當(dāng)中的 this 便是構(gòu)造函數(shù)即將 new 出來的對(duì)象:
var Foo = function () { this.name = "Zavier Tang", this.age = 20, this.year = 1998, console.log(this) } var tang = new Foo() console.log(tang.name) // "Zavier Tang" console.log(tang.age) // 20 console.log(tang.year) // 1998
當(dāng) Foo 不作為構(gòu)造函數(shù)調(diào)用時(shí),this 的指向便是前面討論的,指向全局變量:
// 接上面代碼 Foo() // window {...}4. 函數(shù)調(diào)用 apply、call、 bind 時(shí)
當(dāng)一個(gè)函數(shù)在其主體中使用 this 關(guān)鍵字時(shí),可以通過使用函數(shù)繼承自Function.prototype 的 call 或 apply 方法將 this 值綁定到調(diào)用中的特定對(duì)象。即 this 的值就取傳入對(duì)象的值:
var obj1 = { name: "Zavier1" } var obj2 = { name: "Zavier2" } var foo = function () { console.log(this) console.log(this.name) } foo.apply(obj1) // Ojbect {name: "Zavier1"} //"Zavier1" foo.call(obj1) // Ojbect {name: "Zavier1"} //"Zavier1" foo.apply(obj2) // Ojbect {name: "Zavier2"} //"Zavier2" foo.call(obj2) // Ojbect {name: "Zavier2"} //"Zavier2"
與 apply、call 不同,使用 bind 會(huì)創(chuàng)建一個(gè)與 foo 具有相同函數(shù)體和作用域的函數(shù)。但是,特別要注意的是,在這個(gè)新函數(shù)中,this 將永久地被綁定到了 bind 的第一個(gè)參數(shù),無論之后如何調(diào)用。
var foo = function () { console.log(this.name) } var obj1 = { name: "Zavier1" } var obj2 = { name: "Zavier2" } var g = foo.bind(obj1) g() // "Zavier1" var h = g.bind(ojb2) // bind只生效一次! h() // "Zavier1" var o = { name: "Zavier Tang", f:f, g:g, h:h } o.f() // "Zavier Tang" o.g() // "Zavier1" o.h() // "Zavier1"5. 箭頭函數(shù)
箭頭函數(shù)是 ES6 語法的新特性,在箭頭函數(shù)中,this 的值與創(chuàng)建箭頭函數(shù)的上下文的 this 一致。
在全局代碼中,this 的值為全局對(duì)象:
var foo = (() => this) //在瀏覽器中 foo() === window // true // 在node中 foo() === global // true
其實(shí)箭頭函數(shù)并沒有自己的 this。所以,調(diào)用 this 時(shí)便和調(diào)用普通變量一樣在作用域鏈中查找,獲取到的即是創(chuàng)建此箭頭函數(shù)的上下文中的 this。
當(dāng)箭頭函數(shù)在創(chuàng)建其的上下文外部被調(diào)用時(shí),箭頭函數(shù)便是一個(gè)閉包,this 的值同樣與原上下文環(huán)境中的 this 的值一致。由于箭頭函數(shù)本身是不存在 this,通過 call 、 apply 或 bind 修改 this 的指向是無法實(shí)現(xiàn)的。
作為對(duì)象的方法:
var foo = (() => this) var obj = { foo: foo } // 作為對(duì)象的方法調(diào)用 obj.foo() === window // true // 用apply來設(shè)置this foo.apply(obj) === window // true // 用bind來設(shè)置this foo = foo.bind(obj) foo() === window // true
箭頭函數(shù) foo 的 this 被設(shè)置為創(chuàng)建時(shí)的上下文(在上面代碼中,也就是全局對(duì)象)的 this 值,而且無法通過其他調(diào)用方式設(shè)定 foo 的 this 值。
與普通函數(shù)對(duì)比,箭頭函數(shù)的 this 值是在函數(shù)創(chuàng)建創(chuàng)建確定的,而且無法通過調(diào)用方式重新設(shè)置 this 值。普通函數(shù)中的 this 值是在調(diào)用的時(shí)候確定的,可通過不同的調(diào)用方式設(shè)定 this 值。
總結(jié)this 關(guān)鍵字的值取決于其所處的位置(上下文環(huán)境):
在全局環(huán)境中,this 的值指向全局對(duì)象( window 或 global )。
在函數(shù)內(nèi)部,this 的取值取決于其所在函數(shù)的調(diào)用方式,也就是說 this 的值是在函數(shù)被調(diào)用的時(shí)候確定的,在創(chuàng)建函數(shù)時(shí)無法確定。當(dāng)然,箭頭函數(shù)是個(gè)例外,箭頭函數(shù)本身不存在 this,而在箭頭函數(shù)中使用 this 獲取到的便是創(chuàng)建其的上下文中的 this。同時(shí),使用函數(shù)的繼承方法 call 、 apply 和 bind 會(huì)修改 this 的指向。但值得注意的是,使用 bind 方法會(huì)使 this 的值永久的綁定到給定的對(duì)象,無法再通過調(diào)用 call 和 apply 方法修改 this 的值,箭頭函數(shù)調(diào)用 call 、 apply 或 bind 方法無法修改 this。
原文鏈接
參考:
深入理解javascript原型和閉包(完結(jié)) - 王福朋 - 博客園
this - JavaScript | MDN
javascript中的this作用域詳解 - coder_Jenny - 博客園
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97896.html
摘要:在中,當(dāng)使用關(guān)鍵字調(diào)用函數(shù)構(gòu)造函數(shù)時(shí),函數(shù)構(gòu)造函數(shù)中也有這個(gè)概念,但是它不是惟一的規(guī)則,而且常??梢砸脕碜圆煌瑘?zhí)行上下文的不同對(duì)象。因此,我們使用調(diào)用函數(shù),可以看到這是對(duì)象,并且的屬性是正常的。 一直以來,javascript里邊的this都是一個(gè)很難理解的東西,之前看的最多的就是阮一峰老師關(guān)于this的理解: http://www.ruanyifeng.com/blo... htt...
摘要:然而,異步函數(shù)不會(huì)立即被推入調(diào)用堆棧,而是會(huì)被推入任務(wù)隊(duì)列,并在調(diào)用堆棧為空后執(zhí)行。將事件從任務(wù)隊(duì)列傳輸?shù)秸{(diào)用堆棧稱為事件循環(huán)。我們調(diào)用接受和或返回另一個(gè)函數(shù)稱為高階函數(shù)的函數(shù)。 為了保證可讀性,本文采用意譯而非直譯 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 1.如何理解 JS 中的this關(guān)鍵字? JS 初學(xué)者總是對(duì) this 關(guān)鍵字感到困惑,因?yàn)榕c其他現(xiàn)...
摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...
摘要:是完全的面向?qū)ο笳Z言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街校瑢?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來的。 JavaScript 函數(shù)式腳本語言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長期以來人們對(duì)這一門語言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽猓瑥膶?duì)語言感悟的角度闡述為什...
摘要:當(dāng)談到語言與其他編程語言相比時(shí),你可能會(huì)聽到一些令人困惑東西,其中之一是工廠函數(shù)和構(gòu)造函數(shù)。好的,讓我們用構(gòu)造函數(shù)做同樣的實(shí)驗(yàn)。當(dāng)我們使用工廠函數(shù)創(chuàng)建對(duì)象時(shí),它的指向,而當(dāng)從構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),它指向它的構(gòu)造函數(shù)原型對(duì)象。 showImg(https://segmentfault.com/img/bVbr58T?w=1600&h=900); 當(dāng)談到JavaScript語言與其他編程語言...
閱讀 2901·2021-11-22 09:34
閱讀 1223·2021-11-19 09:40
閱讀 3349·2021-10-14 09:43
閱讀 3578·2021-09-23 11:22
閱讀 1612·2021-08-31 09:39
閱讀 895·2019-08-30 15:55
閱讀 1422·2019-08-30 15:54
閱讀 864·2019-08-30 15:53