函數(shù)

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

函數(shù)聲明和函數(shù)表達(dá)式都可以創(chuàng)建函數(shù)。
函數(shù)聲明寫法:
function 函數(shù)名稱 (參數(shù):可選) {函數(shù)體 }
舉例:
function foo() {}
函數(shù)表達(dá)式寫法:
var 變量 = function 函數(shù)名稱(可選) (參數(shù):可選) {函數(shù)體 }
舉例:
var foo=function(){};
這種寫法將一個(gè)匿名函數(shù)賦值給變量。這時(shí),這個(gè)匿名函數(shù)又稱函數(shù)表達(dá)式(Function Expression),因?yàn)橘x值語句的等號右側(cè)只能放表達(dá)式。
采用函數(shù)表達(dá)式聲明函數(shù)時(shí),function命令后面不帶有函數(shù)名。如果加上函數(shù)名,該函數(shù)名只在函數(shù)體內(nèi)部有效,在函數(shù)體外部無效。


二者區(qū)別主要在于,函數(shù)聲明有聲明提前的特點(diǎn),函數(shù)聲明會被提到被提升到作用域的最前面,即使寫代碼的時(shí)候是寫在最后面,也還是會被提升至最前面。
舉例:

這段代碼的實(shí)際執(zhí)行順序是:

var btn;
function fo(){}
console.log(fo);
console.log(btn);
btn=function(){};

所以輸出結(jié)果,是function fo(){} undefined。

結(jié)果示例

參考函數(shù)聲明 VS 函數(shù)表達(dá)式

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

變量的聲明前置,把所有變量聲明放到代碼的頭部。
函數(shù)的聲明前置是把函數(shù)聲明放到代碼的頭部。如果我們使用函數(shù)聲明的方式,那么即使函數(shù)寫在最后也可以在前面語句調(diào)用,前提是函數(shù)聲明部分已經(jīng)被下載到本地。
舉例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>聲明提前</title>
</head>
<body>
  <script>
   console.log(a);
   function fn(){
    console.log(b);
    console.log(foo);
    var b=4;
    function foo(){}
   }
   var a = 9;
   fn();
  </script>
</body>
</html>

結(jié)果:



這就是變量的聲明前置和函數(shù)的聲明前置的結(jié)果。

3.arguments 是什么 (*)

arguments 是一個(gè)類數(shù)組對象。代表傳給一個(gè)function的參數(shù)列表。arguments 對象是函數(shù)內(nèi)部的本地變量;arguments 已經(jīng)不再是函數(shù)的屬性了。
在函數(shù)內(nèi)部可以用arguments對象來獲取函數(shù)的所有參數(shù)。而且arguments對象僅在函數(shù)內(nèi)部有效,在函數(shù)外部調(diào)用 arguments 對象會出現(xiàn)一個(gè)錯(cuò)誤。
它的作用有:
1.無須明確指出參數(shù)名,可以訪問函數(shù)。



2.無需明確命名參數(shù),就可以重寫函數(shù)。



可以看到name的值被改變了。
3.可以用 arguments 對象檢測函數(shù)的參數(shù)個(gè)數(shù),引用屬性 arguments.length 即可。

可以看到實(shí)際函數(shù)調(diào)用了幾個(gè)參數(shù),arguments.length就等于幾。
4.用arguments 對象判斷傳遞給函數(shù)的參數(shù)個(gè)數(shù),可以模擬函數(shù)重載。

當(dāng)只有一個(gè)參數(shù)時(shí),doAdd() 函數(shù)給參數(shù)加 5。如果有兩個(gè)參數(shù),則會把兩個(gè)參數(shù)相加,返回它們的和。所以,doAdd(10) 輸出的是 "15",而 doAdd(40, 20) 輸出的是 "60"。雖然不如重載那么好,不過已足以避開 ECMAScript 的這種限制。

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

從語言角度來說,javascript不支持函數(shù)重載,先定義的函數(shù)會被后定義的函數(shù)覆蓋。不能夠定義同樣的函數(shù)然后通過編譯器去根據(jù)不同的參數(shù)執(zhí)行不同的函數(shù)。但是javascript卻可以通過自身屬性去模擬函數(shù)重載。如上題中介紹的arguments的第四個(gè)特性,就可以模擬函數(shù)重載。

