js函數(shù)相關(guān)基礎(chǔ)知識(shí)問答

一、問答

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

函數(shù)聲明表示方法的例子:

function printName(){
 alert("shengming");
}
printName();

函數(shù)表達(dá)式的例子:

var printName=function(){
alert("biaodashi");
}

那么他們之間有什么區(qū)別呢?看下面的例子

console.log( shengMing );
console.log( biaodashi );
function shengMing(){
 alert("shengming")
};
var biaodashi=function biaoDaShi(){
 alert("biaodashi")
};
console.log( shengMing );
console.log( biaodashi );

運(yùn)行后:

Paste_Image.png

由以上可以看出,即使聲明函數(shù)shengMing()是在后面聲明的,但在前面也可調(diào)用(第一個(gè)console.log( shengMing );能夠正常運(yùn)行),但是表達(dá)函數(shù)則不行(第一個(gè)console.log( biaodashi ); 運(yùn)行結(jié)果顯示undefined);對(duì)于函數(shù)聲明語句,函數(shù)名稱和函數(shù)體均提前聲明了,可以在聲明之前調(diào)用它;但對(duì)于函數(shù)表達(dá)式,只有函數(shù)變量聲明提前了,但是函數(shù)的初始化代碼仍然在原來的位置;

(二)什么是變量的聲明前置?什么是函數(shù)的聲明前置?
  • 變量的聲明前置,是指即使我們沒有在使用變量前先聲明這個(gè)變量,但是由于變量提升(即變量聲明的前置)的存在,我們可以在聲明前使用該變量,只不過這個(gè)變量的默認(rèn)值是undefined,但解析器不會(huì)報(bào)錯(cuò);例如:
Paste_Image.png
  • 同理,對(duì)于函數(shù)也存在函數(shù)的聲明前置的情況,其實(shí)第一題就說明了這一點(diǎn),下面再舉個(gè)例子:
Paste_Image.png

當(dāng)然對(duì)于表達(dá)式函數(shù)也適用,例如下面的例子:

Paste_Image.png
(三)arguments 是什么 ?

arguments 是一個(gè)類數(shù)組對(duì)象。代表傳給一個(gè)function的參數(shù)列表。
可以在函數(shù)內(nèi)部通過使用 arguments 對(duì)象來獲取函數(shù)的所有參數(shù)。這個(gè)對(duì)象為傳遞給函數(shù)的每個(gè)參數(shù)建立一個(gè)條目,條目的索引號(hào)從 0 開始。arguments 對(duì)象并不是一個(gè)真正的Array。它類似于數(shù)組,但沒有數(shù)組所特有的屬性和方法,除了 length。例如,它沒有 pop 方法。不過可以將其轉(zhuǎn)換成數(shù)組。另外:arguments 對(duì)象僅在函數(shù)內(nèi)部有效,在函數(shù)外部調(diào)用 arguments 對(duì)象會(huì)出現(xiàn)一個(gè)錯(cuò)誤。如果你調(diào)用一個(gè)函數(shù),當(dāng)這個(gè)函數(shù)的參數(shù)數(shù)量比它顯式聲明的參數(shù)數(shù)量更多的時(shí)候,你就可以使用 arguments 對(duì)象。這個(gè)技術(shù)對(duì)于參數(shù)數(shù)量是一個(gè)可變量的函數(shù)來說比較有用。 你可以用 arguments.length 來得到參數(shù)的數(shù)量,然后可以用 arguments object 來對(duì)每個(gè)參數(shù)進(jìn)行處理。 (想要得到當(dāng)一個(gè)函數(shù)定義時(shí)的該函數(shù)的參數(shù)數(shù)量, 請使用 Function.length 屬性。)

arguments的屬性如下:
arguments.callee
指向當(dāng)前執(zhí)行的函數(shù)。
arguments.caller
指向調(diào)用當(dāng)前函數(shù)的函數(shù)。
arguments.length
指向傳遞給當(dāng)前函數(shù)的參數(shù)數(shù)量。

  • 下面舉個(gè)使用arguments的例子:
Paste_Image.png

