摘要:指向的改變構(gòu)造函數(shù)中的操作符會調(diào)用函數(shù)的內(nèi)部的方法,創(chuàng)建對象,之后調(diào)用函數(shù)的方法,把新創(chuàng)建對象作為值。調(diào)用函數(shù)時與設(shè)置的值以及箭頭函數(shù)皆為動態(tài)的改變指針的方法。這一特性使得箭頭函數(shù)在中的函數(shù)中使用起來很方便。
原文地址
JavaScript中的this 原理 錯誤的this指向通常所說的:如果是全局環(huán)境中,this指向全局對象,如果是對象的方法,這this指向這個對象。
例子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,后面都是全局對象。后三者并沒有指向foo。所以我們上面的通常說法不精確。
精確的this指向在全局環(huán)境中,this指向全局對象。而在普通函數(shù)調(diào)用中,this是由激活上下文的調(diào)用者提供,即調(diào)用這個函數(shù)的父作用域,以及函數(shù)調(diào)用的語法形式,決定了this的值,這是一個動態(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沒有指向foo。是什么導(dǎo)致this指向的變化呢?
this指向的內(nèi)部原理this是執(zhí)行上下文的一個屬性:
activeExecutionContext = { VO: {...}, this: thisValue }
在普通函數(shù)調(diào)用中,this是由激活上下文的調(diào)用者提供,即調(diào)用這個函數(shù)的父作用域,函數(shù)調(diào)用的語法形式,決定了this的值,這是一個動態(tài)可變的值。
為什么會引起這個差異呢?
因為引用類型的不同處理,是否會獲取真實的值,所導(dǎo)致的。
引用類型存在形式:
1 標(biāo)識符(變量名,函數(shù)名,函數(shù)參數(shù)名,全局對象屬性名)
2 屬性訪問器(foo.bar(); foo["bar"](), 點標(biāo)記法;可以動態(tài)設(shè)置屬性名的方括號[])
為了從引用類型中獲取真實的值,存在類似getValue的方法。而函數(shù)上下文的規(guī)則是,函數(shù)上下文中this由調(diào)用者提供,并由調(diào)用形式?jīng)Q定。如果調(diào)用的圓括號左側(cè)是一個引用類型,this為這個引用類型,如果是非引用類型,這為null,但為null無意義,被隱式轉(zhuǎn)化為全局對象。
為什么有this的特性?this是一個指針,便于代碼的更為簡潔地復(fù)用。
// 無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可以簡化上下文對象的傳遞。其他OPP語言中this關(guān)鍵字和OPP密切相關(guān),一般是引用剛創(chuàng)建的對象,但在ECMAScript中,this只限于引用創(chuàng)建過的對象,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操作符會調(diào)用函數(shù)的內(nèi)部的Construct方法,創(chuàng)建對象,之后調(diào)用函數(shù)的Call方法,把新創(chuàng)建對象作為this值。
2 調(diào)用函數(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皆為動態(tài)的改變this指針的方法。其中call和apply是當(dāng)Object沒有某個方法,但是其它對象有,可以借助call和apply改變this的指向,調(diào)用其它對象的方法。bind為綁定this為某個對象。
典型的應(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ù)沒有自己的this綁定,同時在函數(shù)執(zhí)行時綁定this會被直接忽略。其中this總是指向定義時所在的對象,而不是運行時所在的對象。即箭頭函數(shù)的this值是lexical
scope 的this值。這一特性使得箭頭函數(shù)在React中的render函數(shù)中使用起來很方便。
function foo() { setTimeout(() => { console.log("id: ", this.id) }, 100) } var id = 0 foo.call({id: 42}) // 容易誤解的地方 // {id: 42} // 是箭頭函數(shù)定義所在的對象還是運行時所在的對象。由于箭頭函數(shù)位于foo函數(shù)內(nèi)部,只有foo函數(shù)運行之后他才會生成,所以foo運行時所在的對象,即箭頭函數(shù)定義所在的對象。
var f = () => 5; // 近似等價于 var f = function() {return 5;}.bind(this);
綜上,call,apply,bind使得JavaScript具有動態(tài)改變this的特性,而箭頭函數(shù)使得JavaScript具有固定this的指向的特性。一動一靜,相得益彰。
在編程中的運用 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
可見super的綁定是靜態(tài)綁定,創(chuàng)建時即完成綁定。所以E委托了D,但并不能調(diào)用到D.foo(),類似于箭頭的函數(shù)的this綁定。
jQuery中的this鏈?zhǔn)秸{(diào)用的實現(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()的實現(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對象引用 ret.context = this.context return ret; }
pushStack函數(shù)在很多涉及DOM操作的函數(shù)都有調(diào)用,用于緩存了當(dāng)前的this。由于只存儲當(dāng)前,所以這里只需要一個preObject即可,無需放在一個數(shù)組里。
利與弊this是JavaScript特性之一,具有腳本語言的動態(tài)特性,帶來很多便捷,同時由于super和箭頭函數(shù)的特性,使得this具有了靜態(tài)的特性,在這兩種情況下,this是固定且無法改變的。其利與弊都是this的靈活,雙刃劍。所以才有了ES2015中super和箭頭函數(shù)的固定this的特性。
拾遺this可被重新賦值么?(不能,this是保留字)
問題(答案見原文)1 call參數(shù)為null時,this的指向
function a() { console.log(this) } a.call(null)
2 調(diào)用形式對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)識符解析,閉包的研究
深入ECMA-262-3 第三章、This
JavaScript內(nèi)部原理實踐——真的懂JavaScript嗎?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/81479.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 的值到底...
摘要:和類在開始時遇到類組件,只是需要有關(guān)類的基礎(chǔ)。畢竟,中的條件呈現(xiàn)僅再次顯示大多數(shù)是而不是特定的任何內(nèi)容。 在我的研討會期間,更多的材料是關(guān)于JavaScript而不是React。其中大部分歸結(jié)為JavaScript ES6以及功能和語法,但也包括三元運算符,語言中的簡寫版本,此對象,JavaScript內(nèi)置函數(shù)(map,reduce,filter)或更常識性的概念,如:可組合性,可重用...
摘要:對象在中,除了數(shù)字字符串布爾值這幾個簡單類型外,其他的都是對象。那么在函數(shù)對象中,這兩個屬性的有什么區(qū)別呢表示該函數(shù)對象的原型表示使用來執(zhí)行該函數(shù)時這種函數(shù)一般成為構(gòu)造函數(shù),后面會講解,新創(chuàng)建的對象的原型。這時的函數(shù)通常稱為構(gòu)造函數(shù)。。 本文原發(fā)于我的個人博客,經(jīng)多次修改后發(fā)到sf上。本文仍在不斷修改中,最新版請訪問個人博客。 最近工作一直在用nodejs做開發(fā),有了nodejs,...
摘要:所以相同點是,在全局范圍內(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)鍵字給困擾住了,我想混亂的根源來自人們理所當(dāng)然地認為中的應(yīng)該像中的或中的一樣工作。盡管有點難理解,但它的原理并不神秘。在瀏覽器中,全局對象是對象。運算符創(chuàng)建一個新對象并且設(shè)置函數(shù)中的指向調(diào)用函數(shù)的新對象。 原文:Understanding the this keyword in JavaScript 許多人被JavaScript中的this關(guān)鍵字給困擾住了,我想混亂的...
閱讀 2934·2023-04-26 02:23
閱讀 1764·2021-11-11 16:55
閱讀 3210·2021-10-19 11:47
閱讀 3446·2021-09-22 15:15
閱讀 2039·2019-08-30 15:55
閱讀 1102·2019-08-29 15:43
閱讀 1360·2019-08-29 13:16
閱讀 2262·2019-08-29 12:38