摘要:當(dāng)中的是一個用于指向當(dāng)前上下文對象的關(guān)鍵字。創(chuàng)建實例時的構(gòu)造函數(shù)中的,永遠(yuǎn)指向那個實例后對象,不是外部環(huán)境使用來調(diào)用函數(shù)時,先改變其上下文環(huán)境,在對其構(gòu)造函數(shù)進(jìn)行調(diào)用。
上下文對象概念javascript 當(dāng)中的 this是一個用于指向當(dāng)前上下文對象的關(guān)鍵字。在面向?qū)ο缶幊碳叭粘i_發(fā)當(dāng)中我們經(jīng)常與其打交道,初學(xué)javscript的朋友非常容易誤入歧途從而理解錯誤。
在我的深入貫徹閉包思想一章中其實已經(jīng)講了很多關(guān)于環(huán)境棧(即上下文對象)的相關(guān)內(nèi)容,但內(nèi)容過于冗長,不便閱讀,時間充足的同學(xué)可以去看下,但這篇中,我們還是獨立開來,下面我總結(jié)了幾條有關(guān)上下文的知識,希望能幫助大家。
首先需要聲明的是這些術(shù)語的問題,其實我們常說的環(huán)境棧,調(diào)用棧,上下文棧 等等很多民間自創(chuàng)術(shù)語,它們形容的都是一個東東,即環(huán)境棧(這里我就拿第一個詞來形容了,大家知道就好)
執(zhí)行上下文棧 (Execution context stack, ECS)javascript代碼塊有三種運行環(huán)境分別是:
1.全局(Global code)
默認(rèn)執(zhí)行環(huán)境,也就是沒有任何函數(shù)包裹在window下執(zhí)行的代碼片段。
//window var a = 12; (function(){ a = 13; }())
就比如這兩段代碼前者在全局window下執(zhí)行了一個新建變量與賦值的操作。后者是一個匿名自調(diào)函數(shù),它的上下文一定是Global,所以,無論在哪里運行它,它只能訪問自身的活動對象以及Global的變量對象。
2.函數(shù)(Function code)
function fun(){ a = 24; return a; } var foo = new Function("var a = 12; return a;"); foo(); fun();
除外的Function它表示在函數(shù)當(dāng)中執(zhí)行的代碼.
3.eval (Eval code)
以上兩種情況指的是在特定情境下的代碼片段,但是不包括另一種情況,也就是eval環(huán)境 (這里應(yīng)指動態(tài)環(huán)境,因為據(jù)我所知以目前JS版本,只有eval可以創(chuàng)建動態(tài)執(zhí)行環(huán)境吧? )。
var codeStr = "var a = 12"; eval(codeStr);
以上三種執(zhí)行上下文構(gòu)成了執(zhí)行上下文棧(ECS),在整個棧中有依次排列的上下文(Execution Context),位于最底層的是Global全局環(huán)境,上面依次是函數(shù)執(zhí)行環(huán)境。而eval則會在運行中javascript引擎臨時去創(chuàng)建,也就是沒有在預(yù)編譯前幾毫秒進(jìn)行編譯代碼整合。
在每個EC當(dāng)中存有幾個特別重要的屬性,變量對象,作用域鏈,this指向
變量對象(Variable Object,VO)
變量
函數(shù)的聲明
函數(shù)的參數(shù)
作用域鏈(Scope Chain)
構(gòu)成作用域的開山鼻祖? (確切的說應(yīng)該是詞法作用域,但不能排除eval創(chuàng)建的動態(tài)環(huán)境)
this 指向
沒錯,它儲存一個對象的引用地址,但不是在詞法階段定義的,而是在運行時綁定的,它引用的值取決于函數(shù)調(diào)用時的各種條件。只取決于函數(shù)的調(diào)用方式。
變量對象里面存儲了在上下文中定義的變量和函數(shù)聲明。在函數(shù)上下文環(huán)境下不能直接使用變量對象,而是要等到執(zhí)行流進(jìn)入當(dāng)前環(huán)境下來激活,被稱作活動對象
注:上面說了在一個EC中它們是屬于特別重要的屬性(其構(gòu)成了最基本的作用域規(guī)則),也就是說還有其他javascript內(nèi)部實現(xiàn)需要的屬性,它們大概包含函數(shù)的調(diào)用方式,在哪里被調(diào)用等等.
好了整理一下,`在這一小節(jié)里面,我們大致了解了ECS及EC的概念以及this與他們的關(guān)系及其this的定義.
使用 this// Global Context var obj = { fun:()=>()=>{ console.log(this); }, foo:()=>{ console.log(this); } } obj.foo.name = "tongtong"; /* 把foo函數(shù)轉(zhuǎn)賦給context變量,這時foo函數(shù)對象身上的屬性是具備`復(fù)合類型條件`的,即引用. */ var context = obj.foo; //通過返回的函數(shù)來二次調(diào)用,同樣屬于全局環(huán)境下,因為內(nèi)部函數(shù)調(diào)用時已經(jīng)不屬于obj對象了. obj.fun()(); //window context(); //window context.name; // "tongtong"
函數(shù)不是簡單類型值,是復(fù)合類型,我們一樣可以用.操作符像對待對象一樣為它添加屬性與方法。與其他兩位小伙伴(Array Object)不同的是,它可以調(diào)用呀。只要調(diào)用環(huán)境變化了,this當(dāng)然也就隨波逐流。
以上這個例子,我們需要注意,在把它們賦給其他變量時,由于它的執(zhí)行環(huán)境是會變化的,即每次調(diào)用都會刷新this,對于新手來說,這點一定要搞清楚。
//global Context //no.1 (function(){ console.log(this); }()) //window //no.2 var x = 12; var foo = function(){ this.x = 12; } new foo(); x //12
在閉包中this是指向window的. 如若不然呢?它沒有任何調(diào)用者,它是自調(diào),只能是window,也可以這樣理解 : 所有以函數(shù)調(diào)用的方式this一定是window,即foo()。而 obj.foo(); new foo()它們的this是有意義的。
創(chuàng)建實例時的構(gòu)造函數(shù)中的this,永遠(yuǎn)指向那個實例后對象,不是外部環(huán)境. 使用new來調(diào)用函數(shù)時,先改變其上下文環(huán)境,在對其構(gòu)造函數(shù)進(jìn)行調(diào)用。對順序不清楚的同學(xué),請自行查閱關(guān)于 javascript生成實例步驟.
call 與 apply這兩個方法位于Function.prototype,擁有更改上下文的功能,前者需手動填寫函數(shù)參數(shù),后者可以通過數(shù)組來表示。
// Global Context var obj = {}; //call var foo = function(num){ console.log(this); console.log(num + 8); }; foo.call(12); // obj 20 foo(12); //window 12 //apply var fun = function(){ console.log(this); console.log(Object.prototype.slice.call(arguments).redux((x,y)=> x + y); ) } fun.call(obj,[12,34,56,78]); fun(null,[12,34,56,78]);
他們都把第一個參數(shù)作為上下文并調(diào)用。那么如何更改一個函數(shù)的上下文調(diào)用環(huán)境呢?我們以bind來簡單模擬一下。
var _bind = function(fun,context){ //取第一個之后的參數(shù)列表. var params = [].slice.call(arguments).slice(2); //給我們的函數(shù)指定上下文對象。 context.fun = fun; return function(){ var result = params.concat(Array.from(arguments)); return context.fun(result)}; }
至于call,apply方法的模擬實現(xiàn),這里就不說了,感興趣的童鞋可以去網(wǎng)上搜索一下.
常見面試題var a = “111”; var b = “222”; function test() { var a = “333”; var b = “444”; alert(this.a); alert(this.b); } var test= new test() ; alert(test.a); alert(test.b);
在創(chuàng)建一個實例時,它的類內(nèi)部的this必然是這個實例。他的順序大致是
創(chuàng)建上下文環(huán)境
執(zhí)行構(gòu)造函數(shù)
把構(gòu)造函數(shù)的prototype,放到實例的原型上
這里我們只需要知道它先創(chuàng)建上下文,再進(jìn)行調(diào)用構(gòu)造函數(shù).
var obj = { Pagination:function(){ return this; } }; new obj.Pagination(); // Pagination {}
查找this的機(jī)制與作用域一致,都是就近原則。
setTimeout(function(){ return this; },0); //window
setTimeout回調(diào)的執(zhí)行環(huán)境下的this對象是window,幾乎瀏覽器的所有原生方法回調(diào)函數(shù)的this都是window,但是如果我們在其場景使用回調(diào),這個this就變成不可預(yù)期的了,因為我們不知道此函數(shù),到底在哪里執(zhí)行了.
憶之獲this是執(zhí)行時決定的,也可以說函數(shù)調(diào)用時,決定的。
EC中附帶的三類對象(非全部),其中this作為其中一員,每次執(zhí)行流進(jìn)入EC時,它都有可能會更新。而this的改變正是依賴這種現(xiàn)象。
this使用就近原則,從當(dāng)前環(huán)境向外延伸,直至找到離它最近的那個對象為止。
列表項目
題外話我特別希望大家能在文章中給我提出意見,文中內(nèi)容都是博主個人理解,算不上是對的,所以我建議大家只做參考,或看其他類似文章做一個自己的總結(jié),每個人理解javascript都不一樣,如果不看底層編譯原理,在這個層面之上,我們只能靠這種方法理解了。。。但是記住,凡事都要自己求證的,別人說的是他人的觀點,自己理解出來的才是最適合你的.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/89220.html
摘要:閉包閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)當(dāng)某個函數(shù)被調(diào)用時,會創(chuàng)建一個執(zhí)行環(huán)境及相應(yīng)的作用域鏈。要注意通過第句聲明的這個方法屬于構(gòu)造函數(shù)生成的對象,而不屬于構(gòu)造函數(shù)的變量對象,也就是說,并不存在于作用域鏈中。 看到評論里有仁兄建議我試試箭頭函數(shù),真是受寵若驚,本來寫這篇文章也只是想記錄寫要點給自己日后看的。今天早上看到一篇總結(jié)javascript中this的文章JavaScr...
摘要:其實它們都很簡單,但是在處理一些與相關(guān)的函數(shù)的時候,用來改變函數(shù)中的指向,卻是必不可少的工具,所以必須掌握好它們的用法。 關(guān)于javascript中的bind、call、apply等函數(shù)的用法 我GitHub上的菜鳥倉庫地址: 點擊跳轉(zhuǎn)查看其他相關(guān)文章 文章在我的博客上的地址: 點擊跳轉(zhuǎn) ? ? ? ? 前面的文章已經(jīng)說到this的指向了,那么這篇文章就要說一說和this相關(guān)的三個...
摘要:關(guān)于中的坑大家都踩過。那這里的和是嚴(yán)格相等的。這里介紹的是通過創(chuàng)建對象時的。提示一下,數(shù)組對象的函數(shù)本身就是有這個功能的,也就是說可以達(dá)到要求。事件有兩種記法,一個是也是類似,那么在中出現(xiàn)的表示觸發(fā)該事件的元素,也就是。 TL;DR: this 指向調(diào)用該方法的對象,只有函數(shù)執(zhí)行時,this 才有定義。 關(guān)于 JavaScript 中 this 的坑大家都踩過。像本文開頭的這句話,道理...
摘要:函數(shù)的調(diào)用有五種模式方法調(diào)用模式,函數(shù)調(diào)用模式,構(gòu)造器調(diào)用模式,調(diào)用模式以及回調(diào)模式,下面分別對這幾種模式進(jìn)行說明。構(gòu)造器調(diào)用模式構(gòu)造函數(shù)的調(diào)用方式被稱為構(gòu)造器調(diào)用模式,這是模擬類繼承式語言的一種調(diào)用方式。 函數(shù)的調(diào)用有五種模式:方法調(diào)用模式,函數(shù)調(diào)用模式,構(gòu)造器調(diào)用模式,apply/call調(diào)用模式以及回調(diào)模式,下面分別對這幾種模式進(jìn)行說明。 1.函數(shù)調(diào)用與方法調(diào)用模式: 1.1 聲...
摘要:關(guān)于中的指向我上的菜鳥倉庫地址點擊跳轉(zhuǎn)查看其他相關(guān)文章文章在我的博客上的地址點擊跳轉(zhuǎn)學(xué)習(xí),必不可少的肯定要理解的指向。 關(guān)于javascript中this的指向 我GitHub上的菜鳥倉庫地址: 點擊跳轉(zhuǎn)查看其他相關(guān)文章 文章在我的博客上的地址: 點擊跳轉(zhuǎn) ? ? ? ? 學(xué)習(xí)javascript,必不可少的肯定要理解this的指向。要學(xué)習(xí)this指向之前,就要先理解了我前面寫的幾...
閱讀 3583·2021-11-15 11:36
閱讀 1073·2021-11-11 16:55
閱讀 712·2021-10-20 13:47
閱讀 3034·2021-09-29 09:35
閱讀 3461·2021-09-08 10:45
閱讀 2562·2019-08-30 15:44
閱讀 860·2019-08-30 11:10
閱讀 1438·2019-08-29 13:43