在聲明上述函數(shù)時(shí)未使用參數(shù),即其不包含命名的參數(shù),這說明在函數(shù)中命名的參數(shù)只提供便利,但不是必須的。

  • 下面再舉個(gè)使用arguments.length的例子:
Paste_Image.png
(四)函數(shù)的重載怎樣實(shí)現(xiàn) ?

由于js不能像傳統(tǒng)意義上那樣實(shí)現(xiàn)重載,因此我們可以通過使用arguments的方法實(shí)現(xiàn)非完美的重載;

如下面的例子:

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

類似于

Paste_Image.png

類似于上述函數(shù)的寫法叫做「立即執(zhí)行函數(shù)」也叫「自執(zhí)行匿名函數(shù)」(self-executing anonymous function);「立即執(zhí)行函數(shù)表達(dá)式」(Immediately-Invoked Function Expression,簡稱IIFE);
其中一般推薦使用第一種寫法,但是目前很多比較好的js library 使用的都是第二種方式。 比如: web 圖形繪制的: git , draw2d ,....

(六)什么是函數(shù)的作用域鏈?

函數(shù)對(duì)象和其他對(duì)象一樣,擁有可以通過代碼訪問的屬性和一系列供js引擎訪問的內(nèi)部屬性,其中一個(gè)內(nèi)部屬性是[scope],該屬性包括了函數(shù)被創(chuàng)建的作用域中的對(duì)象集合,這個(gè)集合稱為函數(shù)的作用域鏈,它決定了哪些能夠被函數(shù)訪問;

舉個(gè)例子:

Paste_Image.png

二、代碼

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);
    getInfo('男');

運(yùn)行結(jié)果會(huì)如下:

    /*  getInfo('hunger', 28, '男')運(yùn)行結(jié)果:

        name:hunger
        age:28
        sxe:男
        {valley, 28, 男}
        name valley
 
    */


    /*   getInfo('hunger', 28)運(yùn)行結(jié)果:

        name:hunger
        age:28
        sxe:undefind
        {valley,28}
        name valley


    */

    /*   getInfo('男')運(yùn)行結(jié)果:

        name:男
        age:undefind
        sxe:undefind
        {valley}
        name valley


    */
Paste_Image.png
2.寫一個(gè)函數(shù),返回參數(shù)的平方和?如
   function sumOfSquares(){
   }
   sumOfSquares(2,3,4);   // 29
   sumOfSquares(1,3);   // 10
function sumOfSquares(){
        for (var i = 0,x = 0; i < arguments.length; i++) {
            x=x+arguments[i]*arguments[i];          
         }
        console.log(x);
    }
Paste_Image.png
3.如下代碼的輸出?為什么 ?
    console.log(a);
    var a = 1;
    console.log(b);

上述代碼相當(dāng)于:

    var a;
    console.log(a);
    a = 1;
    console.log(b);

輸出為 undefined;b is not defined; 由于變量提升的存在,導(dǎo)致console.log(a)時(shí),不會(huì)出現(xiàn)a is not defined,但是由于console.log(a)之前a未賦值,所以才會(huì)導(dǎo)致出現(xiàn) undefined; 而對(duì)于console.log(b)語句,由于b既未聲明也未賦值,所以才會(huì)報(bào)錯(cuò)b is not defined錯(cuò)誤;

Paste_Image.png
4.如下代碼的輸出?為什么 ?
    sayName('world'); //hello world (解釋:該函數(shù)為聲明函數(shù),存在提前聲明的情況;)
    sayAge(10);/*sayAge is not a function (解釋:該函數(shù)為表達(dá)式函數(shù),
不存在提前聲明的情況,所以會(huì)報(bào)錯(cuò))*/
    function sayName(name){
        console.log('hello ', name);
    }
    var sayAge = function(age){
        console.log(age);
    };

上述代碼相當(dāng)于:

var sayAge;
    function sayName(name){
        console.log('hello ', name);
    }
    sayName('world');
    sayAge(10);// sayAge is not a function 
 sayAge = function(age){
        console.log(age);
    };
