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(…).原因:類(lèi)似變量提升,函數(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)用可以寫(xiě)在聲明前面布讹,函數(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è)類(lèi)數(shù)組對(duì)象膘流,類(lèi)似數(shù)組的方式絮缅,可以通過(guò)下標(biāo)的方式去獲取值,但它本身不是數(shù)組呼股,沒(méi)有數(shù)組的一些特性耕魄,所以叫類(lèi)數(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ù)或類(lèi)型不同考润。調(diào)用的時(shí)候根據(jù)函數(shù)的參數(shù)來(lái)區(qū)別不同的函數(shù)。
  • JS并不像其他強(qiáng)類(lèi)型語(yǔ)言一樣可以聲明重載函數(shù)读处,若在原先聲明的函數(shù)后再聲明一個(gè)不同參數(shù)數(shù)量的函數(shù)(JS是弱語(yǔ)言糊治,聲明的函數(shù)不需要指明參數(shù)類(lèi)型),解析器會(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.寫(xiě)一個(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)有定義,類(lè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.如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(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.如下代碼輸出什么? 寫(xiě)出作用域鏈查找過(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.以下代碼輸出什么? 寫(xiě)出作用域鏈的查找過(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.以下代碼輸出什么恃锉? 寫(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()                //輸出: 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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市阐虚,隨后出現(xiàn)的幾起案子序臂,更是在濱河造成了極大的恐慌,老刑警劉巖实束,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奥秆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡咸灿,警方通過(guò)查閱死者的電腦和手機(jī)构订,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)避矢,“玉大人鲫咽,你說(shuō)我怎么就攤上這事签赃」纫欤” “怎么了分尸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)歹嘹。 經(jīng)常有香客問(wèn)我箩绍,道長(zhǎng),這世上最難降的妖魔是什么尺上? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任材蛛,我火速辦了婚禮,結(jié)果婚禮上怎抛,老公的妹妹穿的比我還像新娘卑吭。我一直安慰自己,他們只是感情好马绝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布豆赏。 她就那樣靜靜地躺著,像睡著了一般富稻。 火紅的嫁衣襯著肌膚如雪掷邦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天椭赋,我揣著相機(jī)與錄音抚岗,去河邊找鬼。 笑死哪怔,一個(gè)胖子當(dāng)著我的面吹牛宣蔚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播认境,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼胚委,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了元暴?” 一聲冷哼從身側(cè)響起篷扩,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茉盏,沒(méi)想到半個(gè)月后鉴未,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸠姨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年铜秆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讶迁。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡连茧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啸驯,我是刑警寧澤客扎,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站罚斗,受9級(jí)特大地震影響徙鱼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜针姿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一袱吆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧距淫,春花似錦绞绒、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至拐揭,卻和暖如春撤蟆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堂污。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工家肯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盟猖。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓讨衣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親式镐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子反镇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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

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