JS函數與作用域

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

函數聲明和函數表達式是EMACScript規定的兩種不同的聲明函數的方法。
1.函數聲明

//聲明函數
function name() {      //function+函數名+(參數)+{函數體}
    console.log ('Jack')
}

 //函數調用
name()

函數聲明會在JavaScript代碼開始時提到最前面進行定義,因此函數聲明不必在調用之前定義。
2.函數表達式

var name = function () {
    console.log ('Jack')
}

雖然變量聲明會提到JavaScript代碼開始前,但是賦值要運行到該行代碼才執行,因此在調用用函數表達式聲明的函數時,聲明必須放到調用前。

總結區別:
1.函數聲明會在代碼開始前定義,函數表達式遇到時才會執行。
2.函數聲明必須有函數名,函數表達式則可以省略。

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

變量聲明前置:
JavaScript的工作方式是先解析代碼,獲取一個作用域下所有的變量聲明,放到代碼開頭聲明,再一行行的執行代碼:

var a = 10;
var b = 20;
//等同于下面代碼;
var a,b;  //將聲明提前,聲明ab。ab的值都是undefined。
a = 10;  //a賦值為10,此時a=10;
b = 20; //b賦值為20,此時b=20;

函數聲明前置:
函數聲明前置與變量聲明前置類似,JavaScript工作是會獲取一個作用域下的所有函數聲明,放在代碼開始前進行定義。如果使用的是函數表達式,則規則與變量聲明前置類似:

var name = function () {
    console.log ('Jack')
}

 //等同于
var name;
name = function () {
    console.log ('Jack')
}
  • arguments是什么?

在ECMAScript中,函數的參數在內部是用一個數組來表示的。在函數體內,可以用arguments來訪問這個參數數組。arguments是一個類數組對象(不是Array的實例),因為可以使用方括號語法訪問它的每一個元素,使用length屬性來確定傳遞進來多少參數,示例:

function test ()  {
    console.log (arguments.length);  //參數的長度
    console.log (arguments[0]);    //第一個參數  
    console.log (arguments[1]);   //第二個參數
}
test ('Jack',1,'888');

  //輸出結果為 3,'Jack',1
  • JS函數的"重載"怎樣實現?

重載,是函數或者方法有相同的名稱,但是參數列表不相同的情形,這樣的同名不同參數的函數或者方法之間,互相稱之為重載函數或者方法。但是在JS,并沒有重載這個概念,但我們可以用另外一種方法實現這個功能:

function test (num) {
    if (num>=90) {
        console.log ('優秀')
    }
    if (num>=60&&num<90)  {
        console.log ('及格')
    }
    if (num<60)  {
        console.log ('不及格')
    }
}
test(95)  //輸出 '優秀'
test(77)  //輸出 '及格'
test(18)  //輸出 '不及格'

這樣對于同一個函數,輸入不同參數就會得到不同結果。

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

在JS中我們可以使用函數聲明和函數表達式聲明函數,再通過函數名進行調用:

function sayName (name) {    //函數聲明聲明函數
    console.log (name);
}
 sayName ('Jack');    //  調用函數

 var sayName = function ()  {    //函數表達式聲明函數
    console.log (name);
}
sayName ('Jack')    //  調用函數

因為在JS中圓括號()內是不能有語句的,括號內容會被當做表達式,因此上面例子可以進行改寫:

(function (name)  {
    console.log (name);
})('Jack')
//或者
(function (name)  {
    console.log (name);
}('Jack'))  // 輸出都為Jack

當JS執行到該行代碼時,函數會被定義且立即執行,叫做立即執行函數表達式。
使用立即執行函數表達式可以創建一個獨立的作用域,形成隔離,避免污染全局。

  • 求n!,用遞歸來實現

 function test (n) {
    if (n===1) {
        return 1;
    }
    return n*test(n-1)
}
test (10);  //3628800
  • 以下代碼輸出什么?

function getInfo(name, age, sex){
        console.log('name:',name);
        console.log('age:', age);
        console.log('sex:', sex);
        console.log(arguments);  //輸出整組參數;
        arguments[0] = 'valley';    //第一個參數賦值為‘valley’;
        console.log('name', name);
    }

 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;
  • 寫一個函數,返回參數的平方和

function test (n) {
    if (n===1)  {
        return 1
    }
    return n*n+test(n-1)*text(n-1)
}
test (2)    //5
  • 解釋下列代碼的輸出及原因

console.log(a);  //  由于聲明提前,此時a未賦值,輸出undefined;
var a = 1;    // a=1;
console.log(b);    //報錯,b未被聲明;
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);    //undefined,因為sayAge未定義;
sayAge = function(age){
        console.log(age);
};
//函數表達式需放到調用前!!
  • 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

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

 /*
作用域查找過程
 goblecontext = {
    AO: {
        X=10
        foo: function
        bar: function 
    }
    foo.[[scope]]: goblecontext.AO
    bar.[[scope]]: goblecontext.AO
}
foocontext = {
    AO: {}
    scope: goblecontext.AO
}
barcontext = {
    AO: {
        x = 30
    }
    scope: goblecontext.AO
}
*/
var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}            //輸出30

 /*
作用域查找過程
goblecontext = {
    AO: {
        x=10
        bar:function
    }
    bar.[[scopr]]=goblecontext.AO
}
barcontext = {
    AO: {
        x=30
        foo:function
    }
    foo.[[scope]]=barcontext.AO
    scope=goblecontext.AO
}
foocontext = {
    AO: {}
    scope=barcontext.AO
}
*/
var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}       //輸出30

 /*
作用域查找
goblecontext = {
    AO: {
        x=10
        bar:function
    }
    bar.[[scope]]=goblecontext.AO
    scope=null
}
barcontext = {
    AO: {
        x=30
        f:function
    }
    f.[[scope]]=barcontext.AO
    scope=goblecontext.AO
}
fcontext = {
    AO: {}
    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()              //輸出:undefined,5,1,6,20,200;
 console.log(a)

 /*
goblecontext = {
    AO: {
        a: undefined
        fn: function
        fn3: function
    }
    scope = null
    fn.[[scope]] = goblecontext.AO
    fn3.[[scope]] = goblecontext.AO
}
fncontext = {
    AO: {
        a: undefinef
        fn2: function
    }
    scope = goblecontext.AO
    fn2.[[scope]] = fncontext.AO
}
fn2context = {
    AO: {
        a: 20
    }
    scope = fncontext.AO
}
fn3context = {
    AO: {
        a: 200
    }
    scope = goblecontext.AO
}
*/

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

推薦閱讀更多精彩內容

  • JavaScript中的函數運行在它們被定義的作用域里,而不是它們被執行的作用域里。 函數聲明和函數表達式有什么區...
    畢子歌閱讀 404評論 0 0
  • 1.函數聲明和函數表達式有什么區別 函數聲明可以看作是函數的初始化,我們將給函數傳參并建立函數體的表達式,當我門建...
    高進哥哥閱讀 219評論 0 0
  • 函數聲明和函數表達式有什么區別 JavaScript 中需要創建函數的話,有兩種方法:函數聲明、函數表達式,各自寫...
    蕭雪圣閱讀 960評論 2 2
  • 1. 函數聲明和函數表達式有什么區別 使用function關鍵字聲明一個函數時,聲明不必放到調用的前面。//函數聲...
    _李祺閱讀 278評論 0 0
  • 11月24日周四晚8點,GitChat團隊開啟了來自一位前端女技術工程師李佳芮的問答交流,以下是主持人小冰將交流過...
    李佳芮_chatbot閱讀 2,770評論 0 4