JS-函數(shù)和作用域

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

函數(shù)聲明和函數(shù)表達(dá)式是聲明函數(shù)的兩種不同的方式,形式如下:

  • 函數(shù)聲明:即使用function關(guān)鍵字聲明一個(gè)函數(shù)
 //函數(shù)聲明
 function sayHello(){
   console.log('hello')
 }

 //函數(shù)調(diào)用
 sayHello()

聲明不必放到調(diào)用的前面,函數(shù)調(diào)用可以發(fā)生在函數(shù)聲明之前,例如下面這種情況下不會(huì)報(bào)錯(cuò)

  printName();//輸出console.log('1')
  function printName(){
    console.log('1');
  }
  //正常,因?yàn)樘嵘撕瘮?shù)聲明,函數(shù)調(diào)用可在函數(shù)聲明之前

即在一個(gè)作用域下,var 聲明的變量和function 聲明的函數(shù)會(huì)前置

  • 函數(shù)表達(dá)式
  var sayHello = function(){
    console.log('hello');
  }

  sayHello()

聲明必須放到調(diào)用的前面,例如

  printName();//瀏覽器提示Uncaught TypeError: printName is not a function(…)
  var printName = function(){
  console.log('1');
    };
  //報(bào)錯(cuò),函數(shù)表達(dá)式和 var 一個(gè)變量沒(méi)什么區(qū)別,變量printName還未保存對(duì)函數(shù)的引用,函數(shù)調(diào)用必須在函數(shù)表達(dá)式之后

瀏覽器提示Uncaught TypeError: printName is not a function(…).原因:類似變量提升,函數(shù)作為一個(gè)變量賦值給printName,等價(jià)于

  var printName;    //此時(shí)printName為undefined
  printName();
  printName = function(){
    console.log('1');
  };
  • 因此,函數(shù)聲明和函數(shù)表達(dá)式不同之處在于:
    • Javascript引擎在解析javascript代碼時(shí)會(huì)‘函數(shù)聲明提升’(Function declaration Hoisting)當(dāng)前執(zhí)行環(huán)境(作用域)上的函數(shù)聲明,而函數(shù)表達(dá)式必須等到Javascirtp引擎執(zhí)行到它所在行時(shí),才會(huì)從上而下一行一行地解析函數(shù)表達(dá)式,
    • 函數(shù)聲明后面可以加括號(hào)立即調(diào)用該函數(shù),函數(shù)表達(dá)式不可以,只能以fnName()形式調(diào)用

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

  • 變量聲明前置
    • JavaScript引擎的工作方式是,先解析代碼,獲取所有被聲明的變量,然后再一行一行地運(yùn)行。這造成的結(jié)果,就是所有的變量的聲明語(yǔ)句,都會(huì)被提升到當(dāng)前作用域的頭部,這就叫做變量的聲明前置,也叫變量提升(hoisting)。
  • 函數(shù)聲明前置
    • JavaScript引擎將函數(shù)名視同變量名,所以采用function命令聲明函數(shù)時(shí),函數(shù)聲明會(huì)像變量聲明一樣,被提升到代碼頭部。因此,函數(shù)的調(diào)用可以寫在聲明前面,函數(shù)可以被執(zhí)行。(注意:如下函數(shù)表達(dá)式,變量fn還未保存對(duì)函數(shù)的引用,函數(shù)調(diào)用必須在函數(shù)表達(dá)式之后)。
      console.log(fn); //undefined
      fn(); //瀏覽器提示Uncaught TypeError: fn is not a function(…)
    
      var fn = function(){}
      //報(bào)錯(cuò),變量fn還未保存對(duì)函數(shù)的引用,函數(shù)調(diào)用必須在函數(shù)表達(dá)式之后
    

