函數與作用域

函數聲明和函數表達式有什么區別?

函數聲明:function functionName() {}
函數表達式:var fn = function() {}

  • 函數聲明會提前,函數表達式可以省略標識符(函數名)。

函數聲明不必放到調用的前面,函數表達式聲明必須放到調用的前面。

什么是變量的聲明前置?什么是函數的聲明前置

在一個作用域下,var 聲明的變量和function 聲明的函數會前置.前置到當前作用域的開頭。
變量聲明的前置:

console.log(i);
var i = 1;     //undefined

代碼執行過程:

var i;.   //提前在程序最開始,聲明一個變量i 未賦值 所以是 undefined
console.log(i);
i = 1;   //console.log(i)在 i = 1 ;賦值語句之前,而變量聲明前置所以打印的時候i是undefined;

函數的聲明前置:

test(1)
function test(x){
  console.log(x);
}     // 1

通過函數聲明的方式建立的函數表達式會提前,這段代碼過程:

function test(x){};
test(1)

輸出的結果為1;因為function test(x){} 整個函數 已經提前到了test(1)之前。
但是,同樣的方法,使用函數表達式,其出現的結果是報錯,因為其調用在其聲明之前。
如下例子:

func1();    // 輸出:我是函數聲明

func2();    // 報錯 

console.log(a); // 輸出:undefined

function func1() {
    console.log("我是函數聲明");
}

var func2 = function() {
    console.log("我是函數表達式");
}

var a = 10;

arguments 是什么?

arguments是一個類數組對象。代表傳給一個function的參數列表。
?arguments對象是函數內部的本地變量;arguments 已經不再是函數的屬性了。可以在函數內部通過使用 arguments 對象來獲取函數的所有參數。這個對象為傳遞給函數的每個參數建立一個條目,條目的索引號從0開始。它包括了函所要調用的參數。object對象。類數組。

函數的"重載"怎樣實現?

首先,要明確,在JS中,沒有重載。同名函數會覆蓋。但可以在函數體針對不同的參數調用執行相應的邏輯。
如下例:

function printPeopleInfo(name, age, sex){
    if(name){
      console.log(name);
    }

    if(age){
      console.log(age);
    }

    if(sex){
      console.log(sex);
    }
  }
  printPeopleInfo('Byron', 26);//Byron 26
  printPeopleInfo('Byron', 26, 'male');//Byron 26 male

javascript不能支持函數的重載,如下:

function f(length) 
{ 
   alert("高為:"+length); 
} 

function f(length,width) 
{ 
   alert("高為:"+length+",寬為:"+width); 
}

上面那段代碼其實是行不通的,因為函數定義時的參數個數和函數調用時的參數個數沒有任何關系。在函數中可以用f.arguments[0]和f.arguments[1]得到調用時傳入的第一和第二個參數,所以定義function(length),后面用f(10,10)調用是沒有問題的。所以在上面這段代碼中,第二個函數是永遠不可能被調用到的,那么,要怎樣才能實現像函數重載那樣的功能呢?
那就是在函數定義中用f.arguments.length判斷一下調用時傳入的參數個數。然后對不同的情況采用不同的處理方式。 如下:

function f() 
{ 
    var len= arguments.length; 
    if(2 == len) 
    { 
        var length = arguments[0]; 
        var width = arguments[1]; 
        f2(length,width); 
    } 
    else 
    { 
        var length = arguments[0]; 
        f1(length); 
    } 
} 

function f1(length) 
{ 
    alert("高為:"+length); 
} 

function f2(length,width) 
{ 
    alert("高為:"+length+",寬為:"+width); 
}

*這樣,你就可以給函數f()傳入一個參數也可以傳入兩個參數了,比如f(10)和f(10,10); *

  • 這樣雖然可以實現重載,但也不是很好用,我們可以根據具體情況在一個函數中實現重載,如果要重載的兩個函數相差較大,那就保留兩個函數,而如果兩個函數的實現基本差不多,那么可以在一個函數中進行判斷,處理不同的部分,而不需要像上面那樣寫成三個函數,如下:
