1.函數聲明和函數表達式有什么區(qū)別
函數聲明 :function fn() {} // fn();
1 函數聲明必須有函數名 ,
2 函數可以在任意地方調用fn();
函數表達式
1 前后兩個函數的名字可以相同也可以不相同 。
2 function 后面的這個名字是可以省略的 公浪。
3 function 后面的這個名字只能再函數內部使用盹愚。
4 函數調用只有在函數表達式聲明后調用。
2.什么是變量的聲明前置?什么是函數的聲明前置琼腔。
2.什么是變量的聲明前置寞秃?什么是函數的聲明前置
和變量的聲明會前置一樣斟叼,函數聲明同樣會前置,如果我們使用函數表達式那么規(guī)則和變量一樣.
fn(); // "1"
function fn(){
console.log('1');
}
如果我們使用函數聲明的方式春寿,那么即使函數寫在最后也可以在前面語句調用朗涩,前提是函數聲明部分已經被下載到本地
fn(); // "1"
function fn(){
console.log('1');
}
3.arguments 是什么?
arguments 是JavaScript里的一個內置對象,有的[函數]都有屬于自己的一個arguments對象绑改,它包括了函所要調用的參數谢床。object對象。
function printPersonInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
}
4.函數的重載怎樣實現厘线。
JavasScript不支持函數的重載识腿,但是我們可以通過arguments判斷調用時傳入的參數的個數,然后對不同的情況采取不同的處理方式造壮。例子如下:
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);
printPeopleInfo('Byron', 26, 'male');
5.立即執(zhí)行函數表達式是什么渡讼?有什么作用 ?
立即執(zhí)行函數就是聲明一個匿名函數,然后馬上調用這個函數耳璧。
立即執(zhí)行函數的格式:(function(){console.log(立即執(zhí)行函數);})()成箫;
立即執(zhí)行函數的作用是:創(chuàng)建一個獨立的作用域,這個作用域里面的變量旨枯,外面訪問不到蹬昌。它可以幫你封裝大量的工作而不會在背后遺留任何全局變量。你定義的所有變量都會成為立即執(zhí)行函數的局部變量攀隔,所以你不用擔心這些臨時變量會污染全局空間凳厢。
6.什么是函數的作用域鏈 ?
a) 一個函數創(chuàng)建時账胧,javascript后臺(引擎)會默認創(chuàng)建一個僅供后臺使用的內部屬性[[Scope]],此屬性存儲函數的作用域鏈先紫,如果是全局函數治泥,此時則包含一個變量對象(全局變量),如果是嵌套函數(閉包)遮精,作用域鏈還加上了父函數的變量對象居夹。例如下面的這個全局函數:
function add(num1,num2)
{ var sum = num1 + num2; return sum;}
(此圖是函數定義時的作用域鏈)
b) 函數被調用時--add(5,10),javascript后臺會創(chuàng)建一個內部對象(execution context)--“執(zhí)行環(huán)境”或“運行期上下文”本冲,執(zhí)行環(huán)境有它自己的作用域鏈准脂,執(zhí)行環(huán)境創(chuàng)建時就以定義函數時的作用域鏈初始化它自己的作用域鏈,并且隨后創(chuàng)建了一個活動對象檬洞,活動對象作為函數執(zhí)行期的一個變量對象狸膏,包含所有局部變量(在函數內定義的)、命名參數添怔、arguments湾戳、this,它會被推入到執(zhí)行環(huán)境作用域鏈的前端(如下圖)广料。每執(zhí)行一次函數都會創(chuàng)建一個新的執(zhí)行環(huán)境砾脑,當函數執(zhí)行完畢執(zhí)行環(huán)境就會被銷毀。
(此圖是函數運行時的作用域鏈)
另外關于延長作用域鏈問題:以下的兩種情況會使作用域鏈延長
- try-catch語句的catch塊艾杏;
- with語句韧衣;
這個兩個語句都會再原本的作用域鏈的前端添加一個變量對象。對于with語句來說购桑,新添加的變量對象包含著with括號中指定對象的所有屬性和方法所作的變量聲明畅铭。對于catch來說,當try塊發(fā)生錯誤時勃蜘,代碼執(zhí)行流程自動轉入到catch塊顶瞒,并將異常對象推入到作用域鏈的前端。catch塊執(zhí)行完畢后元旬,作用域鏈就會返回原來的狀態(tài)榴徐。
當代碼流執(zhí)行到一個with表達式時,執(zhí)行環(huán)境的作用域鏈會被臨時改變匀归,此時with的變量對象會被創(chuàng)建添加到作用域鏈的前端坑资,這就意味著此時函數的所有局部變量都被推入到第二個作用域鏈中的變量對象,如下圖:
由上圖可清晰的看到穆端,在執(zhí)行with語句時袱贮,訪問局部變量的代價更高了。所以盡可能避免使用with語句体啰,可以使用局部變量代替
代碼:
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, '男');
//輸出為:getInfo('hunger', 28, '男');
//name: hunger
//age: 28
//sex: 男
//["hunger", 28, "男"]
//name valley
getInfo('hunger', 28);
//name: hunger
//age: 28
//sex: undefined
//["hunger", 28]
//name valle
getInfo('男');
//name: 男
//age: undefined
//sex: undefined
//["男"]
//name valley
2、寫一個函數柒莉,返回參數的平方和闻坚?如 (難度**)
function sumOfSquares(){
for(var i=0;i<arguments.length;i++{
var sum = 0;
sum += arguments[i]*arguments[i];
return sum;
}
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3、如下代碼的輸出兢孝?為什么 (難度*)
console.log(a);
var a = 1;
console.log(b);
//等于
//聲明前置
var a;
console.log(a);
a=1;
console.log(b)
//輸出
// undefined
//Uncaught ReferenceError: b is not defined(…)
4.如下代碼的輸出窿凤?為什么 (難度*)
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
//hello world
//報錯,因為sayAge(10);之前未聲明sayAge是一個函數
5.如下代碼的輸出跨蟹?為什么 (難度**)
function fn(){}
var fn = 3;
console.log(fn);
//3
//在同一個作用域內雳殊,變量同函數同名時,覆蓋之前的函數聲明
6.如下代碼的輸出窗轩?為什么 (難度***)
function fn(){}
var fn = 3;
console.log(fn);
//3
//在同一個作用域內夯秃,變量同函數同名時,覆蓋之前的函數聲明
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);
//輸出
function fn2(){
console.log('fnnn2');
}
3
function fn(fn2){
console.log(fn2);
var fn2 = 3;
console.log(fn2);
console.log(fn);
function fn2(){
console.log('fnnn2');
}
}
7.如下代碼的輸出痢艺?為什么 (難度***)
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
//報錯仓洼,因為fn最后是一個等于1的全局變量
8.如下代碼的輸出?為什么 (難度**)
//作用域
console.log(j);
console.log(i);
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i);
console.log(j);
//undefined i未賦值
//undefined j未賦值
//10 for循環(huán)最后i=10
// 100 var 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);
i = 99;
fn2();
console.log(i);
}
fn();
i = 10;
fn = 20;
console.log(i);
//最后輸出
//undefined
//100
//10
10.如下代碼的輸出衬潦?為什么 (難度*****)
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
//先分解中間那個立即執(zhí)行函數表達式斤蔓,等于
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}
say(10);)
console.log(say);
//把所有聲明提前植酥,變成
var say;
(function say(n){
console.log(n); //第一次10,之后每次減1弦牡,直到2
if(n<3) return; //最后return出一個2友驮,結束循環(huán)
say(n-1);
}
say(10);)
say=0;
console.log(say); //這里為0
//最后就是10到2,接一個0: 10,9,8,7,6,5,4,3,2,0