1.函數聲明和函數表達式有什么區(qū)別 (*)
寫法上的區(qū)別。
函數聲明,是關鍵字
function加函數名函數表達式是 前面比那里,后面一個匿名函數賦值給變量
解析上的差異
函數聲明有個聲明前置,可以把調用語句寫在函數聲明的前面或者后面都行,因為默認的會把函數聲明放前面去
然而函數表達式就不行,調用語句必須寫在后面,因為函數表達式相當于變量的賦值,只能把變量聲明前置了。
2.什么是變量的聲明前置?什么是函數的聲明前置 (**)
- 變量聲明前置會默認把變量的聲明放到前面
例如:
console.log(i); //undefined
var i=100;
這個時候console.log(v);會返回undefined,說明這個變量是在它前面就聲明了,這就是變量聲明前置
- 函數聲明前置會默認把函數聲明放到前面
test1();//我是函數聲明
test2();//test2 is not a function(…)
function test1(){
console.log('我是函數聲明')
}
var test2=function(){
console.log('我是函數表達式')
}
調用語句放在了函數聲明前面,但是結果依然是出來的,這就是函數聲明前置,另外函數表達式就沒有這樣的功能,所以前面調用的時候報錯了
3.arguments 是什么 (*)
- 類似數組,指的是函數的參數,在函數內部默認存在,我們可以通過
arguments來調用函數的每個參數,條目的索引從0開始 后面依次。
function yingxiong(){
console.log('英雄:'+arguments[0]);
console.log('技能:'+arguments[1]);
console.log('口號:'+arguments[2]);
}
yingxiong('蓋倫','大寶劍','人在塔在');//得到以下
英雄:蓋倫
技能:大寶劍
口號:人在塔在
4.函數的重載怎樣實現 (**)
- js函數沒有重載這個概念,因為只要函數名相同,上面的就會被下面的覆蓋,但是js的函數是可以支持無所個參數的,我們可以通過函數
arguments來實現重載。
function item(){
var s="";
for(var i=0;i<arguments.length;i++){
s =s+(arguments[i]+" ");
}
console.log(s);
}
item("項目1","項目2","項目3");//項目1 項目2 項目3
5.立即執(zhí)行函數表達式是什么?有什么作用 (***)
- 簡稱IIFE :immediately-invoked function expression
- 寫法:將函數聲明用一個括號框起,讓JavaScript引擎將其理解為一個表達式,后面再接括號直接調用。
(function(){
//
})();
或
(function(){
//
}());
- 作用:將js代碼包裹在匿名函數中并立即執(zhí)行,保護變量名外部不可見,不必擔心覆蓋的問題而導致變量的污染
參考
6.什么是函數的作用域鏈 (****)
- JavaScript中所有的兩都是存在于某一個作用域中,除了全局作用域,每一個作用域都是存在于某個作用域中,在試圖訪問一個變量時JS引擎會從當前作用域開始向上查找知道Global全局作用域停止。
- 例如:當alert(a);時,JS引擎沿著d的作用域,b的作用域,全局作用域的順序查找,這樣就構成了作用域鏈。
var a;//全局作用域
function b(){
var c;//c位于b函數的作用域
function d(){
var e;//e位于函數d的作用域
alert(a)
}
}
7.代碼
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.寫一個函數,返回參數的平方和?如 (難度**)
function sumOfSquares(){
var s=0;
for(var i=0;i<arguments.length;i++){
s+=arguments[i]*arguments[i]
}
return s;
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3.如下代碼的輸出?為什么 (難度*)
console.log(a); //undefined
var a = 1;
console.log(b); //b is not defined
//因為a變量有個提升,當打印a的時候變量a已經聲明但未賦值,而b還未聲明所以報錯
//變量提升如下:
var a;
console.log(a);
a = 1;
console.log(b);
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);
};
hello world:是因為聲明函數有前置,函數放置的上下順序并不會影響調用
第二個報錯:是因為函數表達式不會前置,這個時候變量sayAge雖然前置了但并不是函數,所以輸入參數會報錯
5.如下代碼的輸出?為什么 (難度**)
function fn(){}
var fn = 3;
console.log(fn);//3,按順序執(zhí)行,當打印fn的時候fn被覆蓋賦值為3
6.如下代碼的輸出?為什么 (難度***)
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
fn(10);
變量提升和聲明函數前置后的樣子。
function fn(fn2){
var fn2;
function fn2(){
console.log('fnnn2');
}
console.log(fn2);
fn2 = 3;
console.log(fn2);
console.log(fn);
}
fn(10);
console.log(fn2);//function fn2(){console.log('fnnn2');} 因為函數聲明前置了,相當于把這個函數賦值給了fn2
console.log(fn2); //3 當打印到這的時候變量fn2已被賦值為3
console.log(fn); 打印整個函數fn(),打印的時候先從局部作用域尋找,發(fā)現沒找到,就從全局作用域尋找,然后打印出外面都函數聲明
console.log('fnnn2');只聲明未調用
7.如下代碼的輸出?為什么 (難度***)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
- 變量提升和聲明函數前置后的樣子。
var fn;
function fn(fn){
console.log(fn);
}
fn = 1;
console.log(fn(fn)); //fn is not a function
//這個時候fn已經被賦值為1,不是函數 所以報錯
8.如下代碼的輸出?為什么 (難度**)
//作用域
console.log(j);
//undefined //除了函數其余都沒有局部作用域,所以j這個時候已經聲明并且提升但未賦值
console.log(i);
//undefined//i已經聲明并且前置,但是還未賦值
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i);//10 for循環(huán)結束得到i=10 所以打印10
console.log(j);//100 打印到這的時候j已經被賦值為100
9.如下代碼的輸出?為什么 (難度****)
fn();
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;
}
}
- 變量提升和聲明函數前置后的樣子。
var i;
var fn;
function fn(){
var i;
function fn2(){
i = 100;
}
console.log(i);//undefined 在局部作用域i已經被聲明且提升
i = 99;
fn2();
console.log(i); //100 前面fn2();已經被調用執(zhí)行,這個時候i賦值為100
}
fn();
i = 10;
fn = 20;
console.log(i);//10 i被賦值位10
10.如下代碼的輸出?為什么 (難度*****)
var say = 0;
(function say(n){
console.log(n); //打印 10 9 8 7 6 5 4 3 2
//這是個立即執(zhí)行函數外面的say=0沒有關系,當輸入10調用的時候首先打印10 然后因為這是個遞歸函數,當n<3的時候停止,所以會依次一直打印直到滿足條件停止,所以到2就停止了。
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);//0 上面的立即執(zhí)行函數和外面函數已經隔絕 不會有命名覆蓋的問題,可以不理,所以打印結果0