JavaScript關(guān)于函數(shù)

問答

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

函數(shù)聲明形式:

function sayHello(){
  console.log("Hello, World! ");
}

函數(shù)表達式形式:

var sayHello = function(){
  console.log("Hello, World! ");
};

在聲明一個變量的時候,javascript解釋器會將變量聲明的語句提前,函數(shù)聲明形式會發(fā)生函數(shù)聲明前置,所以代碼如果放在使用之后也可以生效,而函數(shù)表達式形式只發(fā)生了變量聲明前置,如果在定義之前使用,函數(shù)名目前還只是一個變量名,不能用()進行執(zhí)行,會拋出錯誤。

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

var a = 1;
//實際上相當(dāng)于:
var a; //這句聲明會提前到所有語句之前執(zhí)行
a=1;

所以,

console.log(b); 
var b = 1;//console.log 并不會報錯,而是返回變量聲明之后的值undefined。

arguments 是什么 (*)

arguments 是一個可以接收所有函數(shù)傳遞參數(shù)的類似數(shù)組,在函數(shù)里可以直接取用。當(dāng)函數(shù)的參數(shù)不確定數(shù)量的時候可以使用arguments對形參進行數(shù)組的方式操作,可以實現(xiàn)類似重載。

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

function fn(){ 
  var sum = 0; 
  for(x in arguments ){
    sum=arguments[x]+sum;
  };
  console.log(sum);
}
//無論多少參數(shù)都可實現(xiàn)累加運算

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

(function() {
  c =1 ;
  console.log(c)
})();

立即執(zhí)行函數(shù)可以將寫在函數(shù)體內(nèi)的語句直接執(zhí)行。區(qū)別于普通語句,立即執(zhí)行函數(shù)內(nèi)的變量不會干擾函數(shù)體外,形成一個類似區(qū)塊的空間。

什么是函數(shù)的作用域鏈 (****)

函數(shù)對象其中一個內(nèi)部屬性是[[Scope]],由ECMA-262標(biāo)準(zhǔn)第三版定義,該內(nèi)部屬性包含了函數(shù)被創(chuàng)建的作用域中對象的集合,這個集合被稱為函數(shù)的作用域鏈,它決定了哪些數(shù)據(jù)能被函數(shù)訪問。
在函數(shù)執(zhí)行過程中,每遇到一個變量,都會經(jīng)歷一次標(biāo)識符解析過程以決定從哪里獲取和存儲數(shù)據(jù)。該過程從作用域鏈頭部,也就是從活動對象開始搜索,查找同名的標(biāo)識符,如果找到了就使用這個標(biāo)識符對應(yīng)的變量,如果沒找到繼續(xù)搜索作用域鏈中的下一個對象,如果搜索完所有對象都未找到,則認(rèn)為該標(biāo)識符未定義。函數(shù)執(zhí)行過程中,每個標(biāo)識符都要經(jīng)歷這樣的搜索過程。


--JavaScript 開發(fā)進階:理解 JavaScript 作用域和作用域鏈]

簡單來說,函數(shù)作用域鏈用于查找函數(shù)內(nèi)部變量的位置。在執(zhí)行過程中,按照作用域鏈表的順序依次進行查找。在函數(shù)每執(zhí)行一次,這個表進行動態(tài)創(chuàng)建。所以,在實際使用中應(yīng)當(dāng)盡量減少全局變量的使用,避免with語句使用,如果一個跨作用域的對象被引用了一次以上,則先把它存儲到局部變量里再使用。


代碼

  1. 以下代碼輸出什么? (難度**)

  • 可以看出arguments 是參數(shù)的數(shù)組,可以對其進行修改,改變參數(shù)。
  • 當(dāng)參數(shù)缺省的時候,定義為 undefined。
  • 參數(shù)是具有順序的,第一個參數(shù)傳遞為第一個形參。
  1. 寫一個函數(shù),返回參數(shù)的平方和?如 (難度**)

function sumOfSquares(){
  var sum = 0;
  for(var x in arguments){
    sum += arguments[x]*arguments[x];
  }
  console.log(sum);
}

sumOfSquares(2,3,4);   // 29
sumOfSquares(1,3);   // 10
  1. 如下代碼的輸出?為什么 (難度*)

console.log(a);//返回 undefined
var a = 1;
console.log(b);//報錯 提示未定義

因為聲明前置,實際上在這段代碼執(zhí)行前就已經(jīng)執(zhí)行了var a;,所以在console.log(a)的時候不發(fā)生錯誤,返回undefined。

4.如下代碼的輸出?為什么 (難度*)

  • 由于函數(shù)聲明前置,sayName可以正常執(zhí)行
  • sayAge用了函數(shù)表達式形式,在賦值之前都不可以使用。

