個人筆記,如有錯誤煩請指正
以下面代碼的運行舉例,一行行進行運行的解析
var x = [12, 23];
function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
fn(x);
console.log(x);
var x = [12, 23];
運行如下
x
x
指向堆內存的地址0x000000接著
function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
運行如下
上面這段代碼是創建一個函數的過程。和創建一個變量類似:
function fn(y){...}
時,相當于我們聲明了一個變量,只不過值是函數。類似于var fn = function (y){...}
的函數表達式。最終把一個函數作為值賦值給一個變量或者其他所以創建一個函數,詳細的執行順序如下
fn
,并且指向堆內存地址(假設為0x000001)fn(x);
運行如下(函數執行的步驟)
fn(x)
傳的是x
的值,即x
指向的0x000000堆內存地址fn(0x000000)
形成一個全新的私有上下文EC(fn)接著說說上面第5步的詳細步驟
把之前創建的函數,在堆內存中存儲的代碼字符串拿出來轉換為代碼一行一行的執行執行。
私有上下文中代碼執行中如果遇到一個變量,首先看是否為自己的'私有變量',如果是'私有'的,則操作自己的,和外界沒有必然的關系,如果不是自己私有的,則基于作用域鏈,向其上級上下文中查找,看是否為上級上下文中私有的,如果也不是,繼續向上查找......一直找到EC(G)全局上下文為止,我們把這種查找過程稱之為 作用域鏈查找機制
所以
y[0] = 100
y = [100]
y[1] = 200
是這樣的執行的:
y[0] = 100
,y
現在存儲的內存地址為0x000000,所以修改這個地址下的值:
y = [100]
,出現了新的對象值,所以要開辟新的堆內存0x000002,創建值,賦值
y[1] = 200
,將0x000002地址對應的對象的值進行修改
console.log(y);
這個y
就是0x000002對應的值[100,200]
操作的是私有變量y
fn
函數至此執行完畢。
接著執行外面的console.log(x);
,此時的x為全局變量對象中的x,對應的地址為0x000000,所以直接進行輸出[100,23]
如果fn
執行完之后,繼續執行其他函數,同樣會經歷這樣的流程。形成新的上下文,進棧執行...如果函數非常多,會一直進棧,占內存會越來越大。所以為了優化,瀏覽器會默認做出很多回收機制
js上下文(哪一個區域下執行)分類
私有變量是私有上下文聲明的變量,包含
var
/ let
/ const
/ function
...x
的值是0x000000,通過函數,將0x000000傳給了私有變量y
,y
也是0x000000function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
fn(x)