函數(shù)與作用域

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

  • 區(qū)別:
    用函數(shù)聲明創(chuàng)建的函數(shù)可以在定義之前就進(jìn)行調(diào)用例嘱;而用函數(shù)表達(dá)式創(chuàng)建的函數(shù)不能在被賦值之前進(jìn)行調(diào)用宁舰。
  • 原因
    函數(shù)聲明語(yǔ)句“被提前”到外部腳本或外部函數(shù)作用域的頂部,所以以這種方式聲明的函數(shù)蛮艰,可以被在它定義之前出現(xiàn)的代碼所調(diào)用。
    而要使用一個(gè)以表達(dá)式方式定義的函數(shù)之前即寡,必須把它賦值給一個(gè)變量袜刷。變量的聲明提前了,但給變量賦值是不會(huì)提前的著蟹,所以,以表達(dá)式方式定義的函數(shù)在定義之前無(wú)法調(diào)用奸披。

二涮雷、什么是變量的聲明前置?什么是函數(shù)的聲明前置洪鸭?

  • 變量聲明前置:
    javascript的變量聲明具有hoisting機(jī)制膜钓,JavaScript引擎在執(zhí)行的時(shí)候卿嘲,會(huì)把所有變量的聲明都提升到當(dāng)前作用域的最前面拾枣。

var a = 1;
function main() {
console.log(a);
var a = 2;
}
main()//輸出undefined
//解析如下

function main() {
    var a;
    console.log(a);
    a = 2;
}
main()
//所以輸出undefined```

* 函數(shù)的聲明前置
JavaScript的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)是始終可見(jiàn)的。這意味著變量可以先使用梅肤,后聲明。JavaScript的這一特性被非正式地稱為聲明提前(hoiosting)姨蝴,即JavaScript函數(shù)中所有變量的聲明都被“提前”至函數(shù)體的頂部。
>```
var scope = "global";
function f() {
   console.log(scope);//輸出underfined授帕,而不是"global"
   var scope = "local"; //變量在這里賦初始值浮梢,但變量在函數(shù)體內(nèi)任何地方均是有定義的。
   console.log(scope);//輸出"local"
}
//上述過(guò)程等價(jià)于:將函數(shù)內(nèi)的變量聲明提前至函數(shù)頂部秕硝,但變量初始化(賦值)還在原來(lái)的位置。
var scope = "global";
function f() {
   var scope奈偏;//在函數(shù)頂部聲明了局部變量
   console.log(scope);//變量存在躯护,但值是underfined
   scope = "local"; //初始化賦值
   console.log(scope);//
}```

三、arguments 是什么

標(biāo)識(shí)符arguments是指向?qū)崊?duì)象的引用唁盏,實(shí)參對(duì)象是一個(gè)類數(shù)組對(duì)象(不能修改它检眯,也不能用push來(lái)添加新元素等。但是可以訪問(wèn)其中的元素锰瘸,并且同時(shí)具有.length屬性)。
在函數(shù)代碼中舞萄,使用特殊對(duì)象 arguments管削,無(wú)需明確指出參數(shù)名,就能訪問(wèn)它們崎弃。
例如,在函數(shù) sayHi() 中饲做,第一個(gè)參數(shù)是 message。用 arguments[0] 也可以訪問(wèn)這個(gè)值塞弊,即第一個(gè)參數(shù)的值(第一個(gè)參數(shù)位于位置 0泪姨,第二個(gè)參數(shù)位于位置 1,依此類推)奏候。

四唇敞、函數(shù)的"重載"怎樣實(shí)現(xiàn)

