函數覆蓋

函數聲明有三種: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作用域

  1. 遇到 var a,編譯器會詢問做用域是否已經存在該變量。若是是,編譯器會忽略這個聲明;不然會在做用域中聲明變量a。
  2. 在運行過程當中運行 a = 2,引擎會詢問做用域有沒有叫作 a 的變量。若是有,就使用這個變量;若是沒有,就往更大的做用域查找,若是找不到,在非嚴格模式下會自動聲明一個全局變量 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()。

相關文章
相關標籤/搜索