函數聲明有三種:function a()、函數表達式以及 Function構造函數。前兩種最爲常見,用的最多。函數
(1)function 命令ui
function foo(s){
console.log(s);
}
複製代碼
(2)函數表達式spa
var f = function(s){
console.log(s);
}
複製代碼
函數表達式後面通常是匿名函數,但也能夠是具名,若是加上函數名,則只對函數內部有效,對外部無效。意思就是在相似遞歸這樣函數本身調用本身時有效,而在外部調用就不能經過函數名調用。code
var f = function a(){
console.log(typeof a);
};
a()// ReferenceError: x is not defined
f()// function
複製代碼
在外部經過變量名調用。遞歸
其實js在編譯過程當中表達式是分兩步的,先是聲明,再是賦值。例如 var a = 2作用域
總結:只有聲明會被提高,而賦值或其餘運行邏輯會留在原地。 也就是說,聲明和賦值是在不一樣的階段,聲明 var a是在編譯階段,被提高到了所在做用域的最頂端;而賦值 a = 2是在執行階段,被留在原地等待執行。編譯器
foo()
function foo(){
console.log(2)
}
//2
複製代碼
foo()
var foo = function(){
console.log(2)
}
//Uncaught TypeError: foo is not a function
複製代碼
因此,function 聲明的函數整個就是一個聲明,編譯時會被提高到最頂端,因此調用時在它聲明以前也能夠調用;而函數表達式則只提高左邊聲明部分,而右邊函數體被留在原地,若是在其前面調用函數,則會報錯。it
若是一個函數被重複聲明,後面的聲明會覆蓋前面的。 可是有幾種狀況須要注意:io
1. 都是用 function聲明console
function a(){
console.log(1);
}
a() //2
function a(){
console.log(2);
}
a() //2
複製代碼
因爲「提高」,不管函數在哪調用都會調用後面的那一個,而前面的會被覆蓋。
2. function聲明又有函數表達式
var a = function(){
console.log(1);
}
function a(){
console.log(2);
}
a() //1
||
||至關於
||
var a
function a(){
console.log(2);
}
a = function(){
console.log(1);
}
a()
複製代碼
2的第一種狀況,這時被「提高」的是第一個函數表達式的 var a 和 第二個函數function a()。而第一個函數表達式的右邊部分被留在原地,這就覆蓋了被提高的第二個函數function a()。因此調用時,執行的是第一個函數表達式。
function a(){
console.log(1);
}
a() //1
var a = function(){
console.log(2);
}
||
||至關於
||
function a(){
console.log(1);
}
var a
a()
a = function(){
console.log(2);
}
複製代碼
2的第二種狀況,就是在調用 a()時,第二個函數表達式的右邊部分被留在它的後面,因此執行第一個function a()。