參考 js函數(shù)重載

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

在Javascript中,一對圓括號()是一種運(yùn)算符,跟在函數(shù)名之后,表示調(diào)用該函數(shù)。比如,foo()就表示調(diào)用foo函數(shù)。
所以我們也可以在函數(shù)聲明后加上(),表示立即執(zhí)行函數(shù)。但是不能直接加括號,function(){}();會引起語法錯(cuò)誤。這是因?yàn)?,JavaScript引擎規(guī)定,如果function關(guān)鍵字出現(xiàn)在行首,一律解釋成語句。因此,JavaScript引擎看到行首是function關(guān)鍵字之后,認(rèn)為這一段都是函數(shù)的定義,不應(yīng)該以圓括號結(jié)尾,所以就報(bào)錯(cuò)了。
立即執(zhí)行函數(shù)可以寫成下面的形式:

(function(){ /*code */ }());

或者

(function(){/*code*/})();

上面兩種寫法都是以圓括號開頭,引擎就會認(rèn)為后面跟的是一個(gè)表示式,而不是函數(shù)定義語句,所以就避免了錯(cuò)誤。這就叫做“立即調(diào)用的函數(shù)表達(dá)式”(Immediately-Invoked Function Expression),簡稱IIFE。
它的目的有兩個(gè):
一是不必為函數(shù)命名,避免了污染全局變量;
二是IIFE內(nèi)部形成了一個(gè)單獨(dú)的作用域,可以封裝一些外部無法讀取的私有變量。

// 寫法一
var tmp =newData;
processData(tmp);
storeData(tmp);
// 寫法二
(function (){ 
var tmp = newData; 
processData(tmp); 
storeData(tmp);}());

上面代碼中,寫法二比寫法一更好,因?yàn)橥耆苊饬宋廴救肿兞俊?/p>

參考5.2立即調(diào)用的函數(shù)表達(dá)式(IIFE)

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

  • 函數(shù)作用域就是函數(shù)的可訪問范圍,簡單的說,一個(gè)function從{開始,到}結(jié)束,是這個(gè)函數(shù)的作用域。不同的函數(shù)有不同的作用域。作用域中聲明的變量無法被作用域外部所訪問。但是作用域中可以訪問上級作用域中的變量。
  • 作用域鏈正是內(nèi)部上下文所有變量對象(包括父變量對象)的列表,用來變量查詢。在代碼執(zhí)行的過程中,所用到的變量會在當(dāng)前作用域中進(jìn)行尋找,如果找不到,就會往沿著作用域鏈向上一級進(jìn)行尋找,一直到全局作用域?yàn)橹梗绻业奖銜V梗ǘ焕頃弦患壥欠裼型淖兞浚?,如果找不到,就會?bào)錯(cuò)。

1.參考JavaScript 開發(fā)進(jìn)階:理解 JavaScript 作用域和作用域鏈
2.參考深入理解JavaScript系列(14):作用域鏈(Scope Chain)

代碼題

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*/

結(jié)果:

2.寫一個(gè)函數(shù),返回參數(shù)的平方和?如 (難度**)

 function sumOfSquares(){
 } 
sumOfSquares(2,3,4); // 29 
sumOfSquares(1,3); // 10

代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>函數(shù)平方和</title>
</head>
<body>
<script>
       function sumOfSquares(){
        var s=0;
        for(var i=0;i<arguments.length;i++){
            s= arguments[i]*arguments[i]+s;
        }
        alert(s);
   }
   sumOfSquares(2,3,4);   
   sumOfSquares(1,3);  
</script>
</body>
</html>

預(yù)覽

3.如下代碼的輸出?為什么 (難度*)

console.log(a);//undefined
    var a = 1;
    console.log(b);//not defined

結(jié)果:



因?yàn)樽兞刻嵘?,把對a的聲明提到前面,但是并沒有定義a,所以輸出undefined。而b則未被聲明,輸出錯(cuò)誤。

4.如下代碼的輸出?為什么 (難度*)

 sayName('world');//hello world
    sayAge(10); //not a function
    function sayName(name){
        console.log('hello ', name);
    }
    var sayAge = function(age){
        console.log(age);
    };

