1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
- 函數(shù)聲明:function functionName(){};使用function關(guān)鍵字聲明一個(gè)函數(shù),再指定一個(gè)函數(shù)名,叫函數(shù)聲明
函數(shù)表達(dá)式:var fn = function(){};使用function關(guān)鍵字聲明一個(gè)函數(shù),但未給函數(shù)命名,最后將匿名函數(shù)賦予一個(gè)變量fn,叫函數(shù)表達(dá)式,這是最常見的函數(shù)表達(dá)式語(yǔ)法形式
-** 區(qū)別:
1.Javascript引擎在解析javascript代碼時(shí)會(huì)‘函數(shù)聲明提升’(Function declaration Hoisting)當(dāng)前執(zhí)行環(huán)境(作用域)上的函數(shù)聲明,而函數(shù)表達(dá)式必須等到Javascirtp引擎執(zhí)行到它所在行時(shí),才會(huì)從上而下一行一行地解析函數(shù)表達(dá)式**。
2.函數(shù)表達(dá)式后面可以加括號(hào)立即調(diào)用該函數(shù),函數(shù)聲明不可以,只能以fnName()形式調(diào)用 。
alert(foo); // function foo() {} 原因:變量聲明提升
alert(bar); // undefined:原因bar能提升,但是沒賦值,默認(rèn)為undefined
function foo() {}
var bar = function bar_fn() {};
alert(foo); // function foo() {}
alert(bar); // function bar_fn() {}
2.什么是變量的聲明前置?什么是函數(shù)的聲明前置
- 變量的聲明前置:就是在一個(gè)作用域塊中,所有的變量都被放在代碼塊的開始出處聲明
- 函數(shù)的聲明前置:和變量的聲明會(huì)前置一樣,函數(shù)聲明同樣會(huì)前置。
- 函數(shù)聲明的前置為:聲明和賦值均前置。
- 函數(shù)表達(dá)式的前置為:僅僅聲明前置,值為undefined,直到讀到表達(dá)式后才取得表達(dá)式的值。
3.arguments 是什么
arguments是類數(shù)組對(duì)象,包含著傳入函數(shù)中的所有參數(shù)。arguments 變量不是一個(gè)數(shù)組(Array)。 盡管在語(yǔ)法上它有數(shù)組相關(guān)的屬性 length,但它不從 Array.prototype 繼承,實(shí)際上它是一個(gè)對(duì)象(Object)。
因此,無(wú)法對(duì) arguments 變量使用標(biāo)準(zhǔn)的數(shù)組方法,比如 push, pop 或者 slice。
eg: function printPersonInfo(name, age, sex){
console.log(arguments);
}
printPersonInfo("tiger",6,"boy")

