JS函數(shù)

1.函數(shù)聲明和函數(shù)表達式有什么區(qū)別 ?

函數(shù)聲明:
function func(){
    console.log(1)
}
函數(shù)表達式:(一般匿名函數(shù)賦給一個變量)
var tmp = function (){
    console.log(1)
};
因此函數(shù)聲明和函數(shù)表達式不同之處在于:
    1、js引擎在解析javascript代碼時會[函數(shù)聲明提升],把當前執(zhí)行環(huán)境(作用域)上的函數(shù)聲明給提到執(zhí)行環(huán)境的前頭;而函數(shù)表達式則必須是等到j(luò)s引擎執(zhí)行到它所在的那行代碼,才會從上而下一行一行地解析函數(shù)表達式中的代碼
    2、函數(shù)聲明之后,只需要 func()即可調(diào)用;而函數(shù)表達式后面可以加括號作為立即執(zhí)行函數(shù)調(diào)用,函數(shù)聲明則不可以。
    3、函數(shù)聲明是以function關(guān)鍵詞開始,如果不是,那么它就是函數(shù)表達式。
    4、函數(shù)聲明最后面一般不寫分號,而函數(shù)表達式有分號。

2.什么是變量的聲明前置?什么是函數(shù)的聲明前置

js引擎的工作方式:先解析代碼,獲取所有被聲明的變量,然后一行一行執(zhí)行,會把所有的變量的聲明語句都被提到代碼的頭部,這就叫做變量的聲明前置。

  • 變量的聲明前置:
    ①變量前置就是把變量的聲明提前到當前作用域的最前面,但變量的賦值仍然按照原來的順序執(zhí)行,如果變量聲明但未被賦值,變量會自動賦值為undefined。
var a = 2;
等同于
var a;
a = 2;
  • 函數(shù)的聲明前置:
    ①函數(shù)聲明前置和變量的聲明前置實質(zhì)是一樣的。函數(shù)的聲明前置有兩種情況,一個是使用函數(shù)聲明,則整個聲明都前置,而且會被前置到變量聲明的后面;另一個是使用函數(shù)表達式,那么規(guī)則和變量的聲明前置一樣。
fn()
function fn(){
    console.log(1)
}//1
等同于
function fn(){ console.log (1) }
fn()
  • 函數(shù)表達式的聲明前置:
fn(1)
var f = function fn(n){
    console.log(n)
}
等同于
var f;
fn(1)
f = function fn(n){
    console.log(n)
}
//Uncaught ReferenceError: fn is not defined(…)

疑問:寫上面這題的函數(shù)表達式用具名函數(shù)還是匿名函數(shù)規(guī)范呢?


3.arguments 是什么

  • 在函數(shù)內(nèi)部,可以使用arguments對象獲取到該函數(shù)傳入的全部參數(shù),一般簡稱為[參數(shù)列表]
    (1).arguments是一個類數(shù)組對象,代表傳給一個function的參數(shù)列表,只在函數(shù)內(nèi)部起作用。arguments的值與函數(shù)傳入實參有關(guān),與函數(shù)定義形參無關(guān)。
    (2).即使函數(shù)聲明時不用詳細寫清楚傳入的參數(shù)的個數(shù)和名稱,也能使用arguments獲取參數(shù)。
    (3).arguments是一個偽數(shù)組,無真正數(shù)組的API(eg:push、pop那些方法)。
    (4).arguments.length:指的是實參的長度,不是形參的長度
    (5).arguments是function的隱含屬性,它將會把實參顯示成一個類組對象。
function fn(a,b,c){
    console.log(arguments)
    console.log(arguments.length)
}
fn(1,2,3,4)
11.png

4.函數(shù)的重載怎樣實現(xiàn)

①重載是很多面向?qū)ο笳Z言實現(xiàn)多態(tài)的手段之一,相同名字的函數(shù)參數(shù)個數(shù)不同或者順序不同都被認為是不同的函數(shù),稱為函數(shù)重載。
②在JavaScript中沒有函數(shù)重載的概念,函數(shù)通過名字確定唯一性,參數(shù)不同也被認為是相同的函數(shù),后面的覆蓋前面的。

那是否意味著JS不能通過重載功能來實現(xiàn)一個函數(shù),參數(shù)不同功能不同呢?
答:JavaScript可以通過自身的屬性去模擬函數(shù)重載;可以用arguments來實現(xiàn)函數(shù)的重載(關(guān)鍵只要傳實參的個數(shù)有所不同即可)

22.png

5.立即執(zhí)行函數(shù)表達式是什么?有什么作用

立即執(zhí)行函數(shù)表達式(Immediately-Invoked Function Expression)簡稱IIFE
通俗點解釋:平時寫語句是無需得出結(jié)果,但是表達式是需要求出結(jié)果的。所以推測出立即執(zhí)行函數(shù)表達式字面意思是一個為了馬上得出結(jié)果的函數(shù)。

  • 立即執(zhí)行函數(shù)表達式是什么?
    (1).聲明一個匿名函數(shù)
    (2).馬上調(diào)用這個匿名函數(shù)
    (3).聲明一個匿名函數(shù)function(){} ,然后在匿名函數(shù)后面加一對括號() ,調(diào)用這個匿名函數(shù)
    (4).在function前面加!、 +、 — 、()可以起到函數(shù)定義后立即執(zhí)行的效果,加上運算符后,就告訴js引擎這是一個函數(shù)表達式,不是函數(shù)定義。
典型一:(function(){  alert("我是匿名函數(shù)")    })()
典型二:(function(){  alert("我是匿名函數(shù)")    }())
典型三:!function (){  alert("我是匿名函數(shù)")  }()
典型四:var fn =function(n){console.log(n)}(1) //1
  • 立即執(zhí)行函數(shù)表達式有什么作用?
    作用:創(chuàng)建一個獨立的作用域;這個作用域里面的變量,外面訪問不到(即避免[變量污染]);
    當同時調(diào)用多個JS的情況時,很容易造成因為變量名一致或函數(shù)名一致而覆蓋其他庫的變量;所以才需要采用立即執(zhí)行函數(shù);
    定義的變量都成了立即執(zhí)行函數(shù)的局部變量,以后即使變量名或函數(shù)名一樣也不被污染,同時形成了一個單獨的作用域,可以封裝一些外部無法讀取的私有變量;

6.什么是函數(shù)的作用域鏈

①作用域:作用域就是變量與函數(shù)的可訪問范圍,作用域控制著變量與函數(shù)的可見性和生命周期

  • 全局變量:變量沒有在函數(shù)內(nèi)聲明或者聲明的時候沒有帶var就是全局變量,擁有全局作用域;
  • 局部變量:函數(shù)內(nèi)部聲明并且以var修飾的變量就是局部變量,只能在函數(shù)體內(nèi)使用,函數(shù)的參數(shù)雖然沒有使用var但仍然是局部變量。

②注意:JavaScript并沒有塊級作用域,只有函數(shù)作用域:變量在聲明它們的函數(shù)體及其子函數(shù)內(nèi)是可見的。

③作用域鏈:
作用域鏈用來變量查詢的,在代碼執(zhí)行查找過程中,變量會在當前作用域中進行尋找,如果找不到,就會往沿著作用域鏈向上一級進行尋找,一直到全局作用域為止,如果找到便會停止(而不理會上一級是否有同名的變量),如果找不到,就會報錯。

④作用域只會逐層向上查找,遵循就近原則,只要查找到就停止了。


33.png

代碼:

1.以下代碼輸出什么?

44.png

2.寫一個函數(shù),返回參數(shù)的平方和?

//題目:寫一個函數(shù),返回參數(shù)的平方和
// function sumOfSquares(){
// }
// sumOfSquares(2,3,4);   // 29
// sumOfSquares(1,3);   // 10

--------
方法1:
function sumOfSquares(){
  var result = 0
  for(var i=0; i<arguments.length; i++){
    result += arguments[i]*arguments[i]
  }
  return result
}
console.log( sumOfSquares(2,3,4) );   // 29
console.log( sumOfSquares(1,3) );   // 10
-----------
方法2:
function sumOfSquares(){
  var result = 0
  for(var i=0; i<arguments.length; i++){
    result += arguments[i]*arguments[i]
  }
  console.log(result)
}
sumOfSquares(2,3,4);   // 29
sumOfSquares(1,3);   // 10

3.如下代碼的輸出?為什么

 console.log(a);//打印為undefined,定義了但未賦值
 var a = 1;
 console.log(b);//b is not defined,b沒有聲明,所以直接報錯

4.如下代碼的輸出?為什么

sayName('world'); 
sayAge(10); 
function sayName(name){ 
    console.log('hello ', name);
 }
 var sayAge = function(age){ 
    console.log(age); 
};
等同于
var sayAge  
function sayName(name){   //定義時不看函數(shù)體內(nèi)容
    console.log('hello ', name);
 }
sayName('world')      // 輸出:hello world
sayAge(10)      //輸出:sayAge is a not function ;相當于undefined(10),肯定會報錯
sayAge = function(age){ 
    console.log(age); 
};

5.如下代碼的輸出?為什么

function fn(){}
var fn = 3; 
console.log(fn);
等同于
var fn;          //變量的聲明前置
function fn(){}//聲明提升,函數(shù)聲明在變量的后面,函數(shù)覆蓋變量
fn = 3;       //變量的賦值覆蓋函數(shù)的聲明
console,log(fn)  //輸出3

6,如下代碼的輸出?為什么

function fn(fn2){ 
   console.log(fn2);   //函數(shù)fn2
   var fn2 = 3; 
   console.log(fn2);   //3
   console.log(fn);    //外層fn函數(shù)
   function fn2(){ 
        console.log('fnnn2');  
     } 
  } 
fn(10);

等同于
function fn(fn2){
    var fn2;
    //注意:傳參數(shù)時隱式做了 var fn2 = 10
    function fn2(){console.log('fnnn2')};  //函數(shù)聲明前置覆蓋了之前的變量
    console.log(fn2);// 輸出上面的fn2(){}函數(shù)
    fn2 = 3;
    console.log(fn2); //3
    console.log(fn); //輸出最外層的fn函數(shù),當前作用域(函數(shù)fn內(nèi)部)中沒有這個變量,因此向上一級尋找,找到變量fn被聲明為函數(shù)
}
fn(10)

分析:
1.當輸入 fn(10)的時候,把fn2 直接賦值成了數(shù)值10;
2.剛進入函數(shù)體內(nèi)部時,var fn2; 這時候 fn2還是等于10;
3.接著被賦值成數(shù)值的fn2,又被聲明回函數(shù);
4.這個時候console.log(fn2);,那就輸出函數(shù)fn2;
5.然后又被賦值成數(shù)值3;
6.遇到console.log(fn2);輸出3
7.然后遇到console.log(fn),輸出函數(shù) fn();

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)); //居然是報錯!is not a function 

第七題解析:因為當函數(shù)和變量聲明前置,函數(shù)的聲明覆蓋了變量的聲明,最后1賦值給fn,這時候fu類型不是function而是number,這時候console.log(fn(fn)) 轉(zhuǎn)換就變成console.log(1(1)) ,所以console.log(fn(fn)) 就報錯。顯示fn不是一個函數(shù)。
ps:請老師解析下,這題好懸,我是在控制臺打出才得知會報錯


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
-------
等同于
var i;
var j;
console.log(j);
console.log(i);
i=0;
for(i<10;i++){//只有函數(shù)才有作用域,for循環(huán)沒有作用域,所以里面的變量是全局變量
    j = 100
}
console.log(i)
console.log(j)
for循環(huán)后i跳出就變成10;循環(huán)10次后j被賦值了依然還是100,變量不會隨著循環(huán)的結(jié)束而消失

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(){  //函數(shù)聲明提升
    var i
    function fn2(){  //函數(shù)定義但未執(zhí)行
        i = 100
    }
    console.log(i)  //undefined
    i = 99
    fn2()
    console.log(i) //100 fn2函數(shù)運行后,本來全局的i=99被fn2的i=100覆蓋了
}
fn();  //然后執(zhí)行函數(shù)fn
i = 10; //全局 i 給再次賦值10
fn =20;
console.log(i)  // 10

10.如下代碼的輸出?為什么

var say = 0; 
(function say(n){
    console.log(n); 
    if(n<3) return;
    say(n-1); 
}( 10 ));
console.log(say);
------
等同于
var say;
(function say(n){ //立即執(zhí)行函數(shù)
    console.log(n); //輸出:10 9 8 7 6 5 4 3 2
    if(n<3) return;
    say(n-1); 
}( 10 ));
say = 0
console.log(say);//輸出:0
//變量只在函數(shù)作用域內(nèi)生效,并不會影響到外面的變量。所以最后console.log(say)輸出0

分析:
1.聲明var say = 0; 
2.立即執(zhí)行函數(shù)表達式不會提升的,按位置立即執(zhí)行;
3.進入函數(shù),實參10賦給形參n,n = 10,首先打出console.log(10) ;
4.判斷語句if n<3 return,不滿足條件,執(zhí)行say(n-1);繼續(xù)輸出n,一直遞歸下去 ;
5.直到n=2的時候,n<3此時返回,結(jié)束循環(huán),return為空值的時候,就是return出undefined,函數(shù)執(zhí)行完畢;
6.console.log(say)輸出0 ,因為立即執(zhí)行函數(shù)表達式就是創(chuàng)建一個獨立的作用域;這個作用域里面的變量,外面是訪問不到,所以打出全局定義的變量say;

本文版權(quán)歸區(qū)子銘和饑人谷所有,轉(zhuǎn)載請注明來源。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 函數(shù)聲明和函數(shù)表達式有什么區(qū)別 (*)解析器會率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可以訪問;函數(shù)表達式則必須...
    coolheadedY閱讀 446評論 0 1
  • 1. 函數(shù)聲明和函數(shù)表達式有什么區(qū)別 (*) 函數(shù)在JS中有三種方式來定義:函數(shù)聲明(function decla...
    進擊的阿群閱讀 483評論 0 1
  • 概念 1、函數(shù)聲明和函數(shù)表達式有什么區(qū)別? ECMAScript規(guī)定了三種聲明函數(shù)方式: 構(gòu)造函數(shù)首先函數(shù)也是對象...
    周花花啊閱讀 571評論 1 1
  • 函數(shù)聲明和函數(shù)表達式有什么區(qū)別? 函數(shù)聲明和函數(shù)表達式是EMACScript規(guī)定的兩種不同的聲明函數(shù)的方法。1.函...
    LeeoZz閱讀 442評論 0 1
  • 一、問答1、函數(shù)聲明和函數(shù)表達式有什么區(qū)別 ()函數(shù)聲明和函數(shù)表達式都是聲明函數(shù)的方法。函數(shù)聲明:function...
    崔敏嫣閱讀 407評論 0 0

友情鏈接更多精彩內(nèi)容