javascript
delphi 函数内创建对象 释放_JavaScript 的函数底层运行机制
目錄0 / 題(1)第一題(2)第二題1 / 引用數(shù)據(jù)類型:object2 / 引用數(shù)據(jù)類型:function(1)第二題,簡圖(2)創(chuàng)建函數(shù)(3)執(zhí)行函數(shù)(4)閉包3 / 練習(xí)題(1)第一題(2)第二題(3)第三題
0 / 題
(1)第一題
var a = {n: 1}; var b = a; a.x = a = {n: 2}; console.log(a.x); console.log(b);△ 引用數(shù)據(jù)類型:object
(2)第二題
var x = [12, 23]; function fn(y) { y[0] = 100; y = [100]; y[1] = 200; console.log(y); } fn(x); console.log(x);△ 引用數(shù)據(jù)類型:function
這些題是不是很簡單?我們主要看邏輯:
1 / 引用數(shù)據(jù)類型:object
在Web瀏覽器中執(zhí)行JS代碼,會開辟一塊棧內(nèi)存來作為執(zhí)行環(huán)境:ECStack(Execution Context Stack)
會開辟一塊棧內(nèi)存供全局代碼執(zhí)行:全局執(zhí)行上下文 EC(G)(Execution Context Global),還有其他的上下文:函數(shù)私有執(zhí)行上下文、塊級私有上下文…… 自己管好自己那一攤的代碼執(zhí)行內(nèi)容
形成的執(zhí)行上下文都會 進(jìn)棧 到執(zhí)行環(huán)境棧中運行.私有上下文會在不被占用時出棧釋放,瀏覽器的回收機(jī)制GC.當(dāng)瀏覽器關(guān)閉時,全局執(zhí)行上下文就會出棧釋放了
△ 圖2.1_第一題,簡圖
GO:全局對象 Global Object ,并不是VO(G)全局變量對象 Variable Object Global
全局對象,它是個對象,它就是個堆內(nèi)存,瀏覽器打開一加載頁面就默認(rèn)開辟的堆內(nèi)存。
瀏覽器提供的一些供JS調(diào)用的API,在Web瀏覽器中,全局對象可以通過window來訪問的
?注意:運算符優(yōu)先級,要多看看多比劃比劃
注意:基本數(shù)據(jù)類型值直接存儲在棧內(nèi)存中,引用數(shù)據(jù)類型值存在堆內(nèi)存中
2 / 引用數(shù)據(jù)類型:function
var x = [12, 23]; function fn(y) { y[0] = 100; y = [100]; y[1] = 200; console.log(y); } fn(x); console.log(x);△ 函數(shù)執(zhí)行
(1)第二題,簡圖
△ 圖2.2_函數(shù)執(zhí)行
△ 圖2.3_數(shù)組的格式:鍵值對
(2)創(chuàng)建函數(shù)
創(chuàng)建函數(shù)的步驟:【和創(chuàng)建變量區(qū)別不是很大,函數(shù)名就是變量名】
① 單獨開辟一個堆內(nèi)存:16進(jìn)制地址,函數(shù)堆內(nèi)存中存儲的是函數(shù)體中的代碼字符串
② 創(chuàng)建函數(shù)的時候,就聲明了它的作用域[[scope]],也就是所在的上下文環(huán)境
③ 把16進(jìn)制地址(16進(jìn)制以0x開頭)存放到棧中,供函數(shù)名變量名關(guān)聯(lián)引用即可
只創(chuàng)建函數(shù),不執(zhí)行函數(shù),沒啥意義,那就是一堆字符串。
函數(shù)執(zhí)行的目的:把創(chuàng)建函數(shù)的時候在堆內(nèi)存中存儲的 代碼字符串 變?yōu)榇a執(zhí)行
代碼執(zhí)行一定會有一個執(zhí)行的環(huán)境,它的上級執(zhí)行上下文,是函數(shù)創(chuàng)建的地方
函數(shù)執(zhí)行會形成一個全新的、私有的執(zhí)行上下文,在私有上下文中,也有存放自己變量的對象:AO(Active Object 活動對象),它是VO的一種。
變量對象: ① 在全局上下文中:VO ?② 在私有上下文中:AO
實參都是值。形參是變量。
fn(x):執(zhí)行函數(shù)fn,把全局上下文中存儲的x變量關(guān)聯(lián)的值(0x000001),作為實參傳遞給函數(shù)的形參變量
(3)執(zhí)行函數(shù)
執(zhí)行函數(shù)做了哪些事情:
1、形成了一個全新的、私有的執(zhí)行上下文EC(xxx)
2、當(dāng)前私有的上下文中,有一個存放此上下文內(nèi)聲明的變量的地方 AO(xxx) 私有變量對象
① 形參變量
② 當(dāng)前上下文中聲明的變量
3、進(jìn)棧執(zhí)行
4、代碼執(zhí)行之前還要處理很多事情:
① 初始化作用域鏈
[[scope-chain]]:
(作用域鏈有兩頭,一頭是自己執(zhí)行的上下文,另一頭是自己創(chuàng)建時所在的上下文)
即:當(dāng)前函數(shù)的上級上下文是創(chuàng)建函數(shù)所在的上下文,就是作用域
以后再遇到函數(shù)內(nèi)的代碼執(zhí)行,遇到一個變量,首先看是否為自己上下文中的私有變量(看AO中有沒有,有,是自己私有的;沒有,不是自己私有的)。如果是私有的變量,則當(dāng)前變量的操作和外界環(huán)境中的變量互不干擾(沒有直接關(guān)系);如果不是自己的私有變量,則按照作用域鏈,查找是否為其上級上下文中的私有變量.....一直找到EC(G)全局上下文為止:作用域鏈查找機(jī)制
② 初始化this....
③ 初始化arguments....
④ 形參賦值:形參都是私有變量,放在AO中的。如果不傳遞實參,默認(rèn)值是undefined
⑤ 變量提升....
5、代碼自上而下執(zhí)行
6、.....
7、一般情況下,函數(shù)執(zhí)行所形成的私有上下文,進(jìn)棧執(zhí)行完后,會默認(rèn)出棧釋放掉
【私有上下文中存儲的私有變量和一些值都會被釋放掉,目的:為了優(yōu)化內(nèi)存空間,減少棧內(nèi)存的消耗,提高頁面或者計算機(jī)的處理速度......】
不能出棧釋放:當(dāng)前上下文中某些內(nèi)容(一般是堆內(nèi)存地址)被當(dāng)前上下文的外部的事物占用了,則無法出棧釋放。一旦被釋放,后期外部事物就無法找到對應(yīng)的內(nèi)容了
注意:多次函數(shù)執(zhí)行,會形成多個全新的、私有執(zhí)行上下文,這些上下文之間沒有直接的關(guān)系
(4)閉包
一般,很多人認(rèn)為:大函數(shù)返回小函數(shù)是閉包。
這只是閉包機(jī)制中的一種情況。
閉包:函數(shù)執(zhí)行形成一個私有的執(zhí)行上下文,此上下文中的私有變量,與此上下文以外的變量互不干擾;也就是當(dāng)前上下文把這些變量保護(hù)起來了,我們把函數(shù)的這種保護(hù)機(jī)制稱為閉包。
閉包不是具體的代碼,而是一種機(jī)制。
一般情況下,形成的私有上下文很容易被釋放掉,這種保護(hù)機(jī)制存在時間太短了,不是嚴(yán)謹(jǐn)意義上的閉包。有人認(rèn)為,形成的上下文不被釋放,才是閉包。此時,不僅保護(hù)了私有變量,而且這些變量和存儲的值也不會被釋放掉,保存起來了。
閉包的作用:① 保護(hù) ② 保存
利用閉包的兩個作用,可以實現(xiàn)高階編程技巧,以后再說~
3 / 練習(xí)題
(1)第一題
var x = 100; function fn() { var x = 200; return function(y) { console.log(y + x++); } } var f = fn(); f(10); f(20);△ 第一題
i++ 后加
△ 圖2.4_后加
(2)第二題
let a=0, b=0; function A(a){ A=function(b){ alert(a+b++); }; alert(a++); } A(1); A(2);△ 第二題
(3)第三題
let x = 5; function fn(x) { return function(y) { console.log(y + (++x)); } } let f = fn(6); f(7); fn(8)(9); f(10); console.log(x);△ 第三題
- end -
從“你”到“更好的你”
有無限可能
好啦,好啦,碎碎念了很多:
全局執(zhí)行上下文、創(chuàng)建函數(shù)、作用域、執(zhí)行函數(shù)、私有執(zhí)行上下文、AO和VO、實參、形參、作用域鏈
△ 圖2.5_練習(xí)題,第一題
總結(jié)
以上是生活随笔為你收集整理的delphi 函数内创建对象 释放_JavaScript 的函数底层运行机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言有趣源代码,分享一段有趣的小代码
- 下一篇: antd picker 使用 如何_如何