4.函數(shù)的"重載"怎樣實(shí)現(xiàn)
- "重載"的概念:,是Ada、C++、C#、D和Java等編程語(yǔ)言中具有的一項(xiàng)特性,這項(xiàng)特性允許創(chuàng)建數(shù)項(xiàng)名稱相同但功能的輸入輸出類型不同的子程序,它可以簡(jiǎn)單地稱為一個(gè)單獨(dú)功能可以執(zhí)行多項(xiàng)任務(wù)的能力。
其他語(yǔ)言的重載;
int sum(int num1, int num2){
return num1 + num2;
}
float sum(float num1, float num2){
return num1 + num2;
}
sum(1, 2);
sum(1.5, 2.4);
- 在 JS 中沒有重載! 同名函數(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); // 'Byron' 26
printPeopleInfo('Byron', 26, 'male');// 'Byron' 26 'male'
5.立即執(zhí)行函數(shù)表達(dá)式是什么?有什么作用
- 英文:immediately-invoked function expression,縮寫:IIFE,是一種利用JavaScript函數(shù)生成新作用域的編程方法。有時(shí),這種編程方法也被叫做“自執(zhí)行(匿名)函數(shù)”,但“立即調(diào)用函數(shù)表達(dá)式”是語(yǔ)義上最準(zhǔn)確的術(shù)語(yǔ)。
-
作用
隔離作用域,保護(hù)私有變量,防止污染全局變量 -
用法
最常見的一種是將函數(shù)表達(dá)式字面量置于圓括號(hào)之內(nèi),然后使用圓括號(hào)調(diào)用函數(shù)。
(置于圓括號(hào)內(nèi)是因?yàn)椋簾o(wú)論在全局環(huán)境或者局部環(huán)境里遇到了這樣的function關(guān)鍵字,默認(rèn)的,它會(huì)將它當(dāng)作是一個(gè)函數(shù)聲明,而不是函數(shù)表達(dá)式,如果你不明確的告訴圓括號(hào)它是一個(gè)表達(dá)式,它會(huì)將其當(dāng)作沒有名字的函數(shù)聲明并且拋出一個(gè)錯(cuò)誤,因?yàn)楹瘮?shù)聲明需要一個(gè)名字)
(function() { // 這里的語(yǔ)句將獲得新的作用域 })(); 若要將作用域外變量傳遞進(jìn)函數(shù),則按下述方式書寫: (function(a, b) { // a == 'hello' // b == 'world' })('hello', 'world'); 在一些省略分號(hào)的程序中,可見將分號(hào)至于行首的做法。這樣的分號(hào)被稱為“防御性分號(hào)” a = b + c ;(function() { // 故意將分號(hào)放在這里 // 代碼 })(); 如此書寫,以防止語(yǔ)句被理解為對(duì)函數(shù)c的調(diào)用(c(...))。
6.求n!,用遞歸來(lái)實(shí)現(xiàn)
function factorial(n){
if(n<0){
return "無(wú)效輸入";
}
else if(n<=1){
return 1;
}else{
return n*factorial(n-1) ;
}
}
alert(factorial(5))//120
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('男');

8. 寫一個(gè)函數(shù),返回參數(shù)的平方和?
function sumOfSquares(){
var sum = 0;
for(var i =arguments.length;i>0;i--){
sum+=Math.pow(arguments[i-1],2);
}
return sum
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
9. 如下代碼的輸出?為什么
console.log(a); //undefined ;變量a聲明提前,但未賦值
var a = 1;
console.log(b);//b is not defined ;變量b沒有聲明和賦值
10. 如下代碼的輸出?為什么
sayName('world');// hello world;函數(shù)聲明的前置為聲明和賦值均前置
sayAge(10);//sayAge is not a function ;函數(shù)聲明前置,但表達(dá)式值不能前置,sayAge為undefined,undefined 沒有方法。
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
11. 如下代碼輸出什么? 寫出作用域鏈查找過(guò)程偽代碼
var x = 10
bar() //返回:10
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
globalContext={
Ao:{
x:10
foo:function
bar:function
} ,
Scope:null
}
//聲明 foo 時(shí) 得到下面
foo.[[scope]] = globalContext.Ao
//聲明 bar 時(shí) 得到下面
bar.[[scope]] = globalContext.Ao
//當(dāng)調(diào)用 bar() 時(shí), 進(jìn)入 bar 的執(zhí)行上下文
barContext ={
Ao:{
x:30
},
Scope:bar.[[scope]]// globalContext.Ao
}
當(dāng)調(diào)用 foo() 時(shí),先從 bar 執(zhí)行上下文中的 AO里找,找不到再?gòu)?bar 的 [[scope]]里找找到后即調(diào)用
//當(dāng)調(diào)用 foo() 時(shí),進(jìn)入 foo 的執(zhí)行上下文
fooContext = {
AO: {},
Scope: foo.[[scope]] // globalContext.AO
}
所以 console.log(x)是 10
12. 如下代碼輸出什么? 寫出作用域鏈查找過(guò)程偽代碼
var x = 10;
bar() //返回30
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
作用域查找過(guò)程偽代碼
globalContext={
Ao:{
x:10
bar:function
} ,
Scope:null
}
//聲明 bar 時(shí) 得到下面
bar.[[scope]] = globalContext.Ao
//當(dāng)調(diào)用 bar() 時(shí), 進(jìn)入 bar 的執(zhí)行上下文
barContext ={
Ao:{
x:30,
foo:function
},
Scope:bar.[[scope]]// globalContext.Ao
}
當(dāng)調(diào)用 foo() 時(shí),先從 bar 執(zhí)行上下文中的 AO里找,找到后即調(diào)用
//當(dāng)調(diào)用 foo() 時(shí),進(jìn)入 foo 的執(zhí)行上下文
fooContext = {
AO: {},
Scope: foo.[[scope]] // barContext.AO
}
所以 console.log(x)是 30
13. 以下代碼輸出什么? 寫出作用域鏈的查找過(guò)程偽代碼
var x = 10;
bar() // 30
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
作用域鏈的查找過(guò)程偽代碼
globalContext = {
Ao:{
x:30
bar:function
},
Scope:null
}
// 聲明bar時(shí),得到下面
bar.[[scope]]=globalContext.Ao;
//當(dāng)調(diào)用bar時(shí),進(jìn)入bar的執(zhí)行上下文;先從 bar 執(zhí)行上下文中的 AO里找,找到后即調(diào)用
barContext = {
Ao:{
x:30
IIFE:function
}
Scope: bar.[[scope]]//globalContext.Ao
}
所以 console.log(x)是 30
14. 以下代碼輸出什么? 寫出作用域鏈查找過(guò)程偽代碼
var a = 1;
function fn(){
console.log(a)//undefined
var a = 5
console.log(a)//5
a++
var a
fn3()
fn2()
console.log(a) //20
function fn2(){
console.log(a) //6
a = 20
}
}
function fn3(){
console.log(a) //1
a = 200
}
fn() //20
console.log(a) //200
//作用域鏈查找過(guò)程偽代碼
globalContext = {
Ao:{
a:200
fn:function
fn3:function
},
Scope:null
}
// 聲明fn時(shí),得到下面
fn.[[scope]] = globalContext .Ao
// 聲明fn3時(shí),得到下面
fn3.[[scope]] = globalContext .Ao
fnContext={
Ao:{
a:20
fn2:function
}
Scope:fn.[[scope]]// globalContext .Ao
}
fn3Context={
Ao:{}
Scope:fn.[[scope]]// globalContext .Ao
}
// 聲明fn2時(shí),得到下面
fn2.[[scope]] = fnContext .Ao
fn2Context={
Ao:{}
Scope:fn.[[scope]]// fnContext .Ao
}
所以 fn()是20 console.log(a)是200