簡體   English   中英

這是一個匿名函數嗎?

[英]Is this an anonymous function?

在下面的第一個代碼段中,基於我的理解,我正在創建一個函數並將其分配給變量。 但這是否意味着函數將使用該變量的名稱?

var aFunc = function(){};

我知道這叫做函數。

function bFunc(){};

沒有。

在第一個示例中,您將創建一個匿名函數,然后將其分配給“ aFunc”

在第二個示例中,您聲明一個函數並將其命名為bFunc。

兩者之間最明顯的區別是,您必須在分配它的行之后才能調用“ aFunc”。

不,該函數將不會“使用變量名”。 該變量將包含對匿名函數的引用。 該函數本身仍然是匿名的。

請注意,這最終並沒有多大區別,一旦分配了此函數引用,就可以將其與任何常規命名函數完全一樣地對待。 實際上,它幾乎沒有什么區別,命名函數也可以像持有函數引用的變量一樣對待:

function foo() { }
foo();
foo = 'bar';
alert(foo); // bar

術語“匿名函數”是行話,因此其含義可能會隨時間而改變。 沒有說明它是什么的規范,因此它可以是您想要的任何形式。 而且您所做的任何決定都可能會受到其他人的爭議。 術語就是這樣(查找“ trunking”一詞,這是電話中常見的術語)。

嚴格來說,函數聲明中的名稱是必需的,例如

function foo() {
    ...
}

和函數表達式,其中名稱是可選的。 如果名稱丟失,例如:

var x = function () {
             ...
        };

對我來說,那是一個匿名函數。 如果有名稱,例如

var x = function foo() {
             ...
        };

那么它是一個命名函數表達式(而不是匿名函數)。 在我看來,任何沒有可選名稱的函數表達式都是匿名函數。 函數表達式有很多用途,例如

// assignment to a variable
var x = function() {...}

// pass as a parameter
foo(function(){...})

// immediately executed and pass the result
foo( (function(){...}()) )

等等。 因此,在OP中,賦值的右側是一個函數表達式,沒有名稱,對我而言,這是一個匿名函數。 然后將其分配給標識符的事實並不會突然使它成為一個命名函數表達式。

其他人當然可能有所不同。

附帶地,以下結果:

function foo(){}

var foo = function(){};

實際上幾乎沒有區別,主要的區別在於創建函數的時間。

因此,首先我們必須弄清您編寫的兩個函數之間的主要區別。

這個:

var aFunc = function(){};

是一個函數表達式 凡此:

function bFunc(){};

是一個函數聲明

函數表達式中,您正在使用函數運算符在表達式內部定義函數。 聲明函數時,您正在使用function語句

剛開始時,它們會很相似,因為它們確實很相似,但是函數聲明和函數表達式的行為卻有所不同。 首先,您不能聲明一個匿名函數:如果您使用的是函數語句,則該名稱為必填項。 因此,只有使用函數運算符定義的函數才可以是匿名的:

var aFunc = function(){};

那是一個匿名函數。 在某些瀏覽器中,您實際上可以打印函數的名稱並自己查看:

console.log(aFunc.name); 

(請注意,這還不是標准,但是有一個建議

但這並不意味着用函數運算符聲明的函數必須是匿名的。 例如:

var aFunc = function myFunction() {};

這是一個命名函數。 但是,這與像這樣的函數聲明仍然不同:

function myFunction() {};
var aFunc = myFunction;

為什么? 因為在函數表達式的情況下,您無需在范圍內聲明myFunction函數:

var aFunc = function myFunction() {};

console.log(typeof myFunction) // undefined, unless some bugs

那么給函數表達式起名字有什么意義呢? 答案是:可以從函數主體本身訪問該函數,而不會污染范圍。 舉例來說,您想將事件偵聽器添加到DOM節點,但是僅執行一次偵聽器:

document.body.addEventListener("click", function onclick() {
    // do something
    document.body.removeEventListener("click", onclick, false);
}, false);

因此,您不會使用很多僅用於特定目的的功能來污染范圍,並且您仍然可以從功能主體訪問該功能。 在不推薦使用arguments.callee並用於遞歸的ES5中,這尤其有用。

函數表達式之間的另一個區別是,您可以立即調用它們,但是不能對函數聲明進行調用。 因此,例如:

function() {
    console.log('foo');
}();

將拋出異常,因為引擎無法理解它是函數聲明還是函數表達式。 但是,如果您強迫引擎將其視為一種表達方式:

!function() {
    console.log('foo');
}();

// or
(function(){
    console.log('foo');
}());

// etc, there are a lot of ways

在這里,我們是:JS理解是一個表達式,因此威脅該function作為運算符而不是語句。 然后,您將獲得IIFE(立即調用函數表達式),它在很多情況下都非常有用,尤其是在您希望隔離代碼的地方。

因此,回到您的問題,為什么要使用此函數的名稱:

var aFunc = function(){};

不是aFunc嗎?

因為,這是一種表達。 因此,該值對左側的分配一無所知。 就像有:

var aFunc = -3;

-一元否定運算的位置3是值:他們對aFunc ,對嗎? 函數expression完全相同,其中function是運算符,而(){}是值。

不它不是。 第一條語句的右側是一個函數表達式 只要您不將其分配給變量,它都是匿名的。

分配后,可以將其用作聲明的函數。

查看此問題中有關函數聲明的更多詳細信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM