函數執行棧,在函數VO時入站,執行完AO時出棧ide
let a = 'Hello World!'; function first() { console.log('Inside first function'); second(); console.log('Again inside first function'); } function second() { console.log('Inside second function'); } first(); console.log('Inside Global Execution Context');
首先生命first入棧,以後生命second入棧,以後執行first可是first中執行了second,second執行完出棧,以後執行完first。函數
在執行上下文時,參數聲明,函數聲明,變量的聲明。
參數聲明》函數聲明》變量聲明若是變量對象已經包含了相同名字的屬性,則替換它的值
this
function foo1(a){ console.log(a) function a(){} } foo1(20)//'function a(){}'
此時console.log(a),已經完成了VO階段,也就上聲明階段,因爲函數後聲明,全部輸出爲函數。若是變量名和已經聲明的函數名或者函數的參數名相同,則不會影響已經存在的屬性
spa
function foo1(a){ console.log(a) function a(){} var a =1; } foo1(20)//'function a(){}'
函數的聲明比變量優先級要高,而且定義過程不會被變量覆蓋,除非是賦值指針
function foo(i){ var a = 'hello' var b = function(){} function c(){} } foo(22)
vo階段code
ECObj = { scopChain: {...}, variableObject: { arguments: { 0: 22, length: 1 }, i: 22, c: pointer to function c() a: undefined, b: undefined }, this: { ... } }
ao階段對象
ECObj = { scopeChain: { ... }, variableObject: { arguments: { 0: 22, length: 1 }, i: 22, c: pointer to function c() a: 'hello', b: pointer to function privateB() }, this: { ... } }
此時的console.log(typeof foo); console.log(typeof bar); 在函數的聲明以後階段(vo)blog
(function() { console.log(typeof foo); // 函數指針 console.log(typeof bar); // undefined var foo = 'hello', bar = function() { return 'world'; }; function foo() { return 'hello'; } }());
此時的console.log()爲執行以後階段(ao)作用域
(function() { var foo = 'hello', bar = function() { return 'world'; }; function foo() { return 'hello'; } console.log(typeof foo); // string console.log(typeof bar); // function }());