摘要:指向的改變構(gòu)造函數(shù)中的操作符會(huì)調(diào)用函數(shù)的內(nèi)部的方法,創(chuàng)建對(duì)象,之后調(diào)用函數(shù)的方法,把新創(chuàng)建對(duì)象作為值。調(diào)用函數(shù)時(shí)與設(shè)置的值以及箭頭函數(shù)皆為動(dòng)態(tài)的改變指針的方法。這一特性使得箭頭函數(shù)在中的函數(shù)中使用起來(lái)很方便。
原文地址
JavaScript中的this 原理 錯(cuò)誤的this指向通常所說(shuō)的:如果是全局環(huán)境中,this指向全局對(duì)象,如果是對(duì)象的方法,這this指向這個(gè)對(duì)象。
例子1:
var foo = { bar: function() { console.log(this) } } foo.bar(); (foo.bar)(); (foo.bar = foo.bar)(); (false || foo.bar)(); (foo.bar, foo.bar)();
例子1前兩者為foo,后面都是全局對(duì)象。后三者并沒(méi)有指向foo。所以我們上面的通常說(shuō)法不精確。
精確的this指向在全局環(huán)境中,this指向全局對(duì)象。而在普通函數(shù)調(diào)用中,this是由激活上下文的調(diào)用者提供,即調(diào)用這個(gè)函數(shù)的父作用域,以及函數(shù)調(diào)用的語(yǔ)法形式,決定了this的值,這是一個(gè)動(dòng)態(tài)可變的值。
例子2:
var foo = { bar: function() { console.log(this) console.log(this === foo) } } foo.bar() // foo, true var fn = foo.bar console.log(fn === foo.bar) // true fn() // global, false
例子2中,第一次調(diào)用指向foo,把foo.bar賦值給fn之后,this沒(méi)有指向foo。是什么導(dǎo)致this指向的變化呢?
this指向的內(nèi)部原理this是執(zhí)行上下文的一個(gè)屬性:
activeExecutionContext = { VO: {...}, this: thisValue }
在普通函數(shù)調(diào)用中,this是由激活上下文的調(diào)用者提供,即調(diào)用這個(gè)函數(shù)的父作用域,函數(shù)調(diào)用的語(yǔ)法形式,決定了this的值,這是一個(gè)動(dòng)態(tài)可變的值。
為什么會(huì)引起這個(gè)差異呢?
因?yàn)橐妙愋偷牟煌幚?,是否?huì)獲取真實(shí)的值,所導(dǎo)致的。
引用類型存在形式:
1 標(biāo)識(shí)符(變量名,函數(shù)名,函數(shù)參數(shù)名,全局對(duì)象屬性名)
2 屬性訪問(wèn)器(foo.bar(); foo["bar"](), 點(diǎn)標(biāo)記法;可以動(dòng)態(tài)設(shè)置屬性名的方括號(hào)[])
為了從引用類型中獲取真實(shí)的值,存在類似getValue的方法。而函數(shù)上下文的規(guī)則是,函數(shù)上下文中this由調(diào)用者提供,并由調(diào)用形式?jīng)Q定。如果調(diào)用的圓括號(hào)左側(cè)是一個(gè)引用類型,this為這個(gè)引用類型,如果是非引用類型,這為null,但為null無(wú)意義,被隱式轉(zhuǎn)化為全局對(duì)象。
為什么有this的特性?this是一個(gè)指針,便于代碼的更為簡(jiǎn)潔地復(fù)用。
// 無(wú)this function upper(context) { return context.name.toUpperCase() } function speak(context) { var greeting = "Hello, I"m " + upper(context) console.log(greeting) } var me = { name: "m" } var you = { name: "y" } speak(me) // 利用this function upper() { return this.name.toUpperCase() } function speak() { var greeting = "Hello, I"m " + upper.call(this) console.log(greeting) } speak.call(me)
這里this可以簡(jiǎn)化上下文對(duì)象的傳遞。其他OPP語(yǔ)言中this關(guān)鍵字和OPP密切相關(guān),一般是引用剛創(chuàng)建的對(duì)象,但在ECMAScript中,this只限于引用創(chuàng)建過(guò)的對(duì)象,this的指向和函數(shù)調(diào)用形式有關(guān),不一定引用類型調(diào)用就指向引用類型。
this指向的改變1 構(gòu)造函數(shù)中的this
function C() { console.log(this) this.x = 10 } var a = new C() console.log(a.x);
new操作符會(huì)調(diào)用函數(shù)的內(nèi)部的Construct方法,創(chuàng)建對(duì)象,之后調(diào)用函數(shù)的Call方法,把新創(chuàng)建對(duì)象作為this值。
2 調(diào)用函數(shù)時(shí)call與apply設(shè)置this的值
var b = 10 function a(c) { console.log(this.b) console.log(c) } a(20) a.call({b: 20}, 30) a.apply({b: 20}, [40])call, apply, bind以及箭頭函數(shù)
call,apply,bind皆為動(dòng)態(tài)的改變this指針的方法。其中call和apply是當(dāng)Object沒(méi)有某個(gè)方法,但是其它對(duì)象有,可以借助call和apply改變this的指向,調(diào)用其它對(duì)象的方法。bind為綁定this為某個(gè)對(duì)象。
典型的應(yīng)用:
將類數(shù)組元素轉(zhuǎn)化為數(shù)組:
Array.prototype.slice.apply(document.getElementsByTagName("*"))
檢查類型:
function isArray(obj) { return Object.prototpye.toString.call(obj) === "[object Array]" }
箭頭函數(shù)則與前三者不同。
If kind is Arrow, set the [[ThisModel]] internal slot of F to lexical.If the
value is "lexical", this is an ArrowFunction and does not have a local this
If thisModel is lexical, return NormalCompletion(undefined).
箭頭函數(shù)沒(méi)有自己的this綁定,同時(shí)在函數(shù)執(zhí)行時(shí)綁定this會(huì)被直接忽略。其中this總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。即箭頭函數(shù)的this值是lexical
scope 的this值。這一特性使得箭頭函數(shù)在React中的render函數(shù)中使用起來(lái)很方便。
function foo() { setTimeout(() => { console.log("id: ", this.id) }, 100) } var id = 0 foo.call({id: 42}) // 容易誤解的地方 // {id: 42} // 是箭頭函數(shù)定義所在的對(duì)象還是運(yùn)行時(shí)所在的對(duì)象。由于箭頭函數(shù)位于foo函數(shù)內(nèi)部,只有foo函數(shù)運(yùn)行之后他才會(huì)生成,所以foo運(yùn)行時(shí)所在的對(duì)象,即箭頭函數(shù)定義所在的對(duì)象。
var f = () => 5; // 近似等價(jià)于 var f = function() {return 5;}.bind(this);
綜上,call,apply,bind使得JavaScript具有動(dòng)態(tài)改變this的特性,而箭頭函數(shù)使得JavaScript具有固定this的指向的特性。一動(dòng)一靜,相得益彰。
在編程中的運(yùn)用 ES7中的::this.x = 0 let module = { x: 1, getX: function() { console.log(this.x) } } module.getX() let get = module.getX get() // 0 let boundGetX = get.bind(module) boundGetX() // 1 let ES7boundGetx = module::get ES7boundGetx() // 1super
class P { foo() { console.log("P.foo") } } class C extends P { foo() { super.foo() } } var c1 = new C() c1.foo() // P.foo var D = { foo: function() { console.log("D.foo") } } var E = { foo: C.prototype.foo } Object.setPrototypeOf(E, D) E.foo() // P.foo
可見(jiàn)super的綁定是靜態(tài)綁定,創(chuàng)建時(shí)即完成綁定。所以E委托了D,但并不能調(diào)用到D.foo(),類似于箭頭的函數(shù)的this綁定。
jQuery中的this鏈?zhǔn)秸{(diào)用的實(shí)現(xiàn);
function Constructor() { this.art = 0 } Constructor.prototype.fn_0 = function() { console.log("0") return this; } Constructor.prototype.fn_1 = function() { console.log("1") return this; } new Constructor().fn_0().fn_1()
調(diào)用的方法返回this即可。
end()的實(shí)現(xiàn)
function end() { return this.prevObject || this.constructor(null) } // 設(shè)置preObject的函數(shù) function pushStack( ele ) { // Build a new jQuery macthed element set var ret = jQuery.merge( this.constructor(), elems); ret.prevObject = this // ret.pervObject 設(shè)置為當(dāng)前jQuery對(duì)象引用 ret.context = this.context return ret; }
pushStack函數(shù)在很多涉及DOM操作的函數(shù)都有調(diào)用,用于緩存了當(dāng)前的this。由于只存儲(chǔ)當(dāng)前,所以這里只需要一個(gè)preObject即可,無(wú)需放在一個(gè)數(shù)組里。
利與弊this是JavaScript特性之一,具有腳本語(yǔ)言的動(dòng)態(tài)特性,帶來(lái)很多便捷,同時(shí)由于super和箭頭函數(shù)的特性,使得this具有了靜態(tài)的特性,在這兩種情況下,this是固定且無(wú)法改變的。其利與弊都是this的靈活,雙刃劍。所以才有了ES2015中super和箭頭函數(shù)的固定this的特性。
拾遺this可被重新賦值么?(不能,this是保留字)
問(wèn)題(答案見(jiàn)原文)1 call參數(shù)為null時(shí),this的指向
function a() { console.log(this) } a.call(null)
2 調(diào)用形式對(duì)this的影響
var foo = { bar: function() { console.log(this) } } foo.bar(); (foo.bar)(); (foo.bar = foo.bar)(); (false || foo.bar)(); (foo.bar, foo.bar)();參考資料:
《你所不知道的JavaScript(上卷)》
關(guān)于JavaScript的執(zhí)行域,標(biāo)識(shí)符解析,閉包的研究
深入ECMA-262-3 第三章、This
JavaScript內(nèi)部原理實(shí)踐——真的懂JavaScript嗎?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81479.html
摘要:理解的函數(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ī)?lái)幫助....(據(jù)說(shuō)是阿里的前端妹子寫的) this 的值到底...
摘要:和類在開始時(shí)遇到類組件,只是需要有關(guān)類的基礎(chǔ)。畢竟,中的條件呈現(xiàn)僅再次顯示大多數(shù)是而不是特定的任何內(nèi)容。 在我的研討會(huì)期間,更多的材料是關(guān)于JavaScript而不是React。其中大部分歸結(jié)為JavaScript ES6以及功能和語(yǔ)法,但也包括三元運(yùn)算符,語(yǔ)言中的簡(jiǎn)寫版本,此對(duì)象,JavaScript內(nèi)置函數(shù)(map,reduce,filter)或更常識(shí)性的概念,如:可組合性,可重用...
摘要:對(duì)象在中,除了數(shù)字字符串布爾值這幾個(gè)簡(jiǎn)單類型外,其他的都是對(duì)象。那么在函數(shù)對(duì)象中,這兩個(gè)屬性的有什么區(qū)別呢表示該函數(shù)對(duì)象的原型表示使用來(lái)執(zhí)行該函數(shù)時(shí)這種函數(shù)一般成為構(gòu)造函數(shù),后面會(huì)講解,新創(chuàng)建的對(duì)象的原型。這時(shí)的函數(shù)通常稱為構(gòu)造函數(shù)。。 本文原發(fā)于我的個(gè)人博客,經(jīng)多次修改后發(fā)到sf上。本文仍在不斷修改中,最新版請(qǐng)?jiān)L問(wèn)個(gè)人博客。 最近工作一直在用nodejs做開發(fā),有了nodejs,...
摘要:所以相同點(diǎn)是,在全局范圍內(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,...
摘要:原文許多人被中的關(guān)鍵字給困擾住了,我想混亂的根源來(lái)自人們理所當(dāng)然地認(rèn)為中的應(yīng)該像中的或中的一樣工作。盡管有點(diǎn)難理解,但它的原理并不神秘。在瀏覽器中,全局對(duì)象是對(duì)象。運(yùn)算符創(chuàng)建一個(gè)新對(duì)象并且設(shè)置函數(shù)中的指向調(diào)用函數(shù)的新對(duì)象。 原文:Understanding the this keyword in JavaScript 許多人被JavaScript中的this關(guān)鍵字給困擾住了,我想混亂的...
閱讀 2846·2023-04-26 02:23
閱讀 1594·2021-11-11 16:55
閱讀 3155·2021-10-19 11:47
閱讀 3370·2021-09-22 15:15
閱讀 1984·2019-08-30 15:55
閱讀 1045·2019-08-29 15:43
閱讀 1299·2019-08-29 13:16
閱讀 2203·2019-08-29 12:38