所謂重載,是同一函數(shù)名疆柔,但是參數(shù)類型或參數(shù)個(gè)數(shù)不同的函數(shù)旷档。
Javascript不像其他編程語(yǔ)言一樣具有函數(shù)簽名(函數(shù)簽名,簡(jiǎn)單的說(shuō)就是函數(shù)的接收參數(shù)類型和參數(shù)個(gè)數(shù))。所以Javascript是不能像其他語(yǔ)言一樣實(shí)現(xiàn)方法名相同鞋屈,參數(shù)個(gè)數(shù)不同的這類重載的。
利用arguments渠啊,可以實(shí)現(xiàn)JavaScript的重載权旷。
>         function showMessage(){
            if(arguments.length==1){
                console.log(arguments[0]);
            }else if( arguments.length==2){
                console.log(arguments[0]+"說(shuō):"+arguments[1]);
            }else{
                return false;
            }
        }
       showMessage("Hi!");
       showMessage("張三","Hi 你妹");

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

立即執(zhí)行函數(shù)就是當(dāng)我們?cè)诙x了函數(shù)之后需要立即執(zhí)行的函數(shù)译柏。

( function(){…} ) ()
( function (){…} () )```
是兩種javascript立即執(zhí)行函數(shù)的常見(jiàn)寫(xiě)法。

  • 為什么這么寫(xiě):

首先怎静,要在函數(shù)體后面加括號(hào)就能立即調(diào)用,這個(gè)函數(shù)必須是函數(shù)表達(dá)式蚓聘,不能是函數(shù)聲明盟劫。
下面代碼:

function(){ /* code */ }(); // SyntaxError: Unexpected token```
報(bào)錯(cuò)了侣签,這是為何?這是因?yàn)樵趈avascript代碼解釋時(shí)影所,當(dāng)遇到function關(guān)鍵字時(shí),會(huì)默認(rèn)把它當(dāng)做是一個(gè)函數(shù)聲明阴幌,而不是函數(shù)表達(dá)式卷中,如果沒(méi)有把它顯視地表達(dá)成函數(shù)表達(dá)式,就報(bào)錯(cuò)了议忽,因?yàn)楹瘮?shù)聲明需要一個(gè)函數(shù)名十减,而上面的代碼中函數(shù)沒(méi)有函數(shù)名。(以上代碼帮辟,也正是在執(zhí)行到第一個(gè)左括號(hào)(時(shí)報(bào)錯(cuò),因?yàn)?前理論上是應(yīng)該有個(gè)函數(shù)名的壳繁。)
如果我們給它函數(shù)名荔棉,然后加上()立即調(diào)用,同樣也會(huì)報(bào)錯(cuò):

function foo(){ /* code */ }(); // SyntaxError: Unexpected token```
為什么會(huì)這樣渣触?在一個(gè)表達(dá)式后面加上括號(hào)壹若,表示該表達(dá)式立即執(zhí)行皂冰;而如果是在一個(gè)語(yǔ)句后面加上括號(hào)养篓,該括號(hào)完全和之前的語(yǔ)句不搭嘎,而只是一個(gè)分組操作符舶胀,用來(lái)控制運(yùn)算中的優(yōu)先級(jí)(小括號(hào)里的先運(yùn)算)碧注。所以以上代碼等價(jià)于:

function foo(){ /* code */ }
(); // SyntaxError: Unexpected token )```
相當(dāng)于先聲明了一個(gè)叫foo的函數(shù),之后進(jìn)行()內(nèi)的表達(dá)式運(yùn)算轩端,但是()(分組操作符)內(nèi)的表達(dá)式不能為空逝变,所以報(bào)錯(cuò)。

