解決掉你心中 js function與Function的關係的疑問
前言
在網上有很多關於js function 與 Function直接關係的文章。
但是我感覺過於抽象化了,那麼如何是具體化的解釋?
正文部分為個人理解部分,如有不對望指出。
正文
<script>
if((function(){}).constructor === Function)
{
console.log(true);
}
</script>
我寫了一段這個程式碼,答案為true。
這就是function 與 Function的關係。
看下Function的定義:
Function 建構函式建立一個新的 Function 物件。直接呼叫此建構函式可用動態建立函式,但會遭遇來自 eval 的安全問題和相對較小的效能問題。然而,與 eval 不同的是,Function 建構函式只在全域性作用域中執行。
然後還給出了這樣一個結論:
每個 JavaScript 函式實際上都是一個 Function 物件。
重新理解一下,Function的定義。
第一句話很好理解,就是可以建立一個Function物件。第二句好也好理解,就是會有安全漏洞和效能問題,詳細部分可看eval的安全問題,至於為什麼低效,官方解釋是:因為使用後者建立的函式是跟其他程式碼一起解析的。
第三句話,什麼叫"Function 建構函式只在全域性作用域中執行"?
var func = new Function("alert(x+y);"); var test = function () { var x=1,y=2; func(); eval("x+y"); }
就是func()執行會報錯。而eval("x+y")是成功的。
因為func()是在全域性作用域中執行。
如果是這樣:
var x=1,y=2;
var func = new Function("alert(x+y);");
var test = function () {
var x=1,y=2;
func();
eval("x+y");
}
test();
那麼會彈出3;
當然這裡說eval是在區域性變數中執行也比較絕對,因為eval的引用變數是在全域性中執行的。
var global=eval; global("x+y");
這樣就在全域性中執行,好吧,這不是該篇的重點。
那麼這種Function 物件和申明函式有什麼區別呢?前面已經說明了,Function物件是在全域性中執行,而宣告函式是在區域性中執行。
我找了一個例子:
var x = 10;
function createFunction1() {
var x = 20;
return new Function('return x;'); // 這裡的 x 指向最上面全域性作用域內的 x
}
function createFunction2() {
var x = 20;
function f() {
return x; // 這裡的 x 指向上方本地作用域內的 x
}
return f;
}
var f1 = createFunction1();
console.log(f1()); // 10
var f2 = createFunction2();
console.log(f2()); // 20
看到這裡,以為結束了?下面是本文的核心思想部分。
我們如何才能夠,用function的方式建立出Function物件的效果?或者說我們如何模擬new Function() 到底發生了什麼。
var x=1,y=2;
var func = new Function("alert(x+y);");
var func1= function ()
{
alert(x+y);
}
console.log(func);
console.log(func1);
打印出來func,是一個匿名的函式。
匿名函式自帶是閉包效果,在這裡我似乎找到了答案,現在我們就來模擬出new Function();
function main() {
var x = 5;
var y = 6;
FunctionObj = function () {
alert(x + y);
};
function func() {
var x = 1;
var y = 2;
var Newfunc = FunctionObj;
Newfunc();
}
func();
}
main();
FunctionObj();
彈出的結果是11,另一個彈出的還是11;
在這裡我假設啟動的是main主函式,x與y是全域性變數。
然後在func中的:
var func = FunctionObj;
func();
假設為new Function(),也就是說去假設構建一個Function 物件。
這樣實現的其實就是在全域性變數中建立了FunctionObj變數,然後賦值給了func,然後再執行func的時候自然就在main變數中了,因為匿名函式本身就閉包。
對應為:
var x=5;
var y=6;
function func()
{
var x=1;
var y=2;
var NewFunc= new Function("alert(x+y)");
NewFunc();
}
func();
繼續變化一下,模擬Function 做了什麼:
var x=5;
var y=6;
function func()
{
var x=1;
var y=2;
var NewFunc= Functionsimulation();
NewFunc();
}
function Functionsimulation()
{
var global=eval;
return eval("(function(){return function(){alert(x+y)}})()");
}
func();
彈出的結果依然是:11;
總結
回過頭來,再看一下這段話:
每個 JavaScript 函式實際上都是一個 Function 物件。
new Function 只是將匿名包,繫結到了一個全域性變量了,這樣它的this永遠固定,執行時,永遠是在全域性中執行。
至於宣告函式,因為是動態的執行,所以我們訪問的以區域性優先,也可以理解為繫結的為區域性變數。
以上是個人理解,如有不對望指出