Javascript基礎語法學習介紹4_Function運行原理_Hosting、Scope與 ScopeChain觀念


我們於之前這篇
有簡單介紹function語法使用
但是那時還來不及詳細解說其中原理


Function運行原理

Function 之定義&調用示例
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//沒有參數的function
function myFunc(){
 console.log('This is no parameter function');
}
myFunc();
//有參數的function
function sum(a,b){
 var c = a+b;
 console.log(c);
}
sum(3,4);

每一個function於程式運行中途跑到該區function定義區域時
會自動建立一塊Execution Context之後
於function內部其實還會有兩階段過程運作

【Function 建立階段】

=>Stage1-1.初始化一個空間(Scope Chain)
=>Stage1-2.創建三種變數物件 VO (Variable Object)
第一種 function arguments object(參數物件)
第二種 function中的function之指標 object
第三種 function中的變數設值為undifined

1
2
3
4
function 函式名稱(參數物件){
 掃描function中的function - pointer
 掃描function中的variable - 設為undifined
}

=>Stage1-3.決定 this variable 的 值

【Function 運行階段】
=>進行逐行運行
======================================================================
這邊來一個簡單範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function myFunc(i){
 var a = 'Hi';
 var b = function innerFunc(){

 };
 function c(){

 }
}

myFunc(7);


Step1.創建(先掃描)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
//當function運行時
//會建立 execution Context 之後於function內部做創建
/*
myFunc_Execution_Context = {
 scopeChain: {....}, //Stage1-1.初始化空間(範圍鏈)
 //Stage1-2.創建變數物件
 variableObj:{ 
  //第一種VO:arguments object(參數物件)
  arguments:{
   0:7,
   length: 1
  }
  i:22,
  //第二種 function中的function之指標 object
  c:pointer to function c()
  //第三種 function中的變數設值為undifined
  b:undifined,
  a:undifined
 }
}
*/

Step2.運行(值真正傳入)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
/*
//運行階段
myFunc_Execution_Context = {
 scopeChain: {....}, //Stage2-1.初始化空間(範圍鏈)
 //Stage2-2.變數物件值傳入
 variableObj:{
  0:7,
  length: 1
 }
 i:22,
 c:pointer to function c(),
 b:pointer to function innerFunc(),
 a:'Hi'
}
*/







Hosting效應


正常Case1: 先定義後調用


特殊Case1: 先調用後定義


所以解析器早已在function建立時就知道function的存在了

緊接著再來看一個示例

正常Case2: 先定義後調用


特殊Case2: 先調用後定義


诶~~ 這裡會覺得納悶為何會出現錯誤

主要錯誤訊息再於Hosting效應只適用於function型態的宣告情況
不適用於將function指派於變數之陳述式情況
我們在上面兩case之所以都能正常運行
主要是因為是作為  function型態的呼叫

於這邊我們用變數來存放所以預設都會給予undefined!!!!

概念和下方是一樣的



這裡可以看到變數一開始尚未被解析器讀取到內容預設所給予的是undefined


下方還有一個例子


你會看到  myFunc我們自定義的函數會先調用對應區域變數輸出age=35
之後外部範圍讀取到的則為全域內容age=24


Scope與 ScopeChain觀念

一段JS code 於運行過程時會先建立Global Scope包含所有最上面定義
之變數或物件內容所以又可稱為Global Variale Object
之後每執行下去到特定區域就會包含Global Scope的內容可以去調用
當然first()函數中由於再內部呼叫second()之前已先有定義b變數值
所以也會傳入到second()區塊中

所以下方程式區塊共會切分開三個scope
Global Scope

first() function scope : 包含Global Scope  和first函數內部自己定義的VO

second() function scope : 包含Global Scope 、first函數內部定義的VO、自己second()的VO


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//====================Scope / Scope-Chain=============

//Global Scope (Global Variable Object)
//=========================================
var a = 'Hello';
first();
//=========================================

//first() function scope (variable object_1) + (Global Variable Object)
function first(){
 var b = 'Hi';
 second();
 //secod() function scope (variable object_1)+(variable object_2) + (Global Variable Object)
 function second(){
  var c = 'Hey';
  console.log(a+b+c);
 }
}






所謂的Scope就是我們俗稱的作用範圍

我們說全域區塊(外圍)有自己的Global Scope
那各自函式中也有自己的Local Scope
你可以在Local Scope中去調用 Global Scope的內容
或是 內部子函式Scope可以調用上一層的Local Scope(只要有包含在其中)
所以連著一系列Scope一條鍊條就形成了 Scope Chain

如下再來一範例
主要可以去觀察所謂ScopeChain有包含的Scope在不同地方呼叫的限制



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Global Scope (Global Variable Object)
//=========================================
var a = 'Hello';
first();
//=========================================

//first() function scope (variable object_1) + (Global Variable Object)
function first(){
 var b = 'Hi';
 second();
 //secod() function scope (variable object_1)+(variable object_2) + (Global Variable Object)
 function second(){
  var c = 'Hey';
  third();
 }
}

function third(){
 var d = 'Jimmy';
 console.log(a+b+c+d);
 //console.log(a+d);
}


這段程式碼會有錯誤無法運行輸出

其Scope Chain 只包含
Global Scope
Global Variable Object: a = 'Hello'
Local Scope
Local Variable Object: d = 'Jimmy'

而不包含 first() Scope 及 second() 所以
若將其改成輸出a+d
去除 b 跟 c 則可正常運行



以上是所謂的  Scope與 ScopeChain觀念




留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header