5.如下代碼的輸出?為什么 (難度**)

function fn(){}
var fn = 3;
console.log(fn);//3

結(jié)果比較直觀,實際上將上面的語句顛倒也會輸出相同的結(jié)果:

var fn = 3;
function fn(){}
console.log(fn);//3
  • 還是因為聲明前置的原因,可以將聲明都放到開頭,再來理解:
var fn;
function fn(){}

fn = 3;
console.log(fn);//3

這就是上面那段代碼實際執(zhí)行的樣子,這也就不難理解了。
需要注意的是,聲明前置,變量的聲明要比函數(shù)的聲明要更早執(zhí)行。

  function fn(){}
  var fn;  
  console.log(fn);

//function fn(){}

6.如下代碼的輸出?為什么 (難度***)

  • 在函數(shù)內(nèi)部定義的函數(shù),也會發(fā)生聲明前置。上圖中即使傳入了參數(shù)10,但與函數(shù)內(nèi)部函數(shù)重名,被覆蓋掉了。此時console.log(fn2),打印出的就是fn2函數(shù)本身。此后fn2被重新賦值2,打印出3。

7.如下代碼的輸出?為什么 (難度***)

var fn = 1;
function fn(fn){
   console.log(fn);
}
console.log(fn(fn)); 

//Uncaught TypeError: fn is not a function(…)

實際執(zhí)行過程,由于聲明前置:

var fn;
function fn(fn){
   console.log(fn);
}

fn = 1;
console.log(fn(fn)); 

fn被重新賦值為1,自然無法執(zhí)行,報錯。

8.如下代碼的輸出?為什么 (難度**)

    //作用域
    console.log(j);//undefined
    console.log(i);//undefined
    for(var i=0; i<10; i++){
        var j = 100;
    }
    console.log(i);//10
    console.log(j);//100
  • 需要注意的是,for是屬于運算符,不屬于函數(shù),所以在其內(nèi)部定義的變量和當(dāng)前屬于同一個作用域。在JS中只有函數(shù)內(nèi)部使用var定義,才具備另一個作用域性質(zhì)。

9.如下代碼的輸出?為什么 (難度****)

fn(); 
var i = 10;
var fn = 20;
console.log(i);
function fn(){
    console.log(i);
    var i = 99;
    fn2();
    console.log(i);
    function fn2(){
        i = 100;
    }
}

改寫代碼:

var i;
var fn;
function fn(){
    var i;
    function fn2(){
        i = 100;
    }

    console.log(i);//undefined
    i = 99;
    fn2();
    console.log(i);//100
    
}

fn(); 
//undefined
//100
i = 10;
fn = 20;
console.log(i);//10

10.如下代碼的輸出?為什么 (難度*****)

  • 立即執(zhí)行函數(shù)的內(nèi)部定義的函數(shù)名、變量不會影響到函數(shù)外面。所以在其內(nèi)部執(zhí)行的say(),并沒有覆蓋函數(shù)外的say = 0; 在最后打印出來還是0 。
  • 函數(shù)內(nèi)部有一個嵌套結(jié)構(gòu)。使用嵌套時,函數(shù)名可以在function后定義。不需要的時候可以不加。
  • return的執(zhí)行,伴隨函數(shù)的退出,不再繼續(xù)往下執(zhí)行。

本教程版權(quán)歸屬于 張宇 及 饑人谷 所有,轉(zhuǎn)載請說明來源~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 今天是函數(shù)基礎(chǔ)部分!有點心理準(zhǔn)備!老規(guī)矩,先放思維導(dǎo)圖!圖片哪里不懂,結(jié)合下面文字對應(yīng)理解! 認(rèn)識函數(shù) 在一個完整...
    范小飯_閱讀 458評論 1 9
  • 一、函數(shù)聲明和函數(shù)表達式有什么區(qū)別?(*) ECMAScript里面規(guī)定了三種聲明函數(shù)的方式: 構(gòu)造函數(shù)函數(shù)也是對...
    婷樓沐熙閱讀 606評論 0 2
  • 問答: 1. 函數(shù)聲明和函數(shù)表達式有什么區(qū)別 (*) 在日常的任務(wù)中,JavaScript主要使用下面兩種方式創(chuàng)建...
    小木子2016閱讀 398評論 0 0
  • 朋友一生一起走 那些日子不再有 一句話 一輩子 一生情 一杯酒 朋友不曾孤單過 一聲朋友你會懂 還有傷 還有痛 還...
    21不思量閱讀 226評論 0 0
  • Workflow真的是iOS上的一款效率神器,可以簡化很多步驟,同時可以創(chuàng)造出很多有趣的功能。我也根據(jù)自己的需求,...
    Icebay閱讀 1,143評論 0 0

友情鏈接更多精彩內(nèi)容