[英]Javascript Function Declaration Options
我見過使用下面的專家來聲明一個函數:
(function () {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
//etc
}());
例如https://github.com/douglascrockford/JSON-js/blob/master/json.js
有人可以幫助我理解我們何時應該使用上述模式以及我們如何使用它?
謝謝。
好吧,既然ECMA6還沒有到來,那么函數就是在JS中創建范圍的最佳方式。 如果在IIFE(立即調用的函數表達式)中包裝排序的變量聲明,則不會全局創建該變量。 功能聲明也是如此。
如果給你一個看似令人生畏的清除所有全局變量腳本的艱巨任務,你需要做的就是將整個腳本包裝成一個簡單的(function(){/*script here*/}());
,並且沒有創建全局變量,以免它們是隱含的全局變量,但這只是一個懶惰的修復。 這種模式非常強大。
基本的JS函數調用live-cycle類似的工作如下:
f();//call function
||
====> inside function, some vars are created, along with the arguments object
These reside in an internal scope object
==> function returns, scope object (all vars and args) are GC'ed
與JS中的所有對象一樣,只要該對象不再被引用,就會為GC(垃圾收集)標記一個對象。 但請考慮以下因素:
var foo = (function()
{
var localFoo = {bar:undefined};
return function(get, set)
{
if (set === undefined)
{
return localFoo[get];
}
return (localFoo[get] = set);
}
}());
當IIFE返回時,foo被賦予其返回值,這是另一個函數。 現在localFoo
在localFoo
的范圍內被聲明,並且沒有辦法直接到達該對象。 乍一看,您可能希望localFoo
成為localFoo
。
但是,繼續,返回的函數(並分配給foo
仍然引用該對象,因此它不能被gc'ed。換句話說:scope對象比函數調用更長,並且創建了一個閉包。
然后,在變量foo
超出范圍或重新分配另一個值並且返回的函數的所有引用都丟失之前, localFoo
對象將不會被localFoo
。
看看其中一個鏈接的答案(帶有圖表的答案),在那個答案中有一個文章的鏈接,從那里我偷了我用過的圖像。 如果還沒有,那應該為你清理。
IIFE可以不返回任何內容,但無論如何都要暴露其范圍:
var foo = {};
(function(obj)
{
//obj references foo here
var localFoo = {};
obj.property = 'I am set in a different scope';
obj.getLocal = function()
{
return localFoo;
};
}(foo));
此IIFE不返回任何內容(暗示undefined
),但console.log(foo.getLocal())
將記錄空對象文字。 foo
本身也將被賦予property
。 但是等等,我可以做得更好。 假設foo已經通過上面的代碼一次:
var bar = foo.getLocal();
bar.newProperty = 'I was added using the bar reference';
bar.getLocal = function()
{
return this;
};
console.log(foo.getLocal().newProperty === bar.newProperty);
console.log(bar ==== foo.getLocal());
console.log(bar.getLocal() === foo.getLocal().getLocal());
//and so on
這個日志會是什么? 事實上,它會記錄true
,一次又一次。 對象永遠不會在JS中復制,它們的引用會被復制,但對象始終是相同的。 在某個范圍內更改一次,這些更改將在所有引用中共享(邏輯上)。
這只是告訴你,封鎖可能很難在第一次得到你的頭一輪,但是這也說明他們的強大功能:您可以通過各種IIFE的傳遞對象,每段時間設定可以訪問自己的新方法,其他方法無法達到的獨特范圍。
注意
對於JS引擎而言,更接近Garbage Collect並不是那么容易,但最近,這不再是一個大問題了 。
還花些時間來谷歌這些條款:
this
參考 IIFE也可以命名為函數,但是你可以引用該函數的唯一地方是函數的范圍:
(function init (obj)
{
//obj references foo here
var localFoo = {};
obj.property = 'I am set in a different scope';
obj.getLocal = function()
{
return localFoo;
};
if (!this.wrap)
{//only assign wrap if wrap/init wasn't called from a wrapped object (IE foo)
obj.wrap = init;
}
}(foo));
var fooLocal = foo.getLocal();
//assign all but factory methods to fooLocal:
foo.wrap(fooLocal);
console.log(fooLocal.getLocal());//circular reference, though
console.log(init);//undefined, the function name is not global, because it's an expression
這只是一個基本的例子,說明如何使用閉包來創建包裝器對象......
以上模式稱為立即函數。 這個功能做3件事: -
此代碼的結果是一個表達式,它在單個語句中執行以下所有操作:
JS開發人員使用它來創建變量和函數,而不會污染全局空間,因為它為變量和函數創建了自己的私有范圍。
在上面的示例中,函數f(){}位於immediate函數的私有范圍內,您無法在全局或窗口范圍內調用此函數。
基於瀏覽器的JavaScript只有兩個可用范圍:全局和函數。 這意味着您創建的任何變量都在全局范圍內或僅限於您當前所在函數的范圍。
有時,通常在初始化期間,您需要一堆只需要一次的變量。 將它們放在全局范圍內是不合適的,你不需要特殊的功能來完成它。
輸入,即時功能。 這是一個定義然后立即調用的函數。 這就是你在Crockford(和其他人的)代碼中看到的。 它可以是匿名的或命名的,但不會破壞避免污染全局范圍的目的,因為函數的名稱將是函數體的本地名稱。
它提供了一個包含變量的范圍,而不會留下一個函數。 保持清潔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.