Paste_Image.png
5.如下代碼的輸出?為什么 ?
    function fn(){}
    var fn = 3;
    console.log(fn);//3

上述代碼相當(dāng)于:

     var fn; //fn 此時(shí)為普通變量
    function fn(){}    //fn此時(shí)為函數(shù)名
    fn = 3;  /*fn此時(shí)值等于3,因?yàn)樵谕粋€(gè)作用域內(nèi)定義了名字相同的變量和方法的話,無論其順序如
何,變量的賦值會(huì)覆蓋方法的賦值;*/
    console.log(fn); //打印時(shí)輸出3
Paste_Image.png
6.如下代碼的輸出?為什么 ?
    function fn(fn2){
       console.log(fn2);
       var fn2 = 3;
       console.log(fn2);
       console.log(fn);
       function fn2(){
            console.log('fnnn2');
        }
     }
    fn(10);

上述代碼相當(dāng)于:

    function fn(fn2){
       var fn2;
       function fn2(){
            console.log('fnnn2');
        }
       console.log(fn2);   //
/* 由于同個(gè)作用域下,變量聲明和函數(shù)聲明存在命名沖突時(shí),變量聲明前置要比函數(shù)聲明前置的優(yōu)先級(jí)底,因此此時(shí)打印出的是函數(shù)*/
       fn2 = 3;
       console.log(fn2); //3   
   /*此時(shí)fn2被賦值3了,因?yàn)樵谕粋€(gè)作用域中,定義了同一個(gè)名字的變量
和方法時(shí),無論順序如何,變量的賦值會(huì)覆蓋方法的賦值*/
       console.log(fn); //  此時(shí)會(huì)打印函數(shù)fn本身 

     }
    fn(10);

因此結(jié)果為

Paste_Image.png

如果將此題改成下面的代碼,結(jié)果將是怎樣的呢?

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

       console.log(fn2);
       var fn2 = 3;
       console.log(fn2);

     }
    fn(10);

其實(shí)上面的代碼相當(dāng)于

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

       console.log(fn2); //200 此時(shí)并沒有輸出函數(shù)fn2,為什么呢?
/*因?yàn)橥粋€(gè)作用域中,定義了名字相同的變量和方法的話,無論順序如何
變量的賦值會(huì)覆蓋方法的賦值;
*/
       var fn2 = 3;
       console.log(fn2); //3

     }
    fn(10);

輸出結(jié)果:

Paste_Image.png

如果再將代碼改成:

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

       console.log(fn2);
        fn2 = 3;
       console.log(fn2);

     }
    fn(10);
    console.log(fn2); //此處會(huì)報(bào)錯(cuò),因?yàn)橛捎诤瘮?shù)作用域的存在,此處的fn2并未定義變量且賦值;

則結(jié)果為

Paste_Image.png
7.如下代碼的輸出?為什么?
    var fn = 1;
    function fn(fn){
         console.log(fn); 
    }
    console.log(fn(fn)); 

上述代碼相對(duì)于

    var fn ;
    
    function fn(fn){
         console.log(fn); 
    };
    fn = 1;
    console.log(fn(fn)); //報(bào)錯(cuò) fn  is not a function
/* 由于同一個(gè)作用域中,定義同一個(gè)名字的變量和方法時(shí),變量賦值會(huì)覆蓋方法的賦值,因此此時(shí)解析器
并不能夠識(shí)別fn為函數(shù),但是在打印時(shí)又以函數(shù)的方式打印,因此會(huì)報(bào)錯(cuò)*/

其實(shí)上面的例子可簡化成這樣的理解

Paste_Image.png

打印a(a) ,解析器會(huì)把它當(dāng)作成要打印一個(gè)函數(shù),但是a并不是一個(gè)函數(shù),因此會(huì)報(bào)錯(cuò)。

8.如下代碼的輸出?為什么 ?
    //作用域
    console.log(j); 
    console.log(i); 
    for(var i=0; i<10; i++){
        var j = 100;
    }
    console.log(i); 
    console.log(j); 

