javascript
关于JavaScript中Function Declaration与Function Expression的进一步说明
區(qū)分變量與對象
在討論函數(shù)聲明與函數(shù)表達(dá)式之前,我覺得有必要明確一下JavaScript中變量及對象的區(qū)別。具體來說:
JavaScript中的對象(Object)是一個(gè)實(shí)體,而變量(Variable)僅僅是一個(gè)用于保存值或?qū)ο笠玫姆?#xff08;Symbol)。JavaScript的變量是松散類型的,這意味著變量符號可以任意指向不同類型的數(shù)據(jù)。
混淆變量與對象,常常會(huì)造成誤用。例如在與一位朋友的討論中,他寫下如下代碼試圖切斷原型鏈:
function func(){}
func.prototype = null; //變量func.prototype變?yōu)閚ull,但其之前引用的對象仍存在
var o = new func();
alert(null === o.__proto__) //false
這位朋友的本意是將func的原型對象銷毀,但是func.prototype = null一句并不能達(dá)到其目的,因?yàn)閒unc.prototype只是JavaScript解釋器提供給用戶的一個(gè)以只讀方式訪問原型對象的指針符號,將 其設(shè)為null,只是令這個(gè)符號不引用任何對象了,但實(shí)際func的原型對象并未被銷毀。下圖是對此原理的一個(gè)圖示,虛線表示被切斷的引用。
而且,func構(gòu)造對象時(shí)并不是通過func.prototype去訪問其原型,而是通過一個(gè)用戶不可見的內(nèi)部引用(具體實(shí)現(xiàn)依賴于解釋器,上圖假設(shè)為_proto)去訪問的。這就好比C語言中只將指針置為null是不能釋放內(nèi)存一樣,下面用一段C代碼類比上面的過程:
Function* func = (Function*)malloc(sizeof(Function));func->inner_proto = (Prototype*)malloc(sizeof(Prototype)); //此指針對用戶不可見,供解釋器內(nèi)部使用
func->prototype = func->inner_proto; //此指針提供給用戶
func->prototype = NULL; //因此這樣操作并不能銷毀func的原型對象
JavaScript這一點(diǎn)和PHP很類似,熟悉PHP的朋友應(yīng)該知道,PHP對變量的內(nèi)部表示是一個(gè)zval結(jié)構(gòu)體,JavaScript中的對象就相 當(dāng)于zval,而PHP中的變量同樣是一個(gè)松散類型的符號,因此在PHP中單純將變量設(shè)置為null并不能銷毀其引用的變量,如需銷毀需要顯示使用 unset或依靠GC機(jī)制。例如:
class foo{}$bar = new foo;
// unset($bar); 如果這樣可以立即銷毀對象
$bar = NULL; 單純使用此語句不能立即銷毀$bar引用的對象,如果此對象沒有其它引用,則需要等待GC機(jī)制銷毀
與PHP不同的是,幾乎所有JavaScript解釋器都不提供與PHP中unset對應(yīng)的顯式銷毀對象的方法,因此需要等待GC機(jī)制進(jìn)行垃圾回收時(shí)才能將不再用的對象銷毀。
Function Declaration與Function Expression
Function Declaration與Function Expression在絕大多數(shù)情況下沒有區(qū)別,唯獨(dú)的區(qū)別在創(chuàng)建Function對象的時(shí)機(jī)上。先看下列兩段代碼:
代碼A:
//Function DeclarationsayHello(); //Hello!
function sayHello(){
alert('Hello!');
}
代碼B:
//Function ExpressionsayHello(); //TypeError: undefined is not a function
var sayHello = function(){
alert('Hello!');
}
這兩段代碼幾乎是一樣的,但是使用函數(shù)聲明的代碼A運(yùn)行正常,而使用函數(shù)表達(dá)式的代碼B則會(huì)報(bào)錯(cuò)。這是因?yàn)橐韵率聦?shí):
JavaScript是一種解釋型語言,函數(shù)聲明會(huì)在JavaScript代碼加載后、執(zhí)行前被解釋,而函數(shù)表達(dá)式只有在執(zhí)行到這一行代碼時(shí)才會(huì)被解釋。
所以代碼A相當(dāng)于在執(zhí)行sayHello()前已經(jīng)建立了一個(gè)Function Object并賦給了變量sayHello,其對應(yīng)代碼如下:
var sayHello = new Function("alert('Hello!')");sayHello();
而代碼B在執(zhí)行sayHello()還未存在Function Object和變量sayHello,因?yàn)镴avaScript在第一次使用某變量時(shí)會(huì)建立此變量,所以此處建立變量sayHello,但其值時(shí) undefined,未引用任何對象,將其作為函數(shù)來調(diào)用當(dāng)然會(huì)出錯(cuò)。另外,解釋JavaScript時(shí)如果某個(gè)變量已經(jīng)存在,則其前面的“var”關(guān)鍵 字被忽略,所以B代碼等價(jià)于下列代碼:
sayHello = undefined;sayHello(); //TypeError: undefined is not a function
sayHello = new Function("alert('Hello')");
除了什么時(shí)候可以被訪問到外,JavaScript中的Function Declaration與Function Expression兩種語法其實(shí)是等價(jià)的。另外,大多數(shù)瀏覽器支持將兩種語法一起使用,如:
//除Safari外正確var func = function func(){
}
但是以上語法在Safari上會(huì)報(bào)錯(cuò)。因此為了瀏覽器兼容性考慮,任何時(shí)候都不要合并使用兩種語法。
轉(zhuǎn)載于:https://www.cnblogs.com/kudosharry/articles/2318968.html
總結(jié)
以上是生活随笔為你收集整理的关于JavaScript中Function Declaration与Function Expression的进一步说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决vs2005打开vs2008应用程序
- 下一篇: 热烈庆祝AC70道题