一、函數聲明和函數表達式有什么區別
函數聲明:
function 函數名稱 (參數:可選){ 函數體 }
函數表達式:
function 函數名稱(可選)(參數:可選){ 函數體 }
- 若沒有函數名稱一定是函數表達式。
- 若有函數名稱,如果函數function f(){}作為賦值表達式的一部分,則他是函數表達式,若function f(){}被包含在函數體內或程序最頂部,則是函數聲明。
function f(){} // 聲明,因為它是程序的一部分
var g = function f(){}; // 表達式,因為它是賦值表達式的一部分
new function f(){}; // 表達式,函數創建表達式
(function(){
function bar(){} // 聲明,因為它是函數體的一部分
})();
(fuction(){})也是函數表達式, ()是一個分組操作符,它的內部只能包含表達式 - JavaScript 解釋器中存在一種變量聲明被提升(hoisting)的機制,變量(函數)的聲明會被提升到作用域的最前面,即使寫代碼的時候是寫在最后面,也還是會被提升至最前面。而函數表達式如同定義其它基本類型的變量一樣,只在執行到某一句時對其進行解析。var函數表達式也會聲明,聲明式為給其賦值,所以alert(g)還是undefined。
alert(f)// function f(){}
alert(g)// undefined
function f() {}
var g = function fn() {};
alert(f); // function f() {}
alert(g); // function fn() {}
二、什么是變量的聲明前置?什么是函數的聲明前置
變量的聲明前置
console.log(a);//undefined
var a = 1;
console.log(a);//1
console.log(b);//錯誤
console.log(a)為什么輸出undefined?原因是變量a聲明提前,先聲明var a;然后執行完console.log(a);再給a賦值1,所以指為undefined。b沒有聲明也沒有初始化所以會出現錯誤。
函數的聲明前置:
1.構造函數
printName;// Invalid or unexpected token
var printName = new Function("console.log('Byron');");
構造函數也是一個函數表達式,含有var也會聲明前置,但此時只是聲明未賦值會出現錯誤。有意思的是將上面改一下。
g;//
var g = new Function("console.log('Byron');");
typeof(g);//function
這個時候確沒問題了,var聲明前置時可能將g作為一個變量聲明,然后將new Function的值賦給g,實際上創造了一個匿名函數。而new Function這個函數只是作為g的局部變量。當對new Function檢查類型時就會出現錯誤。
2.函數聲明
functionName();
function functionName(){
console.log("我是函數聲明");
}
functionName();輸出"我是函數聲明",函數聲明會將函數function functionName(){}拿到最前面聲明一下,函數體的內容聲明時是未執行的。此時不會出現錯誤。
3.函數表達式
構造函數實際上就是函數表達式,類型差不多就不舉例了。
三、arguments 是什么
arguments是對象。
作用:可以通過arguments對象來訪問函數參數內部數組,從而獲取傳遞給函數的每一個參數。通過arguments[]來獲取。
exp:參數內第一個元素arguments[0]...
四、函數的重載怎樣實現
靜態語言中確定一個函數的手段是靠方法簽名——函數名+參數列表,也就是說相同名字的函數參數個數不同或者順序不同都被認為是不同的函數,稱為函數重載。
JavaScript中沒有函數重載,函數通過名字確定唯一性,參數不同也被認為是相同的函數,后面的覆蓋前面的。
function sum(x){
console.log(x+1);
}
function sum(x){
console.log(x+2);
}
sum(1);//結果為3;后面覆蓋前面。
五、立即執行函數表達式是什么?有什么作用
立即執行函數表達式結構:
(函數定義表達式)函數調用表達式
( function{} )();
(函數定義表達式 函數調用表達式)
( function{}() );
注意:當函數執行有命名沖突的時候,函數依次填入 變量=》函數=》參數
的順序。
作用:
1.JavaScript中沒有命名空間,而且只有function代碼塊內部可以隔離變量作用域,自調用匿名函數就用來防止變量彌散到全局,以免各種js庫沖突。
2.JS里沒有入口函數的概念,在現今的模塊化方案成熟穩定之前,立即執行函數也常常用來充當主函數的角色。
3.IIFE寫惰性載入。如何實現?
六、什么是函數的作用域鏈
作用域(scope):變量和函數的作用域是在定義時決定而不是執行時決定,當定義了一個函數,當前的作用域鏈就保存起來,并且成為函數的內部狀態的一部份。在最頂級作用域鏈僅由全局對象組成,而不和詞法作用域相關,然而,當定義一個嵌套的函數時,作用域鏈就包括外面的包含函數。這意味著嵌套函數可以訪問包含函數的所有參數和局部變量。盡管當一個函數定義時作用域鏈就固定了,但作用域鏈中定義的屬性還沒有固定。作用域鏈是活的,并且函數被調用時,可以訪問任何當前的綁定。
作用域鏈(scope chain):存儲變量對象的集合(環境棧?),保證對執行環境有權訪問的所有變量和函數的有序訪問,也就是用于標識符解析(變量訪問)。
執行環境(execution context):定義了變量和函數有權訪問的其他數據,決定了它們的各自行為。每個執行環境都有一個與之關聯的變量對象。在web瀏覽器中,window對象就是全局執行環境。每個函數都有自己的執行環境,當函數執行完畢,該環境被銷毀,保存在其中的變量和函數也隨之銷毀