1. 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
- 使用function關(guān)鍵字聲明一個(gè)函數(shù)時(shí),聲明不必放到調(diào)用的前面。
//函數(shù)聲明 function sayHello(){ console.log('hello') } //函數(shù)調(diào)用 sayHello()
函數(shù)表達(dá)式是把一個(gè)匿名函數(shù)function()賦給一個(gè)變量,聲明必須放到調(diào)用的前面。
//函數(shù)聲明 var sayHello = function(){ console.log('hello'); } //函數(shù)調(diào)用 sayHello() - 函數(shù)聲明必須有標(biāo)識(shí)符,也就是常說(shuō)的函數(shù)名,函數(shù)表達(dá)式可以省略函數(shù)名。
- 用函數(shù)聲明創(chuàng)建的函數(shù)可以隨時(shí)調(diào)用,而用函數(shù)表達(dá)式創(chuàng)建的函數(shù)是在運(yùn)行時(shí)進(jìn)行賦值,且要等到表達(dá)式賦值完成后才能調(diào)用。
2. 什么是變量的聲明前置?什么是函數(shù)的聲明前置
- 在一個(gè)作用域下,var 聲明的變量和function 聲明的函數(shù)會(huì)前置
console.log(a);//undefined
var a = 3; console.log(a);//3
sayHello(); function sayHello(){ console.log('hello'); }
執(zhí)行順序?yàn)椋?br>var a function sayHello() console.log(a)//undefined
a = 3 console.log(a)//3
sayHello() - 函數(shù)內(nèi)部的聲明前置。
var a = 1; function main() { console.log(a); var a = 2; } main()
輸出undefined,函數(shù)的執(zhí)行順序如下,變量聲明被提前了。
var a = 1; function main() { var a; console.log(a);//此時(shí)a為undefined
a = 2; } - 解析器在向執(zhí)行環(huán)境加載數(shù)據(jù)時(shí),會(huì)率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用,所以存在函數(shù)聲明提升,對(duì)代碼求值的時(shí)候,js引擎在第一遍會(huì)聲明函數(shù)并將它們放到源代碼樹(shù)的頂部,所以即使調(diào)用函數(shù)的語(yǔ)句在聲明函數(shù)的前面也能正常執(zhí)行。但是對(duì)于函數(shù)表達(dá)式,它必須等到解析器執(zhí)行到它所在的代碼行,才會(huì)真正被解釋執(zhí)行。
3. arguments 是什么
arguments是一個(gè)類(lèi)數(shù)組對(duì)象,在函數(shù)內(nèi)部,可以使用arguments對(duì)象獲取到該函數(shù)的所有傳入?yún)?shù)。
4. 函數(shù)的"重載"怎樣實(shí)現(xiàn)
JS沒(méi)有重載! 同名函數(shù)會(huì)覆蓋。 但可以在函數(shù)體針對(duì)不同的參數(shù)調(diào)用執(zhí)行相應(yīng)的邏輯。例如:
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');
可以在函數(shù)體內(nèi)部使用if語(yǔ)句,來(lái)根據(jù)傳遞的參數(shù),執(zhí)行不同的語(yǔ)句,來(lái)模擬函數(shù)的重載。
5. 立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用
表達(dá)式:(function(){ })();
立即執(zhí)行函數(shù)就是,聲明一個(gè)匿名函數(shù),馬上調(diào)用這個(gè)匿名函數(shù)。立即執(zhí)行函數(shù)可以創(chuàng)建一個(gè)獨(dú)立的作用域,這個(gè)作用域里面的變量,外面訪問(wèn)不到(即避免變量污染)。
6. 求n!,用遞歸來(lái)實(shí)現(xiàn)
function factor(n){ if(n === 1) { return 1 } return n * factor(n-1) } factor(5) n=5
7. 以下代碼輸出什么?
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('饑人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
function getInfo(name, age, sex) { console.log('name:',name); console.log('age:', age); console.log('sex:', sex); } getInfo('饑人谷', 2, '男');結(jié)果://name: 饑人谷 age: 2 sex: 男
getInfo('小谷', 3);結(jié)果://name: 小谷 age: 3 sex: undefined
getInfo('男');結(jié)果://name: 男 age: undefined sex: undefinedfunction getInfo(name, age, sex) { console.log(arguments); } getInfo('饑人谷', 2, '男');結(jié)果:類(lèi)數(shù)組 ["饑人谷", 2, "男"]
getInfo('小谷', 3);結(jié)果:類(lèi)數(shù)組 ["小谷", 3]
getInfo('男');結(jié)果:類(lèi)數(shù)組 ["男"]function getInfo(name, age, sex) { arguments[0] = 'valley'; console.log('name', name); } getInfo('饑人谷', 2, '男');結(jié)果:name valley
getInfo('小谷', 3);結(jié)果:name valley
getInfo('男');結(jié)果:name valley
8. 寫(xiě)一個(gè)函數(shù),返回參數(shù)的平方和?
function sumOfSquares(num1,num2,num3) { sum = num1*num1+num2*num2+num3*num3; return sum; } var result = sumOfSquares(2,3,4); console.log(result)//29function sumOfSquares(num1,num2) { sum = num1*num1+num2*num2; return sum; } var result2 = sumOfSquares(1,3); console.log(result2)//10
9. 如下代碼的輸出?為什么
console.log(a); //結(jié)果:undefined
var a = 1;
console.log(b); //結(jié)果:報(bào)錯(cuò),b沒(méi)有定義。
因?yàn)樽兞柯暶鲿?huì)前置,實(shí)際順序如下:
var a console.log(a); a = 1; console.log(b);
10. 如下代碼的輸出?為什么
sayName('world'); //結(jié)果:hello world
sayAge(10); //結(jié)果:報(bào)錯(cuò),sayAge不是一個(gè)函數(shù)。
function sayName(name){ console.log('hello ', name); } var sayAge = function(age){ console.log(age); };
因?yàn)楹瘮?shù)聲明會(huì)前置,但函數(shù)表達(dá)式只會(huì)在執(zhí)行時(shí)才會(huì)運(yùn)行函數(shù),實(shí)際順序如下:
function sayName(name){ console.log('hello ', name); } //聲明函數(shù)
var sayAge //聲明變量
sayName("name") //調(diào)用函數(shù)
sayAge(10); // 調(diào)用函數(shù),但按順序函數(shù)還未聲明。
sayAge = function(age){ console.log(age); };
11. 如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var x = 10 bar() function foo() { console.log(x) } function bar(){ var x = 30 foo() }
結(jié)果:10
作用域鏈查找過(guò)程:
globalContext { AO: { x: 10, foo: function bar: function }, Scope: null }
//foo.[[scope]] = globalContext.AO
//bar.[[scope]] = globalContext.AO
barContext { AO: { x: 30 foo: function }, Scope: bar.[[scope]] }
fooContext { AO: {}, Scope: foo.[[scope]] }
console.log(x)先從foo 執(zhí)行上下文中的AO里找,找不到再?gòu)膄oo的[[scope]]里找,找到后即調(diào)用,所以 console.log(x)是 10
12. 如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var x = 10; bar() function bar(){ var x = 30; function foo(){ console.log(x) } foo(); }
結(jié)果:30
作用域鏈查找過(guò)程:
globalContext { AO: { x: 10 bar: function }, Scope: null } //bar.[[scope]] = globalContext.AO barContext { AO: { x: 30 foo: function }, Scope: bar.[[scope]] } //foo.[[scope]] = barContext.AO fooContext { AO: {}, Scope: foo.[[scope]] }
console.log(x)先從foo 執(zhí)行上下文中的AO里找,找不到再?gòu)膄oo的[[scope]]里找,即是bar的執(zhí)行上下文,所以 console.log(x)是 30
13. 以下代碼輸出什么? 寫(xiě)出作用域鏈的查找過(guò)程偽代碼
var x = 10; bar() function bar(){ var x = 30; (function (){ console.log(x) })() }
結(jié)果:30
作用域鏈的查找過(guò)程:
globalContext { AO: { x: 10 bar: function }, Scope: null } //bar.[[scope]] = globalContext.AO barContext { AO: { x: 30 function: function }, Scope: bar.[[scope]] } //function.[[scope]] = barContext.AO functionContext { AO: {}, Scope: function.[[scope]] }
console.log(x)先從function 執(zhí)行上下文中的AO里找,找不到再?gòu)膄unction的[[scope]]里找,即是bar的執(zhí)行上下文,所以 console.log(x)是 30
14. 以下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼
var a = 1; function fn(){ console.log(a) //僅聲明,未賦值,undefined var a = 5 console.log(a) //賦值為5 a++ //自增變?yōu)? var a
fn3() //先執(zhí)行fn3里的console.log(a),為1
fn2() //再執(zhí)行fn2里的console.log(a),為6
console.log(a) //經(jīng)過(guò)fn2,a變?yōu)?0
function fn2(){ console.log(a) //即fnContext.AO = globalContext.AO中的a a = 20 } }
function fn3(){
console.log(a) //即globalContext.AO中的a
a = 200 //globalContext.AO中的a變?yōu)?00
}
fn()
console.log(a) //調(diào)用globalContext.AO中的a = 200
結(jié)果:
作用域鏈的查找過(guò)程:
globalContext { AO: { x: 1 fn: function fn3: function }, Scope: null } //fn.[[scope]] = globalContext.AO //fn3.[[scope]] = globalContext.AO fnContext { AO: { x: 1 //之后a賦值5,再之后a++
fn2: function }, Scope: fn.[[scope]] //即globalContext.AO } //fn2.[[scope]] = fnContext.AO fn3Context { AO: { }, Scope: fn3.[[scope]] //即globalContext.AO
}
結(jié)果:
undefined
5
1
6
20
200