Javascript執(zhí)行上下文順序的深入講解
一 執(zhí)行上下文?
1什么是執(zhí)行上下文?
執(zhí)行上下文就是當(dāng)前的 JavaScript 代碼被解析和執(zhí)行時(shí)所在環(huán)境的抽象概念, JavaScript 中運(yùn)行任何的代碼都是在執(zhí)行上下文中運(yùn)行的.
2 執(zhí)行上下文的類型
執(zhí)行上下文分為三種類型:
全局執(zhí)行上下文:只有一個(gè),這是默認(rèn)的,也是基礎(chǔ)的執(zhí)行上下文.(不在任何函數(shù)中的代碼都是全局執(zhí)行上下文)他有兩個(gè)作用,一個(gè)是創(chuàng)建了全局變量,也就是指向window下的變量,另一個(gè)是將this的指向全局.
函數(shù)執(zhí)行上下文:有無(wú)數(shù)個(gè),每個(gè)函數(shù)都擁有自己的執(zhí)行上下文,但是只有在函數(shù)被調(diào)用的時(shí)候才會(huì)被創(chuàng)建,每次調(diào)用時(shí),都會(huì)為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文…
Eval 函數(shù)執(zhí)行上下文: 指的是運(yùn)行在 eval 函數(shù)中的代碼,很少用而且不建議使用。
二 執(zhí)行上下文的生命周期
1.創(chuàng)建階段
執(zhí)行上下文的生命周期有三個(gè)階段:創(chuàng)建階段–執(zhí)行階段—回收階段(主要說(shuō)創(chuàng)建階段)
當(dāng)函數(shù)被調(diào)用,但沒(méi)有執(zhí)行任何其內(nèi)部代碼之前,會(huì)先確定這三個(gè)步驟:
1) 創(chuàng)建變量對(duì)象:首先初始化函數(shù)的參數(shù) arguments,提升函數(shù)聲明和變量聲明
2) 創(chuàng)建作用域鏈:在執(zhí)行期上下文的創(chuàng)建階段,作用域鏈?zhǔn)窃谧兞繉?duì)象之后創(chuàng)建的.作用域鏈本身包含變量對(duì)象。
作用域鏈用于解析變量。當(dāng)被要求解析變量時(shí),JavaScript 始終從代碼嵌套的最內(nèi)層開始,如果最內(nèi)層沒(méi)有
找到變量,就會(huì)跳轉(zhuǎn)到上一層父作用域中查找,直到找到該變量。
3) 確定 this 指向:有多種情況.
2. 執(zhí)行階段
執(zhí)行變量賦值、代碼執(zhí)行
3. 回收階段
執(zhí)行上下文出棧等待虛擬機(jī)回收?qǐng)?zhí)行上下文
三. 變量提升和this的指向
1.變量聲明提升:
大部分編程語(yǔ)言都是先聲明變量再使用,但在 JS 中,事情有些不一樣:
console.log(a); // undefined var a = 10;
上述代碼正常輸出undefined而不是報(bào)錯(cuò)Uncaught ReferenceError: a is not defined,這是因?yàn)槁暶魈嵘?
相當(dāng)于:
var a; //聲明 默認(rèn)值是undefined “準(zhǔn)備工作” console.log(a); a = 10; //賦值
2. 函數(shù)聲明提升
創(chuàng)建函數(shù)的方法有兩種,一種是通過(guò)函數(shù)聲明function aa(){}
另一種是通過(guò)函數(shù)表達(dá)式var aa = function(){} ,那這兩種在函數(shù)提升有什么區(qū)別呢?
console.log(f1); // function f1(){} function f1() {} // 函數(shù)聲明 console.log(f2); // undefined var f2 = function() {}; // 函數(shù)表達(dá)式
接下來(lái)我們通過(guò)一個(gè)例子來(lái)說(shuō)明這個(gè)問(wèn)題:
function test() { aa(); // Uncaught TypeError "aa is not a function" bar(); // "this will run!" var aa = function() { // function expression assigned to local variable 'aa' alert("this won't run!"); }; function bar() { // function declaration, given the name 'bar' alert("this will run!"); } } test();
在上面的例子中,aa()調(diào)用的時(shí)候報(bào)錯(cuò)了,而 bar 能夠正常調(diào)用。
我們前面說(shuō)過(guò)變量和函數(shù)都會(huì)上升,遇到函數(shù)表達(dá)式 var aa = function(){}時(shí),首先會(huì)將var aa上升到函數(shù)體頂部,然而此時(shí)的 aa 的值為 undefined,所以執(zhí)行aa()報(bào)錯(cuò)。
而對(duì)于函數(shù)bar(), 則是提升了整個(gè)函數(shù),所以bar()才能夠順利執(zhí)行。
細(xì)節(jié)必須注意:當(dāng)遇到函數(shù)和變量同名且都會(huì)被提升的情況,函數(shù)聲明優(yōu)先級(jí)比較高,因此變量聲明會(huì)被函數(shù)聲明所覆蓋,但是可以重新賦值。
alert(a); //輸出:function a(){ alert('我是函數(shù)') } function a() { alert("我是函數(shù)"); } // var a = "我是變量"; alert(a); //輸出:'我是變量'
function 聲明的優(yōu)先級(jí)比 var 聲明高,也就意味著當(dāng)兩個(gè)同名變量同時(shí)被 function 和 var 聲明時(shí),function 聲明會(huì)覆蓋 var 聲明
這代碼等效于:
function a() { alert("我是函數(shù)"); } var a; //hoisting alert(a); //輸出:function a(){ alert('我是函數(shù)') } a = "我是變量"; //賦值 alert(a); //輸出:'我是變量'
3. 確定this指向
// 情況1 function foo() { console.log(this.a) //1 } var a = 1 foo() // this->window // 情況2 function fn(){ console.log(this); } var obj={fn:fn}; obj.fn(); //this->obj // 情況3 function CreateJsPerson(name,age){ //this是當(dāng)前類的一個(gè)實(shí)例p1 this.name=name; //=>p1.name=name this.age=age; //=>p1.age=age } var p1=new CreateJsPerson("尹華芝",48); // 情況4 function add(c, d){ return this.a + this.b + c + d; } var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 // 情況5 <button id="btn1">箭頭函數(shù)this</button> <script type="text/javascript"> let btn1 = document.getElementById('btn1'); let obj = { name: 'kobe', age: 39, getName: function () { btn1.onclick = () => { console.log(this);//obj }; } }; obj.getName(); </script>
結(jié)果:
1 this指向window;
2誰(shuí)調(diào)用了函數(shù),誰(shuí)就是 this,所以在這個(gè)場(chǎng)景下 foo 函數(shù)中的 this 就是 obj 對(duì)象
3 在構(gòu)造函數(shù)中,this 是當(dāng)前類的一個(gè)實(shí)例
4call、apply 和 bind:this 是第一個(gè)參數(shù)
5箭頭函數(shù) this 指向:箭頭函數(shù)沒(méi)有自己的 this,看其外層的是否有函數(shù),如果有,外層函數(shù)的 this 就是內(nèi)部箭頭函數(shù)的 this,如果沒(méi)有,則 this 是 window。
到此這篇關(guān)于Javascript執(zhí)行上下文順序的文章就介紹到這了,更多相關(guān)Javascript執(zhí)行上下文順序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- js bind 函數(shù) 使用閉包保存執(zhí)行上下文
- JS ES6中setTimeout函數(shù)的執(zhí)行上下文示例
- 深入理解JavaScript 中的執(zhí)行上下文和執(zhí)行棧
- 一篇文章弄懂javascript中的執(zhí)行棧與執(zhí)行上下文
- JavaScript ECMA-262-3 深入解析(一):執(zhí)行上下文實(shí)例分析
- 通過(guò)實(shí)例了解JS執(zhí)行上下文運(yùn)行原理
- js 執(zhí)行上下文和作用域的相關(guān)總結(jié)
- 詳解JavaScript中的執(zhí)行上下文及調(diào)用堆棧
- 深入學(xué)習(xí)JavaScript執(zhí)行上下文
相關(guān)文章
javascript中創(chuàng)建對(duì)象的三種常用方法
在javascript中創(chuàng)建對(duì)象的三種方法,腳本之家以前發(fā)布過(guò)有簡(jiǎn)單實(shí)例版的,大家可以參考下。2010-12-12Bootstrap彈出框modal上層的輸入框不能獲得焦點(diǎn)問(wèn)題的解決方法
這篇文章主要介紹了Bootstrap彈出框modal上層的輸入框不能獲得焦點(diǎn)問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12JS設(shè)置cookie、讀取cookie、刪除cookie
Js操作Cookie總結(jié)(設(shè)置,讀取,刪除),工作中經(jīng)常會(huì)用到的哦!下面是詳細(xì)代碼,如有錯(cuò)誤,請(qǐng)留言指正!2015-04-04Javascript學(xué)習(xí)之談?wù)凧S的全局變量跟局部變量(推薦)
這篇文章主要介紹了Javascript學(xué)習(xí)之談?wù)凧S的全局變量跟局部變量雖然腳本之家小編以前發(fā)過(guò),但還是這篇文章整理的比較好,需要的朋友可以參考一下2016-08-08微信小程序?qū)崿F(xiàn)密碼顯示與隱藏的睜眼閉眼功能
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)密碼顯示與隱藏的睜眼閉眼功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-02-02詳解XMLHttpRequest(一)同步請(qǐng)求和異步請(qǐng)求
這篇文章主要為大家詳細(xì)介紹了XMLHttpRequest 同步請(qǐng)求和異步請(qǐng)求,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09微信小程序中如何使用flyio封裝網(wǎng)絡(luò)請(qǐng)求
這篇文章主要介紹了微信小程序中如何使用flyio封裝網(wǎng)絡(luò)請(qǐng)求,F(xiàn)ly.js 通過(guò)在不同 JavaScript 運(yùn)行時(shí)通過(guò)在底層切換不同的 Http Engine來(lái)實(shí)現(xiàn)多環(huán)境支持,但同時(shí)對(duì)用戶層提供統(tǒng)一、標(biāo)準(zhǔn)的Promise API,需要的朋友可以參考下2019-07-07javascript實(shí)現(xiàn)動(dòng)態(tài)增加刪除表格行(兼容IE/FF)
javascript實(shí)現(xiàn)動(dòng)態(tài)增加刪除表格行(兼容IE/FF)...2007-04-04javascript中this做事件參數(shù)相關(guān)問(wèn)題解答
有關(guān)this想必大家早有所耳聞,只不過(guò)在使用中不是那么在意而已,接下來(lái)為大家介紹下this做事件參數(shù)問(wèn)題,感興趣的你可不要錯(cuò)過(guò)了哈2013-03-03