3.arguments 是什么

  • arguments是一個(gè)類數(shù)組對(duì)象,類似數(shù)組的方式,可以通過(guò)下標(biāo)的方式去獲取值,但它本身不是數(shù)組,沒(méi)有數(shù)組的一些特性,所以叫類數(shù)組對(duì)象。在函數(shù)內(nèi)部,可以使用arguments對(duì)象獲取到該函數(shù)的所有傳入?yún)?shù)。

    • 例如如下函數(shù)
      function printPersonInfo(name, age, sex){
        console.log(name);
        console.log(age);
        console.log(sex);
        console.log(arguments);
      }
    
    • 執(zhí)行printPersonInfo('liu', 21, 'boy')后,輸出:
      name : liu
      age : 22
      sex : boy
      ["liu", 22, "boy"]
    
    • 執(zhí)行printPersonInfo('liu', 21,)后,輸出:
      name : liu
      age : boy
      sex : undefined
      ["liu", "boy"]
    

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

  • 重載是指不同的函數(shù)使用相同的函數(shù)名,但是函數(shù)的參數(shù)個(gè)數(shù)或類型不同。調(diào)用的時(shí)候根據(jù)函數(shù)的參數(shù)來(lái)區(qū)別不同的函數(shù)。
  • JS并不像其他強(qiáng)類型語(yǔ)言一樣可以聲明重載函數(shù),若在原先聲明的函數(shù)后再聲明一個(gè)不同參數(shù)數(shù)量的函數(shù)(JS是弱語(yǔ)言,聲明的函數(shù)不需要指明參數(shù)類型),解析器會(huì)用后面聲明的函數(shù)覆蓋前面聲明的函數(shù)。

JS種沒(méi)有重載! 同名函數(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);
  printPeopleInfo('Byron', 26, 'male');

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

  (function(){ var a=1; })();
  (function(){ var a=1; }());  
  • 作用:

    • 作用:隔離作用域。
  • 參考

6.遞歸

  • 遞歸實(shí)現(xiàn)一個(gè)函數(shù),計(jì)算 n!
  function factor(n) {
    if(n===1){
      return n
    }
    return n*factor(n-1)
  }

幾個(gè)代碼小題目

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, '男');
  getInfo('小谷', 3);
  getInfo('男');
  • 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

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

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

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

  console.log(a);//undefined
  var a = 1;
  console.log(b);//報(bào)錯(cuò)Uncaught ReferenceError: b is not defined(…)

a輸出undefined是因?yàn)樽兞刻嵘?b沒(méi)有定義,類似如下代碼

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

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

  sayName('world');   //輸出 'hello ', 'world' 使用函數(shù)聲明做出的聲明前置
  sayAge(10);        //報(bào)錯(cuò) Uncaught TypeError: sayAge is not a function(…) sayAge此時(shí)還為被賦值為函數(shù)
  function sayName(name){
    console.log('hello ', name);
  }
  var sayAge = function(age){
    console.log(age);
  };

作用域鏈

5.如下代碼輸出什么? 寫出作用域鏈查找過(guò)程偽代碼

// 輸出10

  var x = 10
  bar()       //輸出10
  function foo() {
    console.log(x)
  }
  function bar(){
    var x = 30
    foo()
  }

作用域鏈查找過(guò)程偽代碼

/*
  1.
  globalContext = {
    AO:{
      x: 10
      foo:funcation(){}
      bar:funcation(){}
    }
    Scope: null
  }

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

  2.
  barContext = {
    AO:{
      x: 30
    }
    scope: bar.[[scope]] // globalContext.AO
  }
  3.
  fooContext = {
    AO:{}
    scope: foo.[[scope]] // globalContext.AO
  }

*/

6.如下代碼輸出什么? 寫出作用域鏈查找過(guò)程偽代碼

// 輸出30

  var x = 10;
  bar()     //輸出30
  function bar(){
    var x = 30;
    function foo(){
      console.log(x) 
    }
    foo();
  } 

作用域鏈查找過(guò)程偽代碼