( function(){…} ) ()
( function (){…} () )```
為什么這樣就能立即執(zhí)行并且不報(bào)錯(cuò)呢骨田?因?yàn)樵趈avascript里态贤,括號(hào)內(nèi)部不能包含語(yǔ)句,當(dāng)解析器對(duì)代碼進(jìn)行解釋的時(shí)候悠汽,先碰到了(),然后碰到function關(guān)鍵字就會(huì)自動(dòng)將()里面的代碼識(shí)別為函數(shù)表達(dá)式而不是函數(shù)聲明茬高。

  • 作用:

1. 創(chuàng)建只使用一次的函數(shù)假抄,并立即執(zhí)行它。
 2. 創(chuàng)建閉包熏瞄,保存狀態(tài)谬以,隔離作用域。
 3. 作為獨(dú)立模塊存在(例子如jQuery)邮丰,防止命名沖突,命名空間注入(模塊解耦)剪廉。

六、求n!淮野,用遞歸來(lái)實(shí)現(xiàn)

function recursion(n) {
    if (n===1) {
        return 1;
    }else {
        return n * recursion(n-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('饑人谷', 2, '男');
/*輸出
name: 饑人谷
age: 2
sex: 男
['饑人谷',2,'男']
name valley
*/
getInfo('小谷', 3);
/*
name: 小谷
age: 3
sex: undefined
['小谷',3]
name valley
*/
getInfo('男');
/*
name: 男
age: undefined
sex: undefined
['男']
name valley
*/

八舆吮、寫(xiě)一個(gè)函數(shù),返回參數(shù)的平方和色冀?

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

九锋恬、如下代碼的輸出?為什么

console.log(a);
    var a = 1;
    console.log(b);
以上可重寫(xiě)為:
var a与学;//聲明前置
console.log(a);//輸出underfined
a = 1;
console.log(b);//ReferenceError: b is not defined

十、如下代碼的輸出晕窑?為什么

sayName('world');//輸出hello world卵佛,函數(shù)聲明前置
    sayAge(10);//ReferenceError: sayAge is not defined
    function sayName(name){
        console.log('hello ', name);
    }
    var sayAge = function(age){
        console.log(age);
    };

十一、如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼

var x = 10
bar() 
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}
//輸出10
/*
 1. globalContext = {
        AO: {
            x: 10
            foo: function
            bar: function
        }
        Scope: null
    }

    foo.[[Scope]] = globalContext.AO
    bar.[[Scope]] = globalContext.AO

 //調(diào)用 bar()
 2. barContext = {
        AO: {
            x: 30
        }
        Scope: globalContext.AO
    }
  
 //調(diào)用 foo() 
 3. fooContext = {
        AO: {}
        Scope: globalContext.AO
    }
*/

十二疾牲、如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(guò)程偽代碼

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}   
//輸出30
/*
1. globalContext = {
        AO: {
            x: 10
            bar: function
        }
        Scope: null
    }

    bar.[[Scope]] = globalContext.AO

 //調(diào)用 bar() 
 2. barContext = {
        AO: {
            x: 30
            foo: function
        },
        Scope: globalContext.AO
    }

    foo.[[Scope]] = barContext.AO
  
 //調(diào)用 foo() 
 3. fooContext = {
        AO: {}
        Scope: barContext.AO
    }
*/

十三说敏、以下代碼輸出什么? 寫(xiě)出作用域鏈的查找過(guò)程偽代碼

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}
//輸出30
 /*1.
    globalContext = {
        AO:{
            x:10
            bar:function
        }
        Scope: null
    }
    bar.[[scope]] = globalContext.AO
    2.調(diào)用bar()
    barContext = {
        AO:{
            x:30
            function
        }
        Scope:bar.[[scope]] = globalContext.AO
    }
    function.[[scope]] = barContext.AO
    3.調(diào)用立即執(zhí)行函數(shù)
    functionContext = {
        AO:{}
        Scope:function.[[scope]] = barContext.AO
    }
*/

十四丢郊、以下代碼輸出什么医咨? 寫(xiě)出作用域鏈查找過(guò)程偽代碼

var a = 1;

function fn(){
  console.log(a)
  var a = 5
  console.log(a)
  a++
  var a
  fn3()
  fn2()
  console.log(a)

  function fn2(){
    console.log(a)
    a = 20
  }
}

function fn3(){
  console.log(a)
  a = 200
}

fn()
console.log(a)
重寫(xiě)為:
var a;
function fn(){
  var a;           //3.聲明fn()的局部變量a
  var a;
  function fn2(){  //4.聲明fn2()
    console.log(a);//13.fn2()未定義變量a拟淮,尋找父級(jí)谴忧,輸出6
    a=20;          //14.把fn()的a賦值為20
  }
  console.log(a);  //5.未賦值輸出underfined
  a=5;             //6.為fn()的局部變量a賦值為5
  console.log(a);  //7.輸出5
a++;               //8.a=6
fn3()              //9.調(diào)用fn3()
fn2()              //12.調(diào)用fn2()
console.log(a)     //15.輸出20
}
function fn3(){
  console.log(a);  //10.fn3()的作用域未定義變量a,尋找父級(jí)沾谓,輸出1
  a=200            //11.將全局a賦值為200
}
a=1;              //1.全局變量a賦值為1
fn()              //2.調(diào)用fn()
console.log(a)    //16.輸出200
//輸出
undefined
5
1
6
20
200
/*
 1. globalContext = {
        AO: {
            a: 1 -> 200
            fn: function
            fn3: function
        },
        Scope: null
    }

    fn.[[Scope]] = globalContext.AO
    fn3.[[Scope]] = globalContext.AO

 //調(diào)用 fn() 
 2. fnContext = {
        AO: {
            a: undefined -> 5 -> 6 -> 20
            fn2: function
        }
        Scope: globalContext.AO
    }

    fn2.[[Scope]] = fnContext.AO
  
 //調(diào)用 fn3()
 3. fn3Context = {
        AO: {}
        Scope: globalContext.AO
    }
 //調(diào)用 fn2() 
 3. fn2Context = {
        AO: {}
        Scope: fnContext.AO
    }
*/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末均驶,一起剝皮案震驚了整個(gè)濱河市妇穴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腾它,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件曲梗,死亡現(xiàn)場(chǎng)離奇詭異逛腿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)碘举,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)搁廓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蝙场,你說(shuō)我怎么就攤上這事粱年。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)弊知。 經(jīng)常有香客問(wèn)我,道長(zhǎng)叔扼,這世上最難降的妖魔是什么漫雷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮食呻,結(jié)果婚禮上澎现,老公的妹妹穿的比我還像新娘每辟。我一直安慰自己,他們只是感情好渠欺,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布挠将。 她就那樣靜靜地躺著,像睡著了一般舔稀。 火紅的嫁衣襯著肌膚如雪内贮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天夜郁,我揣著相機(jī)與錄音,去河邊找鬼屎即。 笑死,一個(gè)胖子當(dāng)著我的面吹牛乘陪,可吹牛的內(nèi)容都是我干的虽另。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谣拣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼族展!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起仪缸,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恰画,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后拴还,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡端盆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年焕妙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弓摘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寺旺,死狀恐怖势决,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情果复,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布走搁,位于F島的核電站,受9級(jí)特大地震影響忌栅,放射性物質(zhì)發(fā)生泄漏曲稼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一瑞驱、第九天 我趴在偏房一處隱蔽的房頂上張望窄坦。 院中可真熱鬧唤反,春花似錦鸭津、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吴汪。三九已至,卻和暖如春杆融,著一層夾襖步出監(jiān)牢的瞬間霜运,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工藕各, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焦除,地道東北人激况。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓乌逐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浙踢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別? 函數(shù)聲明和函數(shù)表達(dá)式是EMACScript規(guī)定的兩種不同的聲明函數(shù)的方法奋岁。1.函...
    LeeoZz閱讀 350評(píng)論 0 1
  • 1闻伶,函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 1滨攻、背景介紹 定義函數(shù)的方法主要有三種: 1:函數(shù)聲明(Function De...
    進(jìn)擊的前端_風(fēng)笑影閱讀 443評(píng)論 0 0
  • 1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 函數(shù)聲明不必放在調(diào)用前面 函數(shù)表達(dá)式必須放在調(diào)用前面 2.什么是變量的聲明前置...
    LINPENGISTHEONE閱讀 298評(píng)論 0 0
  • JavaScript中的函數(shù)運(yùn)行在它們被定義的作用域里光绕,而不是它們被執(zhí)行的作用域里畜份。 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)...
    畢子歌閱讀 397評(píng)論 0 0
  • 1. 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 使用function關(guān)鍵字聲明一個(gè)函數(shù)時(shí)爆雹,聲明不必放到調(diào)用的前面。//函數(shù)聲...
    _李祺閱讀 275評(píng)論 0 0