1. 函數(shù)聲明和函數(shù)表達式有什么區(qū)別鹃觉?(*)
- 函數(shù)聲明后面的分號可加可不加,不影響接下來的語句,但是函數(shù)表達式后面沒有分號結(jié)束,js引擎則會認為后面的內(nèi)容仍是函數(shù)表達式的一部分
//沒加分號報錯
var a = function(){}console.log("")
//沒加分號不報錯
function b(){}console.log("")
- ** 函數(shù)表達式**則是提升變量漠秋;
//提升變量var a
var a = function(){};
- 函數(shù)聲明將作為整個代碼塊一起提升至作用域的最上面;
//提升函數(shù)function fn(){}
function fn(){};
2. 什么是變量的聲明前置抵屿?什么是函數(shù)的聲明前置 (**)
- JavaScript的解析代碼時存在變量提升機制,具體流程是JS解析器在預(yù)執(zhí)行(解析)階段先會將所有的變量聲明提升至該作用域的最頂部
var a = 1;
function main(){
console.log(a);
var a = 2;
}
main(); //undefined
等價于
var a;
function main() {
console.log(a);
a = 2;
}
a = 1;
main(); //undefined
- 函數(shù)聲明前置就是把函數(shù)聲明提升到當前的最前面(位于變量聲明前置后面)
var num1 = 1, num2 = 2;
getsum(num1, num2); //3
function getsum(num1, num2){
return num1 + num2;
}
等價于
var num1, num2;
function getsum(num1, num2){
return num1 + num2;
}
num1 = 1;
num2 = 2;
getsum(num1, num2); //3
3. arguments 是什么 (*)
arguments是一個用于存放函數(shù)所有傳入實參的類數(shù)組對象捅位。
function main(a, b, c){
return arguments;
}
main(1, 2, 3); //[1, 2, 3]
4.函數(shù)的重載怎樣實現(xiàn) (**)
- 函數(shù)的重載是指為一個函數(shù)編寫多個定義轧葛,只要這兩個定義的簽名(接受的參數(shù)的類型和數(shù)量)不同即可。
- ECMAScript函數(shù)沒有簽名艇搀,所以ECMAScript函數(shù)不能重載尿扯,如果同時定義兩個名稱相同的函數(shù),后定義的那個函數(shù)會覆蓋先定義的函數(shù)
-
利用arguments實現(xiàn)重載
arguments是JavaScript里的一個內(nèi)置對象焰雕,包含了調(diào)用者傳遞的實際參數(shù)衷笋,而調(diào)用時只它和數(shù)組一樣有個length屬性;
我們暫且把它當“數(shù)組”來理解吧矩屁,我們根據(jù)該數(shù)組的長度以及其元素的類型來選擇不同的實現(xiàn)辟宗,從而模擬了重載爵赵。
給個例子:
function getDate(){
if(arguments.length==0){
var date=new Date().toLocaleDateString();
return "您沒有輸入?yún)?shù),現(xiàn)在時間:" + date ;
}
if(arguments.length==1){
if(arguments[0].constructor ==Date){
return "您輸入的參數(shù)是Date類型泊脐,現(xiàn)在時間是:" + arguments[0].toDateString();
}
}
if(arguments[0].constructor ==String){
return "您輸入的參數(shù)是String類型空幻,現(xiàn)在時間是:" + arguments[0];
}
}
}
于是我們可以這樣調(diào)用:
getDate()
getDate(newDate())
getDate("星期一")
這樣就實現(xiàn)了JavaScript的重載!
5. 立即執(zhí)行函數(shù)表達式是什么?有什么作用 (*)
- 什么是立即執(zhí)行函數(shù)
一種聲明之后就立即進行該函數(shù)執(zhí)行操作的函數(shù) - 立即執(zhí)行函數(shù)的寫法
function()前面加任意符號容客,告訴js引擎這是要執(zhí)行函數(shù)而不是聲明函數(shù)秕铛,注意最后必須加分號
寫法1:
(function fn(n){
console.log(n)
}());
____________________
寫法2:
!function (){
}();
作用:
- 消除全局變量的污染缩挑;
- 防止其他js文件出現(xiàn)與本文件的函數(shù)名重名情況但两,那么函數(shù)內(nèi)部定義的 同一個變量a有可能被污染;
- IIFE內(nèi)部形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量
6. 什么是函數(shù)的作用域鏈 (**)
-
作用域
作用域(scope)就是變量和函數(shù)的可訪問范圍供置,控制著變量與函數(shù)的可見性和生命周期镜遣。在Javascript中變量的作用域有全局作用域和局部作用域。- 全局作用域(Global Scope)
變量沒有在函數(shù)內(nèi)聲明或者聲明的時候沒有帶var就是全局變量士袄,擁有全局作用域悲关,window對象的所有屬性擁有全局作用域,在代碼任何地方都可以訪問娄柳。 - 局部作用域(Local Scope)
函數(shù)內(nèi)部聲明并且以var修飾的變量就是局部變量寓辱,只能在函數(shù)體內(nèi)使用,函數(shù)的參數(shù)雖然沒有使用var但仍然是局部變量赤拒。
- 全局作用域(Global Scope)
var a = 1;
function fn(){
var b = 2;
c=3;
console.log(a+b)
}
b//b is not defined
//a是全局變量秫筏,只要js運行都會生效;
//b是局部變量挎挖,只在函數(shù)體內(nèi)部生效这敬;
//注意如果函數(shù)內(nèi)部的變量不加var聲明,那么會當做全局變量
執(zhí)行環(huán)境上下文(execution context)
執(zhí)行環(huán)境(execution context)定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù)蕉朵,決定了他們的各自行為崔涂。每個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的變量對象(variable object,VO)始衅,執(zhí)行環(huán)境中定義的所有變量和函數(shù)都會保存在這個對象中冷蚂,解析器在處理數(shù)據(jù)的時候就會訪問這個內(nèi)部對象。
全局執(zhí)行環(huán)境是最外層的一個執(zhí)行環(huán)境汛闸,在web瀏覽器中全局執(zhí)行環(huán)境是window對象蝙茶,因此所有全局變量和函數(shù)都是作為window對象的屬性和方法創(chuàng)建的。每個函數(shù)都有自己的執(zhí)行環(huán)境诸老,當執(zhí)行流進入一個函數(shù)的時候隆夯,函數(shù)的環(huán)境會被推入一個函數(shù)棧中,而在函數(shù)執(zhí)行完畢后執(zhí)行環(huán)境出棧并銷毀,保存在其中的所有變量和函數(shù)定義隨之銷毀蹄衷,控制權(quán)返回到之前的執(zhí)行環(huán)境中忧额,全局的執(zhí)行環(huán)境在應(yīng)用程序退出(瀏覽器關(guān)閉)才會被銷毀。作用域鏈(scope chain)
當代碼在一個環(huán)境中執(zhí)行時宦芦,會創(chuàng)建變量對象的一個作用域鏈宙址。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問调卑。作用域鏈的前端抡砂,始終都是當前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境是函數(shù)恬涧,則將其活動對象(activation object)作為變量對象注益。活動對象在最開始時只包含一個變量,即arguments對象(這個對象在全局環(huán)境中是不存在的)溯捆。作用域鏈中的下一個變量對象來自包含(外部)環(huán)境丑搔,而再下一個變量對象則來自下一個包含環(huán)境。這樣提揍,一直延續(xù)到全局執(zhí)行環(huán)境啤月;全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象。標識符解析是沿著作用域鏈一級一級地搜索標識符的過程劳跃。搜索過程始終從作用域的前端開始谎仲,然后逐級地向后回溯,直至找到標識符為止(如果找不到標識符刨仑,通常會導(dǎo)致錯誤發(fā)生)