問答:
函數(shù)聲明和函數(shù)表達式有什么區(qū)別?
- 函數(shù)聲明必須帶有標(biāo)示符(即函數(shù)名稱)嵌纲,而函數(shù)表達式則可以省略這個標(biāo)示符。
function 函數(shù)名稱 (參數(shù):可選){ 函數(shù)體 }
函數(shù)表達式:
function 函數(shù)名稱(可選)(參數(shù):可選){ 函數(shù)體 }
- 可以看出腥沽,如果不聲明函數(shù)名稱逮走,它肯定是表達式,可如果聲明了函數(shù)名稱的話今阳,如何判斷是函數(shù)聲明還是函數(shù)表達式呢师溅?ECMAScript是通過上下文來區(qū)分的,如果function foo(){}是作為賦值表達式的一部分的話盾舌,那它就是一個函數(shù)表達式墓臭,如果function foo(){}被包含在一個函數(shù)體內(nèi),或者位于程序的最頂部的話矿筝,那它就是一個函數(shù)聲明起便。還有一種函數(shù)表達式不太常見,就是被括號括住的(function foo(){}),他是表達式的原因是因為括號 ()是一個分組操作符榆综,它的內(nèi)部只能包含表達式妙痹。
什么是變量的聲明前置?什么是函數(shù)的聲明前置?
- JavaScript引擎的工作方式是鼻疮,先解析代碼怯伊,獲取所有被聲明的變量,然后再一行一行地運行判沟,這造成的結(jié)果耿芹,就是所有的變量的聲明語句,都會被提升到代碼的頭部挪哄,這就叫做變量提升吧秕。例如:
var a=1;
而在實際工作的時候JavaScript是這樣讀取代碼的,如下:
var a;先讀取變量而不讀取其賦值迹炼,也就是說在運行過程中第一時間知曉有這么個定義變量存在砸彬。
a = 1; 當(dāng)讀取完變量之后才會讀取其賦值。
綜上這就是傳說中的變量聲明前置斯入。
- 和變量的聲明會前置一樣砂碉,函數(shù)聲明同樣會前置,如果我們使用函數(shù)表達式那么規(guī)則和變量一樣.例如:
console.log(fn); //undefined javascript中運行代碼是一行一行逐一執(zhí)行的刻两,因此在這里就變量中讀取到 (var a;)這里一樣增蹭,console.log中需要執(zhí)行的語句存在但是并沒有定義,因此才會出現(xiàn)undefined磅摹。
var fn = function(){}
如果我們使用函數(shù)聲明的方式滋迈,那么即使函數(shù)寫在最后也可以在前面語句調(diào)用,前提是函數(shù)聲明部分已經(jīng)被下載到本地,例如:
fn(); // "1"
執(zhí)行函數(shù)fn偏瓤;
function fn(){
console.log('1');
}
arguments 是什么杀怠?
在JavaScript中椰憋,arguments對象是比較特別的一個對象厅克,實際上是當(dāng)前函數(shù)的一個內(nèi)置屬性。同時arguments對象的長度是由實參個數(shù)而不是形參個數(shù)決定的橙依。形參是函數(shù)內(nèi)部重新開辟內(nèi)存空間存儲的變量证舟,但是其與arguments對象內(nèi)存空間并不重疊。對于arguments和值都存在的情況下窗骑,兩者值是同步的女责,但是針對其中一個無值的情況下,對于此無值的情形值不會得以同步创译。再次利用函數(shù)的arguments屬性可以實現(xiàn)函數(shù)的重載抵知。
函數(shù)的重載怎樣實現(xiàn) ?
- 在這里首先我們要明確函數(shù)重載的定義:重載是很多面向?qū)ο笳Z言實現(xiàn)多態(tài)的手段之一,在靜態(tài)語言中確定一個函數(shù)的手段是靠方法簽名——函數(shù)名+參數(shù)列表刷喜,也就是說相同名字的函數(shù)參數(shù)個數(shù)不同或者順序不同都被認(rèn)為是不同的函數(shù)残制,稱為函數(shù)重載。
- 在JavaScript中沒有函數(shù)重載的概念掖疮,函數(shù)通過名字確定唯一性初茶,參數(shù)不同也被認(rèn)為是相同的函數(shù),后面的覆蓋前面的浊闪,這是不是意味著JavaScript不能通過重載功能實現(xiàn)一個函數(shù)恼布,參數(shù)不同功能不同呢?
在JavaScript中搁宾,函數(shù)調(diào)用沒必要把所有參數(shù)都傳入折汞,只要你函數(shù)體內(nèi)做好處理就行,但前提是傳的參數(shù)永遠被當(dāng)做前幾個盖腿,看個例子:
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);如前面所說:函數(shù)調(diào)用沒必要把所有參數(shù)都傳入字支,只要你函數(shù)體內(nèi)做好處理就行,這里用條件過濾奸忽,滿足要求則會執(zhí)行相應(yīng)的指令堕伪。
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);這里兩個參數(shù)在執(zhí)行的時候會對參數(shù)進行判定,到底屬于name age sex中的那一個;滿足其中的兩個栗菜,那么另一個就不會執(zhí)行欠雌。
printPeopleInfo('Byron', 26, 'male');
立即執(zhí)行函數(shù)表達式是什么?有什么作用疙筹?
- 先創(chuàng)建了一個匿名函數(shù)富俄,然后不傳入?yún)?shù)調(diào)用它,這就變成了立即執(zhí)行函數(shù)而咆。例如:
(function(){})();
其實他的實際結(jié)構(gòu)就是:
(函數(shù)定義表達式)函數(shù)調(diào)用表達式
再看一個例子:
function fn(){
console.log(1);
}
這里定義了一個函數(shù)fn霍比,也就是說fn這個函數(shù)就是 前面function fn(){}; 這個整體,那么他的直接調(diào)用就是后邊:(function fn(){
console.log(1);
})()暴备;當(dāng)然這里我們沒有加入實參悠瞬。
fn();調(diào)用此函數(shù)
什么是函數(shù)的作用域鏈?
在大多數(shù)語言中都是用花括號{}來形成一個作用域涯捻,但是在JavaScript中{}并沒有帶來塊作用域浅妆,JavaScript的作用域是靠函數(shù)來形成的,也就是說一個函數(shù)內(nèi)定義的變量函數(shù)外不可以訪問障癌,從而就形成了一個特有的作用區(qū)域凌外,俗稱作用域√握悖看個例子:
function fn(){
var a =1;
if(a > 2){
var b = 3;
}
console.log(b);
}
fn(); // undefined
console.log(a); // "ReferenceError: a is not defined 報錯a沒有被定義康辑,個人覺得函數(shù)中并沒有執(zhí)行a,因此在函數(shù)外執(zhí)行console.log(a)就沒法執(zhí)行摄欲,因為獲取不到a的信息,也就是沒有在函數(shù)的作用域中疮薇。
代碼:
1
輸出內(nèi)容為:
function getInfo(name, age, sex){
console.log('name:',name); 1
console.log('age:', age); 2
console.log('sex:', sex); 3
console.log(arguments); 4
arguments[0] = 'valley'; 5這里重新定義name為valley
console.log('name', name); 6
}
getInfo('hunger', 28, '男');
輸出//name: hunger 1 js中的代碼逐行執(zhí)行蒿涎,因此對應(yīng)上邊的函數(shù)依次解析參數(shù)。
age: 28 2
sex: 男 3
["hunger", 28, "男"] 4 arguments數(shù)組
name valley 6
getInfo('hunger', 28);
輸出://name: hunger 1
age: 28 2
sex: undefined 3
["hunger", 28] 4 arguments數(shù)組
name valley 6
getInfo('男');
輸出:// name: 男 1
age: undefined 2 無參數(shù) 所以undefined
sex: undefined 3
["男"] 4
name valley 6
2惦辛、寫一個函數(shù)劳秋,返回參數(shù)的平方和?如 (難度**)
function sumOfSquares(){ }
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
答案如下:
function sumOfSquares(){
var sum =0; 定義一個變量
for(var i=0;i<arguments.length;i++){
sum += arguments[i]*arguments[i]
}利用函數(shù)的arguments屬性實現(xiàn)重載
console.log(sum); 打印出sum的值
}
sumOfSquares(1,3); 輸出10
sumOfSquares(2,3,4); 輸出29
3胖齐、如下代碼的輸出玻淑?為什么 ?
console.log(a); 輸出undefined 變量前置
var a = 1;
console.log(b); 報錯找不到b
4呀伙、如下代碼的輸出补履?為什么 ?
sayName('world'); // hello world
sayAge(10);// 報錯 sayAge不是一個函數(shù)
function sayName(name){
console.log('hello ', name); }
var sayAge = function(age){ // 相當(dāng)于是定義一個變量剿另,因此并不是函數(shù)箫锤,所以不能執(zhí)行。
console.log(age);
};
5雨女、如下代碼的輸出谚攒?為什么?
function fn(){} //這里fn是一個函數(shù)
var fn = 3; // 此處對fn進行了重新定義氛堕,覆蓋了前者馏臭。
console.log(fn);因此此處應(yīng)該顯示3,但是瀏覽器中執(zhí)行的時候是報錯讼稚。報錯內(nèi)容為:標(biāo)識符的fn已經(jīng)宣布括儒。
6、如下代碼的輸出锐想?為什么帮寻?
function fn(fn2){ console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){ console.log('fnnn2'); } }
fn(10);
由于該題中涉及到變量提示和函數(shù)聲明前置,因此該題可以改寫如下:
function fn(fn2){
function fn2(){
console.log('fnnn2');
}
var fn2赠摇;
console.log(fn2); 顯示fnnn2
fn2 = 3;//此處重新定義fn2固逗,因此下邊的執(zhí)行會顯示3
console.log(fn2); //顯示3
console.log(fn); //顯示10
}
fn(10);
7、如下代碼的輸出蝉稳?為什么 抒蚜?
var fn = 1; //定義fn為1
function fn(fn){ console.log(fn); } //這是一個函數(shù)聲明掘鄙,無法自動執(zhí)行
console.log(fn(fn)); //因此在這里會報錯耘戚,報錯原因是由于前邊對變量fn進行了定義,而且權(quán)重高于函數(shù)操漠,如果后邊是console.log(fn)則為1.
8收津、如下代碼的輸出饿这?為什么?
console.log(j); undefined
console.log(i); undefined
for(var i=0; i<10; i++){ var j = 100; }
console.log(i); 10
console.log(j); 100
作用域存在于函數(shù)中的時候才存在局部作用域撞秋,當(dāng)沒有函數(shù)的時候长捧,除了特殊定義,其余皆可視為全局變量吻贿,因此在該題中 第一行和第二行代碼的執(zhí)行結(jié)果為undefined串结,這也正好體現(xiàn)在js中代碼是逐行執(zhí)行的,當(dāng)執(zhí)行到for循環(huán)的時候舅列,便將i和j視為全局變量肌割,根據(jù)條件對i的限制有0-9共計執(zhí)行10次,因此console.log(i)為10帐要,與此同時變量j被定義為100把敞,因此執(zhí)行console.log(j)為100.
9、如下代碼的輸出榨惠?為什么奋早?
fn(); // 這里是指執(zhí)行函數(shù)fn,只要函數(shù)存在,執(zhí)行可以在前赠橙。
var i = 10;
var fn = 20;
console.log(i);
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){ i = 100; } }
根據(jù)函數(shù)聲明提前耽装,上題中的代碼可以寫成:
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){ i = 100; }
代碼逐行執(zhí)行,后邊覆蓋前面期揪,因此在這個局部作用域中i的最終值是100剂邮,所以該大函數(shù)fn的執(zhí)行結(jié)果就是100
}
fn(); 顯示100
var i = 10; 全局變量重新定義i
var fn = 20;
console.log(i); 因此此處顯示為10
故而輸出結(jié)果為:100 10
10、如下代碼的輸出横侦?為什么挥萌?
var say = 0;
(function say(n){
console.log(n);打印出n
if(n<3) 條件判斷,當(dāng)n小于3的時候返回結(jié)果枉侧,后邊就不執(zhí)行引瀑。
return;
say(n-1);執(zhí)行n-1 }( 10 ) );、
因此此處的執(zhí)行結(jié)果為10 9 8 7 6 5 4 3 2 但是為什么沒有1呢榨馁?
因為當(dāng)n=3的時候 依次執(zhí)行console.log(3) 顯示3 同時后邊執(zhí)行say(3-1)憨栽; 顯示2 , 當(dāng)n=2的時候 滿足了后邊的if條件翼虫,就執(zhí)行return,所以沒有1.
console.log(say); 最后在執(zhí)行這個 因為前面定義了變量say=0屑柔,所以此處顯示0.
首先聲明一點,上題中
(function say(n){
console.log(n);
if(n<3)
return;
say(n-1); }( 10 ) );是一個立即執(zhí)行函數(shù)相當(dāng)于()珍剑;只不過括號里邊是一個函數(shù)聲明而已掸宛,但是后邊的10是實參,也就是N的初始值為10.
綜上 執(zhí)行結(jié)果為10 9 8 7 6 5 4 3 2 0