function f(length) 
{ 
    var len= arguments.length; 
    if(1 == len) 
    { 
        var width = arguments[1]; 
        alert("高為:"+length+",寬為:"+width); 
    } 
    else 
    { 
        alert("高為:"+length); 
    } 
}

立即執行函數表達式是什么?有什么作用

(function(){
    var a = 1;
})()

作用: 隔離作用域。
??JavaScript有很多致命缺陷,比如JavaScript中沒有命名空間,而且只有function代碼塊內部可以隔離變量作用域,自調用匿名函數就用來防止變量彌散到全局,以免各種js庫沖突。

求n!,用遞歸來實現

function fn(n) {
                if(n < 0){
                alert("error")
                }
        else if(n == 0 || n == 1)  {
            return 1;
        }
        return n * fn(n-1);
    }
    fn(5);

以下代碼輸出什么?

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:2
sex: undefined
['小谷','3']
name valley

name:男
age:undefined
sex:undefined
['男']
name valley

寫一個函數,返回參數的平方和?

 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

如下代碼的輸出?為什么

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

console.log(a)輸出的是undefined、因為變量在當前作用域下被前置,結果在console.log(a)前面的var a;雖然聲明了但是沒有賦值,結果為undefined.
console.log(b) b完全是沒有聲明也沒有賦值,結果是報錯.//ReferenceError: b is not defined
*/

如下代碼的輸出?為什么

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

sayNme('world');會返回'hello world'.
sayAge(10);因為是使用表達式定義,所以,當調用在定義之前就會報錯,sayAge is not a function.

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

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
  },

foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
}
2.調用bar()
barContext = {
  AO: {
    x: 30
  }
  Scope: bar.[[scope]] = globalContext.AO
}
3.調用foo()
fooContext = {
  AO: {}
  Scope: foo.[[scope]] = globalContext.AO
} */

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

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
2. 調用bar
barContext={
  AO:{
    x: 30,
    foo:function
  },
Scope: bar.[[scope]]=globalContext.AO
}
foo.[[scope]]=barContext.AO
3. 調用foo
fooContext={
  AO:{},
  Scope: foo.[[scope]]=barContext.AO
}

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

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.調用bar
barContext={
  AO:{
    x:30, 
    function(){}
  }
Scope:bar.[[scope]]=globalContext.AO
}
function().[[scope]]=barContext.AO
3. 調用function()
functionContext={
  AO:{}
  Scope:function().[[scope]]=barContext.AO
}

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

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)
輸出: undefined 5 1 6 20 200
1.
globalContext={
  AO:{
    a:200,
    fn:function,
    fn3:function
  }
Scope: null
}
fn.[[scope]]=globalContext.AO
fn3.[[scope]]=globalContext.AO
2. 調用fn
fnContext={
  AO:{
  a:20, 
  fn2:function  
}
Scope: fn.[[scope]]=globalContext.AO
}
fn2.[[scope]]=fnContext.AO
3. 調用fn3
fn3Context={
  AO:{}
  Scope:fn3.[[scope]]=globalContext.AO
}
4. 調用fn2
fn2Context={
  AO:{}
 Scope:fn2.[[scope]]=fnContext.AO
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • 1.函數聲明和函數表達式有什么區別 函數就是一段可以反復調用的代碼塊。函數還能接受輸入的參數,不同的參數會返回不同...
    徐國軍_plus閱讀 481評論 0 0
  • 函數聲明和函數表達式有什么區別 函數聲明語法:function functionName(arg0,arg1,ar...
    _Dot912閱讀 576評論 0 3
  • 函數聲明和函數表達式有什么區別? 函數聲明和函數表達式是EMACScript規定的兩種不同的聲明函數的方法。1.函...
    LeeoZz閱讀 350評論 0 1
  • 1.函數聲明和函數表達式有什么區別 function命令聲明的代碼區塊,就是一個函數。function命令后面是函...
    饑人谷_Leon閱讀 286評論 0 0
  • 聲明前置和作用域也是JS 部分面試常考點 1.函數聲明和函數表達式有什么區別 函數聲明:使用function關鍵字...
    湖衣閱讀 204評論 0 0