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

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

  • ECMAScript規(guī)定了三種聲明函數(shù)方式:構造函數(shù)肄程、函數(shù)聲明贯钩、和函數(shù)表達式

  • 函數(shù)聲明: 函數(shù)聲明通過關鍵字function來聲明, 關鍵詞后面是函數(shù)名, 名稱后面有個小括號, 括號里面放的是函數(shù)的參數(shù), 最后是一對花括號,包括函數(shù)的代碼塊

function sum(num1,num2) {
    return num1+num2;
}

函數(shù)表達式

var sum = function(num1, num2) {
    return num1+num2;
};

定義變量sum并將一個匿名函數(shù)賦值給變量霎箍,這時這個匿名函數(shù)又稱函數(shù)表達式(Function Expression)奇钞。function關鍵字后面沒有函數(shù)名。

區(qū)別:

  1. 函數(shù)聲明最后一般不寫分號, 而函數(shù)表達式有分號
  2. 函數(shù)聲明和變量聲明都有聲明提前的特點, 函數(shù)聲明是函數(shù)名稱和函數(shù)體均提前聲明了, 可以在聲明之前調用它;
  3. 函數(shù)表達式的規(guī)則與變量聲明提前一樣,只是函數(shù)聲明變量提前了, 但是它的賦值仍在原來的位置, 不能在函數(shù)表達式之前調用漂坏。

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

  • 變量的聲明前置:
    變量聲明前置是指把變量的聲明提前到當前作用域的最前面, 但變量的賦值仍然按照原來的順序執(zhí)行, 如果變量聲明但未被賦值, 變量自動賦值為undefined。
  • 函數(shù)的聲明前置:
    函數(shù)的聲明前置有兩種情況, 一個是使用函數(shù)聲明, 則整個聲明都前置, 另一個是使用函數(shù)表達式, 那么規(guī)則和變量的聲明前置一樣顶别。

例如:

console.log(a); //undefined
var a = 3;
console.log(a); //3

sayHello();

function sayHello(){
  console.log('hello');
}

執(zhí)行的情況為:

var a;     // 變量聲明前置                     
function sayHello() {     // 函數(shù)聲明前置
    console.log('hello');
}
console.log(a); 
a = 3;
console.log(a);
sayHello();

3. arguments 是什么

  • arguments是一個類數(shù)組對象, 代表傳給一個function的參數(shù)列表, 只在函數(shù)內部起作用; arguments的值與函數(shù)傳入參數(shù)有關, 與定義參數(shù)無關谷徙。
  • 可以使用arguments對象在函數(shù)中引用函數(shù)的參數(shù)。此對象包含傳遞給函數(shù)的每個參數(shù)的條目驯绎,第一個條目的索引從0開始完慧。例如,如果一個函數(shù)傳遞了三個參數(shù)剩失,你可以以如下方式引用他們:
arguments[0]
arguments[1]
arguments[2]

參數(shù)也可以被設置:
arguments[1] = 'new value';

  • arguments對象不是一個 Array 屈尼。它類似于Array册着,但除了長度之外沒有任何Array屬性
  • 屬性
    1.arguments.callee
    指向當前執(zhí)行的函數(shù)。
    2.arguments.caller
    指向調用當前函數(shù)的函數(shù)脾歧。
    3.arguments.length
    指向傳遞給當前函數(shù)的參數(shù)數(shù)量甲捏。
    4.arguments[@@iterator]
    返回一個新的Array迭代器對象,該對象包含參數(shù)中每個索引的值。

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

  • 重載是很多面向對象語言實現(xiàn)多態(tài)的手段之一, 相同名字的函數(shù)參數(shù)個數(shù)不同, 或者順序不同, 都被認為是不同的函數(shù).
  • 如果定義了兩個名字相同的函數(shù),則該名字屬于后定義的函數(shù)锰镀。
  • ECMAscript函數(shù)不能像傳統(tǒng)意義上的那樣實現(xiàn)重載, ECMAscript函數(shù)沒有簽名大溜,其參數(shù)是由包含零個或多個值的數(shù)組來表示的。而沒有函數(shù)簽名估脆,真正的重載是不可能做到的钦奋。但可以在函數(shù)體針對不同的參數(shù)調用執(zhí)行相應的邏輯
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');

也可以用arguments.length來實現(xiàn)重載。

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

  • 在JavaScript中, 一對圓括號()是一種運算符, 跟在函數(shù)明后, 表示調用該函數(shù); 有時我們希望在定義函數(shù)之后, 立即調用該函數(shù); 這時, 不能再函數(shù)的定義之后加圓括號, 會產生語法錯誤; 因為function這個關鍵字既可以當做語句, 也可當做表達式; 為了避免解析上的歧義, JavaScript引擎看到行首是function關鍵字之后, 認為這一段都是函數(shù)的定義 , 不應該以圓括號結尾, 所以報錯;
  • 解決方法就是不要讓function出現(xiàn)在行首, 讓引擎將其理解外一個表達式, 最簡單的方式, 是將其放在圓括號內