/*
  1.
  globalContext = {
    AO:{
      x: 10
      bar:funcation(){}
    }
    Scope: null
  }
  bar.[[scope]] = globalContext.AO

  2.
  barContext = {
    AO:{
      x: 30
      foo:funcation(){}
    }
    Scope: bar.[[scope]] // globalContext.AO
  }
  foo.[[scope]] = barContext.AO

  3.
  fooContext = {
    AO:{}
    Scope: foo.[[scope]] // barContext.AO
  }
*/

7.以下代碼輸出什么? 寫出作用域鏈的查找過(guò)程偽代碼

輸出30

  var x = 10;
  bar() 
  function bar(){
    var x = 30;
    (function (){
      console.log(x)    // 30
    })()
  }
/*
  globalContext = {
    AO:{
      x: 10
      bar:funcation(){}
    }
    Scope: null
  }
  bar.[[scope]] // globalContext.AO

  2.
  barContext = {
    AO:{
      x: 30
      匿名函數(shù)A:funcation(){}
    }
    Scope: bar.[[scope]] = globalContext.AO
  }
  匿名函數(shù)A.[[scope]] // barContext.AO

  3.
  匿名函數(shù)AContext = {
    AO:{}
    Scope: 匿名函數(shù)A.[[scope]] // barContext.AO
  }
*/  

8.以下代碼輸出什么? 寫出作用域鏈查找過(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()                //輸出: undefined 5 1 6 20 
  console.log(a)      //輸出: 200
/*
1.
  globalContext = {
    AO:{
      a: 1 -> 200
      fn:funcation(){}
      fn3:funcation(){}
    }
    Scope: null
  }
  fn.[[scope]] = globalContext.AO
  fn3.[[scope]] = globalContext.AO

  2.
  fnContext = {
    AO:{
      a: 5 -> 6 -> 20
      fn2:funcation(){}
    }
    Scope: fn.[[scope]] // globalContext.AO
  }
  fn2.[[scope]] = fnContext.AO

  3.
  fn3Context = {
    AO:{}
    Scope: foo.[[scope]] // globalContext.AO
  }

  4.
  fn2Context = {
    A:{}
    Scope: fn2.[[scope]] // fnContext.AO
  }
*/
注意:在JavaScript里,每個(gè)函數(shù),當(dāng)被調(diào)用時(shí),都會(huì)創(chuàng)建一個(gè)新的執(zhí)行上下文。因?yàn)樵诤瘮?shù)里定義的變量和函數(shù)只能在函數(shù)內(nèi)部被訪問(wèn),外部無(wú)法獲取;當(dāng)調(diào)用函數(shù)時(shí),函數(shù)提供的上下文就提供了一個(gè)非常簡(jiǎn)單的方法創(chuàng)建私有變量。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,441評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,475評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,834評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,009評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,559評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,516評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,728評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,249評(píng)論 3 399
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,484評(píng)論 2 379

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

  • 一、函數(shù)聲明和函數(shù)表達(dá)式 函數(shù)聲明的形式:function fn() { } ,使用函數(shù)聲明的形式聲明一個(gè)函數(shù)時(shí),...
    sutingy閱讀 173評(píng)論 0 0
  • 一、函數(shù)聲明function(){}是function +函數(shù)名字(){內(nèi)容}調(diào)用函數(shù)是 函數(shù)名字();funct...
    崔敏嫣閱讀 295評(píng)論 0 0
  • 函數(shù)聲明和函數(shù)表達(dá)式 函數(shù)聲明: fuction fn(){console.log("test");} 函數(shù)表達(dá)式...
    趙BW閱讀 318評(píng)論 0 0
  • 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 用函數(shù)聲明創(chuàng)建的函數(shù)可以在定義之前就進(jìn)行調(diào)用(聲明前置);而用函數(shù)表達(dá)式創(chuàng)建的函數(shù)...
    727上上上閱讀 83評(píng)論 0 0
  • 1.函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*) 區(qū)別: 函數(shù)聲明后面的分號(hào)可加可不加,不加也不影響接下來(lái)語(yǔ)句的執(zhí)行,但...
    Sheldon_Yee閱讀 410評(píng)論 0 1