摘要:直到有一天關(guān)于閉包某一天,小伙伴們討論到說關(guān)于閉包變量的問題時,君指出,如果一個函數(shù)沒有引用到其所處閉包的變量,那這個變量所指向的空間將被釋放。對于的引擎而言,如,,,無論閉包中是否包含,它們都不會釋放掉那些再也引用不到的變量。
之前在祼看ECMA262-5,在說到eval的地方,死活看不明白為什么會有一節(jié)專門扯到Direct Call to Eval:
A direct call to the eval function is one that is expressed as a CallExpression that meets the following two conditions:
The Reference that is the result of evaluating the MemberExpression in the CallExpression has an environment record as its base value and its reference name is "eval".
The result of calling the abstract operation GetValue with that Reference as the argument is the standard built-in function defined in 15.1.2.1.
當時覺得寫規(guī)范的那群家伙一定是有毛病,眾所周知,eval無非是接收一個字符串,把這個字符串當做代碼解釋執(zhí)行。
這個問題我一直不明白,然后就放著。
直到有一天.....
關(guān)于閉包某一天,小伙伴們討論到說關(guān)于閉包變量的問題時,Y君指出,如果一個函數(shù)沒有引用到其所處閉包的a變量,那這個a變量所指向的空間將被釋放。
function getClosure() { var a = 1; var b = 2; return function inner() { debugger; console.log(b); } } var func = getClosure(); func();
正如上面代碼所示,當打開Chrome調(diào)試工具時到達debugger語句時,我們只能訪問到b變量。試圖訪問a是會拋出ReferenceError的。
但是這真的能證明a引用已經(jīng)被釋放了嗎?如果沒被釋放的話,還不讓在調(diào)試的時候訪問,這個設(shè)計就只能說是(嗶~)坑爹了,Y君補充道。
于是我寫了如下代碼做了測試:
function getClosure() { var a = 1; var b = 2; return function inner(val) { debugger; console.log(eval(val)); } } var func = getClosure(); func("a"); func("b");
在閉包中使用eval,這樣引擎就不知道我在閉包中的會引用到什么變量了。這一次到達debugger語句時,驚奇地發(fā)現(xiàn),a和b都可以直接引用到了。難道是因為eval的原因?引擎在發(fā)現(xiàn)閉包中有eval之后,就不會回收閉包中的垃圾了?(因為它無從得知哪些變量會在將來被引用到)。
但如果引擎不知道將來會不會執(zhí)行到eval呢?
function getClosure(){ var a = 1; var b = 2; return function inner(func, val) { debugger; console.log(func(val)); } } var f = getClosure(); f(eval, a);
把eval當做函數(shù)傳進去,然后讓這個eval函數(shù)解釋執(zhí)行傳入的val指向的變量。遺憾的是,到在debugger處,無法訪問到a和b,執(zhí)行到console.log(func(val))拋了異常,表示找不到引用。
于是我才回過神,似乎之前閱讀過蛇精病般的什么direct call to eval的東西,跟這個相關(guān)?
回到eval在規(guī)范中指出,進調(diào)用eval函數(shù)時:
如果是直接調(diào)用eval函數(shù)的話,將當前的this指向,詞法環(huán)境以及變量環(huán)境當做新的執(zhí)行上下文的this指向,詞法環(huán)境以及變量環(huán)境。
如果不是直接調(diào)用的話,則新的執(zhí)行上下文就相當于全局執(zhí)行上下文。
>更準確地說,則是以global對象,全局詞法環(huán)境以及全局變量環(huán)境當做新的執(zhí)行上下文的this指向,詞法環(huán)境以及變量環(huán)境。
那什么是直接調(diào)用呢?參照篇首。簡言之,有如下限制:
a. BaseValue必須是一個Environment Record
b. Reference Name必須是"eval"
如下例子:
var a = eval; a("hello"); //非直接調(diào)用,因為Reference Name是"a"而不是"eval" var f = {eval: eval}; f.eval("hello"); //非直接調(diào)用,因為BaseValue是f變量,而不是Environment Record eval("hello"); //直接調(diào)用 function test() { var eval = window.eval, x = window.eval; eval("hello"); //直接調(diào)用 x("hello"); //非直接調(diào)用 }
看到規(guī)律了吧?只要是祼的eval調(diào)用就是direct call,前面不要有宿主對象,且函數(shù)名一定要是eval字符串。
再回到閉包了解了什么是直接eval調(diào)用后,如果我弄出這樣的代碼呢?
function getClosure() { var a = 1; var b = 2; var eval = function(x){ return x; } return function inner(val) { debugger; console.log(eval(val)); } } var func = getClosure(); func("a"); func("b");
在getClosure中給一eval賦成一個完全不相干的函數(shù),進入到debugger時,能不能訪問到a和b這兩個變量呢?思考一下。
最后從eval可以管窺出來,ES5的規(guī)范幾乎是從引擎現(xiàn)實者的角度來考慮問題。如果上下文中沒有eval的話,那么閉包中的變量將被很好的釋放掉(并不完全正確,參見A surprising JavaScript memory leak found at Meteor),因為引擎可以檢測出哪些變量會被引用到,而哪些不會。
對于ES3的引擎而言,如IE6,IE7, IE8,無論閉包中是否包含eval,它們都不會釋放掉那些再也引用不到的變量。原因在于,ES3規(guī)范中沒有對非直接eval調(diào)用進行規(guī)范,如下代碼在IE6,7,8能通過,而在現(xiàn)代瀏覽器中會報錯:
function getClosure(){ var a = 1; var b = 2; return function (func, val) { alert(func(val)); } } var f = getClosure(); f(eval, "a"); f(eval, "b");結(jié)論
不要在閉包中用eval,許多垃圾將得不到回收。
不要采用eval當函數(shù)名,引擎會誤認為那是一個direct call to eval的,然后內(nèi)存得不到釋放。
從理論上而言,ES5比ES3要有更好的性能,ES5更多地考慮到了內(nèi)存管理的問題。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/78156.html
嚴格模式 首先來了解一下嚴格模式是什么?嚴格模式是JavaScript中的一種限制性更強的變種方式,不是一個子集:它在語義上與正常代碼有明顯的差異,不支持嚴格模式的瀏覽器與支持嚴格模式的瀏覽器行為上也不一樣,所以不要在未經(jīng)嚴格模式特性測試情況下使用嚴格模式,嚴格模式可以與非嚴格模式共存,所以腳本可以逐漸的選擇性加入嚴格模式 嚴格模式的目的 首先,嚴格模式會將JavaScript陷阱直接變成明顯的錯...
摘要:在這次螞蟻金服的電話面試里面認識到了自己很多不足的地方吧。把字符串分割為字符串數(shù)組。從起始索引號提取字符串中指定數(shù)目的字符。通常消息包括客戶機向服務(wù)器的請求消息和服務(wù)器向客戶機的響應(yīng)消息。 先簡短的介紹一下我自己吧,我是一個前端學(xué)習(xí)者,雖然我基礎(chǔ)知識也學(xué)了比較好,但是許久不用的知識就像流失的水,很容易就忘。在這次螞蟻金服的電話面試里面認識到了自己很多不足的地方吧。雖然在阿里內(nèi)推后的人才...
摘要:在這次螞蟻金服的電話面試里面認識到了自己很多不足的地方吧。把字符串分割為字符串數(shù)組。從起始索引號提取字符串中指定數(shù)目的字符。通常消息包括客戶機向服務(wù)器的請求消息和服務(wù)器向客戶機的響應(yīng)消息。 先簡短的介紹一下我自己吧,我是一個前端學(xué)習(xí)者,雖然我基礎(chǔ)知識也學(xué)了比較好,但是許久不用的知識就像流失的水,很容易就忘。在這次螞蟻金服的電話面試里面認識到了自己很多不足的地方吧。雖然在阿里內(nèi)推后的人才...
摘要:用戶態(tài)不能干擾內(nèi)核態(tài)所以指令就有兩種特權(quán)指令和非特權(quán)指令不同的狀態(tài)對應(yīng)不同的指令。非特權(quán)指令所有程序均可直接使用。用戶態(tài)常態(tài)目態(tài)執(zhí)行非特權(quán)指令。 這是我今年從三月份開始,主要的大廠面試經(jīng)過,有些企業(yè)面試的還沒來得及整理,可能有些沒有帶答案就發(fā)出來了,還請各位先思考如果是你怎么回答面試官?這篇文章會持續(xù)更新,請各位持續(xù)關(guān)注,希望對你有所幫助! 面試清單 平安產(chǎn)險 飛豬 上汽大通 浩鯨科...
閱讀 2006·2021-09-13 10:23
閱讀 2336·2021-09-02 09:47
閱讀 3798·2021-08-16 11:01
閱讀 1220·2021-07-25 21:37
閱讀 1601·2019-08-30 15:56
閱讀 539·2019-08-30 13:52
閱讀 3132·2019-08-26 10:17
閱讀 2447·2019-08-23 18:17