其實(shí)上面的代碼相當(dāng)于

   var j ;
   var i ;
    console.log(j);  // undefined 
/*解釋:由于變量提升的存在,導(dǎo)致此處提示j未被賦值,但不抱錯(cuò)*/
    console.log(i); //undefined 
/*解釋:同理,由于變量提升的存在,
導(dǎo)致此處提示i未被賦值,但不抱錯(cuò)*/
    for(var i=0; i<10; i++){
        var j = 100;
    }
    console.log(i); //10 (解釋:for語句執(zhí)行完后,i值為10)
    console.log(j); // 100 (解釋:for語句執(zhí)行完后,j值為100)
Paste_Image.png
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;
        }
    }

上述代碼相當(dāng)于:

    var i;
    var fn;
    function fn(){
        var i;
        function fn2(){
            i = 100;
        }
        console.log(i);  //undefinded
/*此時(shí)i并未被賦值,因此為undefinded*/
        var i = 99;
        fn2(); //執(zhí)行后i為100;
        console.log(i);  //100
/*此時(shí)打印i,i的值為100*/

    }

    fn();
    var i = 10;
    var fn = 20;
    console.log(i); //10 
/*雖然i在function內(nèi)部為100但由于函數(shù)作用域的存在及i的外部賦值,在外部的為10;*/

Paste_Image.png
10.如下代碼的輸出?為什么?
    var say = 0;
    (function say(n){ 
        console.log(n);

        if(n<3) return; 
        say(n-1);
    }( 10 )); //輸出 10,9,8,7,6,5,4,3,2
/*該函數(shù)為立即執(zhí)行函數(shù),因此會(huì)馬上執(zhí)行,當(dāng)n為2時(shí),因?yàn)?<3,因此會(huì)立即跳出該函數(shù)*/
    console.log(say); //輸出0  
/*因?yàn)樵谠撟饔糜蛑?,變量say已經(jīng)被賦值了0,在同一個(gè)作用域中,變量和方法同名時(shí),無論順序如何,
變量的賦值會(huì)覆蓋方法的賦值,更何況say()為立即執(zhí)行函數(shù);
*/
Paste_Image.png

如果將題中代碼改成

    var say = 0;
    var n=10086;
    function say(n){ 
        console.log(n); 
        if(n<3) return; 
        say(n-1);
    };
    console.log(say(n)); 
    console.log(say(n));   /*此時(shí)解析器以為要執(zhí)行say(n)函數(shù),但由于同一個(gè)作用域下,若存在同
名的變量和方法,變量的賦值會(huì)覆蓋方法的賦值,因此say還是被看成值為0的變量,而say(n)又不是一個(gè)函
數(shù),因此會(huì)報(bào)錯(cuò)說say不是一個(gè)函數(shù)
*/

上述代碼執(zhí)行后將會(huì)報(bào)錯(cuò)。

Paste_Image.png

補(bǔ)充:作用域鏈相關(guān)資料

**本文版權(quán)歸本人即簡書筆名:該賬戶已被查封 所有,如需轉(zhuǎn)載請注明出處。謝謝! *

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

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

  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,692評(píng)論 0 4
  • 第 2 章:函數(shù)基礎(chǔ) 函數(shù)式編程不是僅僅用 function 這個(gè)關(guān)鍵詞來編程。如果真這么簡單,那我這本書可以到此...
    iKcamp閱讀 1,025評(píng)論 0 7
  • 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*)解析器會(huì)率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可以訪問;函數(shù)表達(dá)式則必須...
    coolheadedY閱讀 458評(píng)論 0 1
  • 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大獎(jiǎng):點(diǎn)擊這里領(lǐng)取 函...
    HetfieldJoe閱讀 1,637評(píng)論 2 12
  • 時(shí)間不停的轉(zhuǎn)動(dòng),帶走了當(dāng)初的天真,帶走了當(dāng)初的幻想。當(dāng)初的堅(jiān)貞不渝,當(dāng)初的誓死不離,都已成為過眼云煙。 那個(gè)敢愛敢...
    執(zhí)著等待閱讀 198評(píng)論 0 0

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