(function(){
  var a  = 1;
})()
console.log(a); //undefined

其他寫法

// 在數(shù)組初始化器內只能是表達式
[function fn2() {}]();
 
// 逗號也只能操作表達式
1, function fn3() {}();

作用:將全局變量與局部變量分隔開锨苏,保證全局變量不受污染。

6. 求n!棺聊,用遞歸來實現(xiàn)

function factorial(num) {
  if (num === 1 || num === 0) {
    return 1;
  }
  else if (num < 0) {
    return console.log("minus has no factorial");
  }
  return num*arguments.callee(num-1);
}
console.log(factorial(7));

7. 以下代碼輸出什么

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

輸出結果:

name:饑人谷
age:2
sex:男
["饑人谷", 2, "男"]
name:valley
name:小谷
age:3
sex:undefined
[“小谷”, “3”]
name:valley
name:男
age:undefined
sex:undefined
["男"]
name:valley

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

function sumOfSquares(){
   var sum = 0;
    for(var i = 0; i < arguments.length; i++) {
        sum = 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

9.如下代碼的輸出贞谓?為什么

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

聲明前置實際為:

var a;
console.log(a);  //undefined
a = 1;
console.log(b); //Uncaught ReferenceError: b is not defined

console.log(a); 這個時候a還沒有賦值; b變量沒有聲明和定義, 所以報錯限佩。

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

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

聲明前置實際為:

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

函數(shù)聲明在作用域內會前置, 函數(shù)表達式不會前置裸弦,所以函數(shù)表達式需要放在調用的前面祟同,后一個函數(shù)調用的時候還未被定義,所以出現(xiàn)報錯理疙。

11. 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

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

作用域鏈查找過程偽代碼:

globalContext= {
  AO: {
    x: 10
    foo: funtion
    bar: funtion
         }晕城,
        Scope: null
}
//聲明 foo 時 得到下面
foo.[[scope]] = globalContext.AO
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
當調用 bar() 時, 進入 bar 的執(zhí)行上下文
barContext = {
  AO: {
    x: 30
  },
  Scope: bar.[[scope]] //globalContext.AO
}
當調用 foo() 時窖贤,先從 bar 執(zhí)行上下文中的 AO里找砖顷,找不到再從 bar 的 [[scope]]里找到后即調用
當調用 foo() 時,進入 foo 的執(zhí)行上下文
fooContext = {
  AO: {},
  Scope: foo.[[scope]] // globalContext.AO
}
所以 console.log(x)是 10

12.如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

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

作用域鏈查找過程偽代碼:

globalContext = {
  AO: {
    x: 10
    bar: function
  },
  Scope: null
}
//聲明 bar 時 得到下面
bar.[[scope]] = globalContext.AO
當調用 bar() 時赃梧, 進入 bar 的執(zhí)行上下文
barContext = {
  AO: {
    x: 30,
    foo: function
  },
  Scope: bar.[[scope]] //globalContext.AO
}
//在 bar 的執(zhí)行上下文里聲明 foo 時 得到下面
foo.[[scope]] = barContext.AO
當調用 foo() 時滤蝠,先從 bar 執(zhí)行上下文中的 AO里找,找到后即調用
當調用 foo() 時授嘀,進入 foo 的執(zhí)行上下文
fooContext = {
  AO: {},
  Scope: foo.[[scope]] // barContext.AO
}
所以 console.log(x)是 30

13.以下代碼輸出什么? 寫出作用域鏈的查找過程偽代碼

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}

作用域鏈查找過程偽代碼:

globalContext = {
  AO: {
    x: 10,
    bar: function
  },
  Scope: null
}
//聲明bar時
bar.[[scope]] = globalContext.AO
//調用bar時物咳,進入bar的執(zhí)行上下文
barContext = {
  AO: {
    x: 30,
    function//立即執(zhí)行函數(shù)表達式
  },
  Scope: bar.[[scope]] // globalContext.AO
//執(zhí)行立即執(zhí)行函數(shù)
functionContext = {
  AO:{ }
},
Scope: function.[[scope]] //barContext.AO
所以console.log(x)為30。

14.以下代碼輸出什么蹄皱? 寫出作用域鏈查找過程偽代碼

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)

作用域鏈查找過程偽代碼:

globalContext = {
  AO: {
    a: 1,
    fn: function,
    fn3: function
  },
  Scope: null
}
//聲明fn時
fn.[[scope]] = globalContext.AO
//聲明fn3時
fn3.[[scope]] = globalContext.AO
調用fn览闰,進入fn的執(zhí)行上下文
fnContext = {
  AO: {
    a: 5
    fn2: function
  },
  Scope: fn.[[scope]] //globalContext.AO
}
//調用fn3芯肤,此時在fn的執(zhí)行上下文的AO中找不到fn3,于是在fn的scope里找压鉴,找到后即調用
fn3Context = {
  AO: {
    a: 200
  },
  Scope: fn3.[[scope]] //globalContext.AO
}
//調用fn2崖咨,在bar的執(zhí)行上下文AO中可以找到fn2,直接調用
fn2Context = {
AO: {
    a: 20
  },
  Scope: fn2.[[scope]] //fnContext.AO
}
//輸出結果如下:
//調用fn
console.log(a) // a的值在fnContext.AO中晴弃,此時a變量聲明了但未定義掩幢,所以輸出undefined。
var a = 5 // a被賦值為5
console.log(a) // 輸出5
a++ // fnContext.AO中a的值變?yōu)?
//調用fn3
fn3() //此時a的值為globalContext.AO里的a上鞠,即console.log(a) 輸出1
a = 200 // globalContext.AO里的a值變?yōu)?00
//調用fn2
fn2() //此時a的值為fnContext.AO里的a际邻,即console.log(a) 輸出6
a = 20 // fnContext.AO里的a變?yōu)?0
console.log(a) //輸出20
//fn調用結束,此時 globalContext.AO里的a值為200
console.log(a) // 輸出200
// 輸出順序為:undefined, 5, 1, 6, 20, 200
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末芍阎,一起剝皮案震驚了整個濱河市世曾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谴咸,老刑警劉巖轮听,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異岭佳,居然都是意外死亡血巍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門珊随,熙熙樓的掌柜王于貴愁眉苦臉地迎上來述寡,“玉大人,你說我怎么就攤上這事叶洞■晷祝” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵衩辟,是天一觀的道長螟炫。 經常有香客問我,道長艺晴,這世上最難降的妖魔是什么昼钻? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮封寞,結果婚禮上换吧,老公的妹妹穿的比我還像新娘。我一直安慰自己钥星,他們只是感情好沾瓦,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般贯莺。 火紅的嫁衣襯著肌膚如雪风喇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天缕探,我揣著相機與錄音魂莫,去河邊找鬼。 笑死爹耗,一個胖子當著我的面吹牛耙考,可吹牛的內容都是我干的。 我是一名探鬼主播潭兽,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼倦始,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了山卦?” 一聲冷哼從身側響起鞋邑,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎账蓉,沒想到半個月后枚碗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡铸本,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年肮雨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箱玷。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡酷含,死狀恐怖,靈堂內的尸體忽然破棺而出汪茧,到底是詐尸還是另有隱情,我是刑警寧澤限番,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布舱污,位于F島的核電站,受9級特大地震影響弥虐,放射性物質發(fā)生泄漏扩灯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一霜瘪、第九天 我趴在偏房一處隱蔽的房頂上張望珠插。 院中可真熱鬧,春花似錦颖对、人聲如沸捻撑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顾患。三九已至番捂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間江解,已是汗流浹背设预。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留犁河,地道東北人鳖枕。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像桨螺,于是被迫代替她去往敵國和親宾符。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持彭谁,譯者再次奉上一點點福利:阿里云產品券吸奴,享受所有官網優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 2,306評論 0 21
  • 1.函數(shù)聲明和函數(shù)表達式有什么區(qū)別 函數(shù)就是一段可以反復調用的代碼塊缠局。函數(shù)還能接受輸入的參數(shù)则奥,不同的參數(shù)會返回不同...
    徐國軍_plus閱讀 476評論 0 0
  • 函數(shù)聲明和函數(shù)表達式有什么區(qū)別 函數(shù)聲明語法:function functionName(arg0,arg1,ar...
    _Dot912閱讀 575評論 0 3
  • 1.函數(shù)聲明和函數(shù)表達式有什么區(qū)別 (*) 區(qū)別: 函數(shù)聲明后面的分號可加可不加,不加也不影響接下來語句的執(zhí)行狭园,但...
    Sheldon_Yee閱讀 401評論 0 1
  • 月光的平靜是內心的獨白 于是思念被升華為一道無形的傷口 窗外的人們嘻笑著打破這孤寂 他們如何懂得我有怎樣的故事 風...
    走來走去的孫小皮閱讀 199評論 0 1