問答:
1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
函數(shù)聲明 函數(shù)聲明由 function +函數(shù)名+([參數(shù)])+{函數(shù)體} 組成
console.log(typeof fn); //這里輸出不是undefined 而是 function 由于 函數(shù)聲明提前的作用
fn(); //函數(shù)調(diào)用
function fn(){ //函數(shù)聲明
console.log("hello")
}
javaScript引擎將函數(shù)名視同變量名双饥,所以采用 function聲明函數(shù)時,整個函數(shù)(也就是說包括函數(shù)體里面的代碼)會像變量聲明一樣冯键,被提升到代碼頭部。所以上面的代碼不會報錯铝侵。
函數(shù)表達(dá)式
fn(); //報錯 Uncaught ReferenceError: fn is not defined
var fn=function(){
console.log("hello")
}
fn(); //hello
}
函數(shù)表達(dá)式只有個執(zhí)行到var fn=function(){}之后才能夠調(diào)用予跌。
所以在如下代碼中榆纽,雖然函數(shù)聲明在函數(shù)表達(dá)式的后面,但是由于函數(shù)聲明被聲明提前了芬探,所以是函數(shù)表達(dá)式相當(dāng)于在函數(shù)的后面神得,函數(shù)表達(dá)式覆蓋了函數(shù)聲明部分。
var fn=function(){
console.log("world");
}
function fn(){
console.log("hello");
}
fn(); //最后的結(jié)果是world.
2.什么是變量的聲明前置偷仿?什么是函數(shù)的聲明前置
變量的聲明前置是指變量名的聲明前置
console.log(fn); //這里并沒有提示 fn is not defined 而是提示undefined
//說明變量fn已經(jīng)聲明過了但是沒有賦值
var fn=0;
相當(dāng)于
var fn;
console.log(fn);
fn=0;
函數(shù)的生命前置是指整個函數(shù)(包括函數(shù)體)的聲明前置
console.log(fn); //輸出 function fn(){console.log("hello")}
function fn(){
console.log("hello")
}
所以在如下代碼中
console.log(fn); //輸出 function fn(){}
var fn=1;
function fn(){};
console.log(fn); //由于被覆蓋 fn的值變?yōu)?循头;
上面的代碼相當(dāng)于
var fn; function fn(){};
console.log(fn);
fn=1;
console.log(fn);
3.arguments 是什么
arguments是函數(shù)的參數(shù)集合,在函數(shù)內(nèi)部,你可以使用arguments對象獲取到該函數(shù)的所有傳入?yún)?shù)炎疆。
function fn(){
console.log(arguments);
}
fn(2,3) //[2, 3]
4.函數(shù)的重載怎樣實現(xiàn)
在java中重載(overloading) 是在一個類里面卡骂,方法名字相同,而參數(shù)不同
參數(shù)不同:包括 對應(yīng)位置的參數(shù)的類型不同形入,參數(shù)的數(shù)量不同全跨。
而作為javascript這種弱類型語言 我們只需要實現(xiàn) 參數(shù)的數(shù)量不同就可以了
我們可以使用arguments來實現(xiàn)方法的重載;
function fn(){
var sum=0;
for(var i in arguments){
sum+=arguments[i];
}
return sum;
}
fn(2,3);
fn(1,2,3);
5.立即執(zhí)行函數(shù)表達(dá)式是什么亿遂?有什么作用
立即執(zhí)行表達(dá)式就是在函數(shù)定義后立即執(zhí)行浓若;
而JavaScript引擎規(guī)定,如果function關(guān)鍵字出現(xiàn)在行首蛇数,一律解釋成語句挪钓。所以我們一般用括號括上,變成函數(shù)表達(dá)式+括號 來立即調(diào)用
立即執(zhí)行函數(shù)表達(dá)式= 函數(shù)表達(dá)式+([參數(shù)])耳舅;
常用的寫法
(function fn1(){console.log("hello")})();
(function fn2(){console.log("world")}());
//其中函數(shù)名可以省略
(function (){console.log("hello")})();
它的目的有兩個:
一是不必為函數(shù)命名波岛,避免了污染全局變量;
即使是命名了函數(shù)名 也會在執(zhí)行后銷毀
(function fn1(){console.log("hello")})();
console.log(fn1); //報錯 Uncaught ReferenceError: fn1 is not defined
二是IIFE內(nèi)部形成了一個單獨的作用域敦捧,可以封裝一些外部無法讀取的私有變量
6.什么是函數(shù)的作用域鏈
我們首先要理解什么是作用域
作用域包括 全局作用域和局部作用域
- 全局作用域(Global Scope)
全局作用域有兩種定義方式
- 定義在最外層的的變量擁有全局作用域
- 末定義直接賦值的變量自動聲明為擁有全局作用域(這種情況應(yīng)該避免)
function fn(){
global="hello";
var inner= "world";
}
fn();
console.log(global);//未定義變量自動聲明為擁有全局作用域
console.log(inner) //報錯 inner is not defined
2.局部作用域(Local Scope)
和全局作用域相反膘魄,局部作用域一般只在固定的代碼片段內(nèi)可訪問到晾蜘,最常見的例如函數(shù)內(nèi)部,
函數(shù)內(nèi)部可以訪問到,在外部不可以。
function fn(){
var inner= "world";
console.log(inner);
}
fn();
console.log(inner) //報錯 inner is not defined
函數(shù)會首先從函數(shù)內(nèi)部開始查找局部變量,然后逐級向上查找呢岗,直到全局變量,這樣便形成了一個關(guān)于作用域的鏈條蛹尝。
var a=1;
function fn1 (){
var b=10;
function fn2(){
console.log(a);
console.log(b);
}
fn2();
}
fn1();
參考文檔:
阮一峰的Blog
夢想天空的Blog
饑人谷的課件
代碼
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, sex undefined, ["hunger",28] ,name valley
getInfo('男'); // name: "男" ,age: undefined, sex undefined, ["男"] ,name valley
2.寫一個函數(shù),返回參數(shù)的平方和突那?如 (難度**)
function fn(){
var sum=0;
if(arguments.length==0) return 0;
for(var i in arguments){
var temp=+arguments[i];
if(temp!==temp) continue;
sum+= temp*temp;
}
return sum;
}
3.如下代碼的輸出挫酿?為什么 (難度*)
console.log(a); //undefined 變量聲明提前
var a = 1;
console.log(b); //報錯 b is not defined
4.如下代碼的輸出?為什么 (難度*)
sayName('world'); //hello world
sayAge(10); //報錯 sayAge is not a function
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
5.如下代碼的輸出陨收?為什么 (難度**)
function fn(){}
var fn = 3;
console.log(fn); //3 由于fn被覆蓋
6.如下代碼的輸出?為什么 (難度***)
function fn(fn2){
console.log(fn2); //輸出fn2 函數(shù) 實參被函數(shù)覆蓋掉了
var fn2 = 3;
console.log(fn2); //輸出3
console.log(fn); //輸出fn 函數(shù)
function fn2(){
console.log('fnnn2');
}
}
fn(10);
7.如下代碼的輸出鸵赖?為什么 (難度***)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn)); //fn是1 不是函數(shù)
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
9.如下代碼的輸出?為什么 (難度****)
fn();
var i = 10;
var fn = 20;
console.log(i); //10 fn函數(shù)沒有改變?nèi)肿兞?i的值
function fn(){
console.log(i); //undefined 沒有執(zhí)行到 var i=10 i 未定義
var i = 99;
fn2();
console.log(i); //100 由于fn2 中未定義i fn2 改變的是 fn中 i的值
function fn2(){
i = 100;
}
}
10.如下代碼的輸出它褪?為什么 (難度*****)
var say = 0;
(function say(n){
console.log(n);
if(n<3) return; //遞歸調(diào)用 直到n=2 后結(jié)束 10饵骨,9,8茫打,7居触,6,5老赤,4轮洋,3,2抬旺,
say(n-1);
}( 10 ));
console.log(say); //立即執(zhí)行函數(shù)執(zhí)行完后銷毀 弊予,不會影響say 0