1、函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別?
- 函數(shù)聲明:
function foo(arguments){////}; - 函數(shù)表達(dá)式:
var foo = function(arguments){///};
兩者除了在寫法上的不同以外,最大的區(qū)別在于:函數(shù)聲明提前的是整個(gè)函數(shù),而函數(shù)表達(dá)式所提前的是函數(shù)名所代表的變量。下面看一個(gè)例子:
func1();
func2();
function func1(){
console.log("I'm func1");
}
var func2=function(){
console.log("I'm func2");
}
其結(jié)果為:

若此時(shí)將
func2();替換為func2;則此時(shí)結(jié)果為:

2、什么是變量的聲明前置?什么是函數(shù)的聲明前置?
JavaScript會(huì)線檢索一遍全部代碼,如果遇到變量聲明,會(huì)默認(rèn)的將其置入最前端。如:var a=3;,會(huì)被拆分為var a;和a=3;兩句,并把var a;提升至代碼首行,所以:
console.log(a);// undefined
var a=3;
console.log(a);// 3
函數(shù)聲明前置,意為將函數(shù)的位置前提,具體第一題中已經(jīng)做出了回答。值得注意的是,函數(shù)聲眀提前至變量聲明之后。
3、arguments 是什么?
arguments是函數(shù)的固有屬性,它代表了傳入函數(shù)的形參所組成的數(shù)組。
例如:
function foo(x,y,z){
console.log(arguments);
console.log(arguments.length);
console.log(arguments[2])
}
foo(1,2,3); // [1,2,3] 3 3
foo(1,2); //[1,2] 2 undefind
foo(1,2,3,4,5) //[1,2,3,4,5] 5 3
可見arguments與函數(shù)所聲明的變量沒(méi)有什么關(guān)系,最終還是取決于實(shí)際的傳入?yún)?shù)。我們亦可以通過(guò)給arguments.length賦值,來(lái)改變arguments的數(shù)據(jù)結(jié)構(gòu)。
function foo(x,y,z){
arguments.length=5;
console.log(arguments);
}
foo(1,2,3); // [1,2,3,undefined,undefined]
4、函數(shù)的重載怎樣實(shí)現(xiàn)
在靜態(tài)語(yǔ)言中,同種函數(shù)擁有唯一的函數(shù)名與形參,相同名字的函數(shù)參數(shù)個(gè)數(shù)不同或者順序不同都被認(rèn)為是不同的函數(shù),稱為函數(shù)重載。
JavaScript并沒(méi)有函數(shù)重載這個(gè)特性,因?yàn)橹灰瘮?shù)名相同JS就認(rèn)為是同一個(gè)函數(shù)。
但是我們可以通過(guò)判斷傳入?yún)?shù)的個(gè)數(shù)來(lái)簡(jiǎn)單的模擬函數(shù)重載,例如:
function specialSum(){
if(arguments.length ==1 ){
return arguments[0];
}
if(arguments.length =2){
return arguments[0]*10+arguments[1];
}
}
5、立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用?
立即執(zhí)行函數(shù)表達(dá)式:
(function() {statement} ());或者(function() {statement}) ();
為什么function(){statement}();這種寫法不行呢??
因?yàn)镴avaScript解釋器,遇見funtion時(shí)會(huì)將該語(yǔ)句當(dāng)做函數(shù)聲明來(lái)處理,而正常的函數(shù)聲明寫法后面顯然是沒(méi)有最后那一對(duì)括號(hào)的。function() {statement} 的本質(zhì)是一個(gè)函數(shù),所以只需要用新的括弧將它包裝起來(lái),就可以“騙過(guò)”解釋器,從而將函數(shù)立即生效。
作用
最大、最常見的用處是形成自己的封閉空間,防止內(nèi)部參數(shù)與外部參數(shù)的相互污染,實(shí)現(xiàn)自我的私有封裝。
JavaScript中的立即執(zhí)行函數(shù)表達(dá)式
6、什么是函數(shù)的作用域鏈?
先說(shuō)函數(shù)的作用域,JavaScript最大的作用域?yàn)槿肿饔糜颍╳indow),任何子作用域都能引用全局作用域中的變量。任何一個(gè)變量,只在它所在范圍的作用域內(nèi)生效,且子作用域可以繼承父作用域中的變量。舉這么一個(gè)例子:
var a = 1;
function func1(){
var b = 2;
function func2(){
var a = 3;
var c = 4;
console.log(a);
console.log(b);
}
function func3(){
console.log(c);
}
func2(); // 3 2
func3(); //error:c is not defined;
}
func1();
connsole.log(a); //1
我們可以理解上例中有三層作用域:
- 第一層為全局作用域,其中有一個(gè)全局變量
a = 1; - 第二層作用域?yàn)楹瘮?shù)func2,也有一個(gè)局部變量
b = 2; - 第三層分別為func2,和func3,其中func2有兩個(gè)變量
a = 3,c = 4,而func3沒(méi)有變量。
實(shí)際上這就已經(jīng)形成了一個(gè)作用鏈,
- 對(duì)于 func2來(lái)說(shuō),它首先會(huì)尋找自己所擁有的局部變量以及其對(duì)應(yīng)值(
a=3,c=4),但其本身沒(méi)有b這個(gè)變量,那么它便會(huì)在它的父級(jí)函數(shù)中尋找,所以它能在func2中找到b=2。 - 而對(duì)于 func3想要尋找c這個(gè)變量,func3中尋找——>未果——>func1中尋找——>未果——>window中尋找——>未果。因此拋出錯(cuò)誤,
c is not defined。
雖然func2中對(duì)變量c進(jìn)行了聲明,但是func2與func3沒(méi)有任何關(guān)系,換句話來(lái)說(shuō)他們不在一條作用鏈上,自然func3無(wú)法識(shí)別變量。
代碼:
1. 以下代碼輸出什么? (難度**)
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';
console.log('name', name);
}
getInfo('hunger', 28, '男'); //name: hunger age: 28 sex: 男 ["hunger",28,"男"] name valley
getInfo('hunger', 28); //name: hunger age: 28 ["hunger",28] name valley
getInfo('男'); //name:男 ["男"] name valley
2.寫一個(gè)函數(shù),返回參數(shù)的平方和?如 (難度**)
function sumOfSquares(){
var sum=0
for(var i = 0; i < arguments.length; i++){
sum = arguments[i]*arguments[i]+sum;
}
return sum;
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3.如下代碼的輸出?為什么 (難度*)
console.log(a); //undefined
var a = 1;
console.log(b); //error:b is not definede
實(shí)際上該代碼為:
var a;
console.log(a);
a = 1;
console.log(b);
4.如下代碼的輸出?為什么 (難度*)
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
// hello world erro:sayAge is not a function
// 函數(shù)聲明使函數(shù)定義被提前;而函數(shù)表達(dá)式只有函數(shù)名所代表的變量提前,本質(zhì)是變量,而非函數(shù)。
5.如下代碼的輸出?為什么 (難度**)
function fn(){}
var fn = 3;
console.log(fn); // 3
照妖鏡還原:
var fn;
function fn(){}
fn = 3;
console.log(fn);
6.如下代碼的輸出?為什么 (難度3)
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
fn(10);
// function 3 function
照妖鏡還原:
function fn(fn2){
var fn2;
function fn2(){
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
console.log(fn);
}
fn(10);
7.如下代碼的輸出?為什么 (難度3)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn)); //error: fn is not a function;
照妖鏡還原:
var fn;
function fn(fn){
console.log(fn);
}
fn=1;
console.log(fn(fn)); //error: fn is not a function;
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
沒(méi)什么好解釋的吧,變量聲明提前,故前兩個(gè)為undefined,后面進(jìn)行賦值了,自然輸出數(shù)值。
9.如下代碼的輸出?為什么 (難度4)
fn();
var i = 10;
var fn = 20;
console.log(i); //10
function fn(){
console.log(i); //undefined
var i = 99;
fn2();
console.log(i); //100
function fn2(){
i = 100;
}
}
// undefine 100 10
照妖鏡還原:
var i,fn;
function fn(){
var i;
function fn2(){
i = 100;
}
console.log(i);
i = 99;
fn2();
console.log(i);
}
fn();
i = 10;
fn = 20;
console.log(i);
10.如下代碼的輸出?為什么 (難度4)
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
// 10 9 8 7 6 5 4 3 2 0
雖然立即執(zhí)行函數(shù)并不會(huì)提前,但是會(huì)立刻執(zhí)行,所以say函數(shù)一直在迭代,并且同時(shí)輸出10 9....一直到2(小于3),此時(shí)return null,函數(shù)結(jié)束。最終console.log(say);會(huì)輸出0,因?yàn)榱⒓磮?zhí)行函數(shù)所在的封閉空間發(fā)生的一切事情與外界無(wú)關(guān)。