結(jié)果:


函數(shù)聲明提前到代碼最前面,調(diào)用函數(shù)sayName。而var sayAge = function(age){console.log(age);};定義了函數(shù)表達(dá)式,sayAge是一個(gè)變量,調(diào)用sayAge(10)會出錯(cuò)。

5.如下代碼的輸出?為什么 (難度**)

  function fn(){}
    var fn = 3;
    console.log(fn);//3

結(jié)果:



當(dāng)在同一個(gè)作用域內(nèi)定義了名字相同的變量和方法的話,無論其順序如何,變量的賦值會覆蓋方法的賦值。

6.如下代碼的輸出?為什么 (難度***)

 function fn(fn2){
    var fn2
    function fn2(){
            console.log('fnnn2');
        }
       console.log(fn2);
       var fn2 = 3;
       console.log(fn2);
       console.log(fn);
       
     }
    fn(10);

結(jié)果:



執(zhí)行順序:

function fn(fn2){
         var fn2;
         function fn2(){
            console.log('fnnn2');
        }
       console.log(fn2);/*function fn2(){
            console.log('fnnn2');
        }*/
       fn2 = 3;
       console.log(fn2);//3
       console.log(fn);
     }
    fn(10);

調(diào)用函數(shù),才會執(zhí)行函數(shù)中的內(nèi)容。console.log(fn);調(diào)用上級函數(shù)。

7.如下代碼的輸出?為什么 (難度***)

 var fn = 1;
    function fn(fn){
         console.log(fn);
    }
    console.log(fn(fn)); //not a function

結(jié)果:



執(zhí)行順序:

 var fn;
 function fn(fn){
         console.log(fn);
    }
 fn = 1; 
  console.log(fn(fn)); 

fn被賦值為1,是一個(gè)數(shù)字不是函數(shù),出錯(cuò)。

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

結(jié)果:



for循環(huán)把i增加到10,j的值被設(shè)置為100。這兩個(gè)都是全局變量。
類似于:

 console.log(j);
    console.log(i);
    var i=10;
   var j=100;
    console.log(i);
    console.log(j);

輸出結(jié)果如上圖示。

9.如下代碼的輸出?為什么 (難度****)

 fn();//undefined 100
    var i = 10;
    var fn = 20;
    console.log(i);//10
    function fn(){
        console.log(i);//undefined
        var i = 99;
        fn2();
        console.log(i);//100
        function fn2(){
            i = 100;
        }
    }

結(jié)果:



根據(jù)變量的聲明提升和函數(shù)的聲明提升,可以把上面的代碼寫成:

 var i;
 var fn;
  function fn(){
      var i;
      function fn2(){
            i = 100;
        }//并沒有被調(diào)用,沒有運(yùn)行。
       console.log(i);//undefined
        i = 99;
        fn2();//i=100,i是全局變量
        console.log(i);//100
    }
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);//10 9 8 7 6 5 4 3 2 0

結(jié)果:


(function say(n){
        console.log(n);
        if(n<3) return;
        say(n-1);
    }( 10 ));

是立即執(zhí)行函數(shù),這個(gè)函數(shù)是對n從10依次遞減,直到n<3,即n的值是2時(shí),停止執(zhí)行這個(gè)函數(shù)。得到數(shù)字10 9 8 7 6 5 4 3 2。而say又被賦值為0,最后輸出0。

本文版權(quán)歸本人和饑人谷所有,轉(zhuǎn)載請注明出處

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

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

  • 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*)解析器會率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可以訪問;函數(shù)表達(dá)式則必須...
    coolheadedY閱讀 454評論 0 1
  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,712評論 0 1
  • 1.函數(shù)參數(shù)的默認(rèn)值 (1).基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。
    趙然228閱讀 847評論 0 0
  • 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大獎(jiǎng):點(diǎn)擊這里領(lǐng)取 函...
    HetfieldJoe閱讀 1,637評論 2 12
  • 豫夏周天,鳥雀無言,浪暖熱潮。看校園南北,枝椏枯敗,眉湖兩岸,人影匿銷。河涌溫湯,氣襲燃焰,如此中原似火燒。風(fēng)吹過...
    有故事的許同學(xué)閱讀 411評論 6 5

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