JS函數與作用域

  • 函數聲明和函數表達式有什么區(qū)別宵睦?

函數聲明和函數表達式是EMACScript規(guī)定的兩種不同的聲明函數的方法槐臀。
1.函數聲明

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

 //函數調用
name()

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

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

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

總結區(qū)別:
1.函數聲明會在代碼開始前定義鹿霸,函數表達式遇到時才會執(zhí)行排吴。
2.函數聲明必須有函數名,函數表達式則可以省略懦鼠。

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

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

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工作是會獲取一個作用域下的所有函數聲明阱飘,放在代碼開始前進行定義斥杜。如果使用的是函數表達式虱颗,則規(guī)則與變量聲明前置類似:

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 ('優(yōu)秀')
    }
    if (num>=60&&num<90)  {
        console.log ('及格')
    }
    if (num<60)  {
        console.log ('不及格')
    }
}
test(95)  //輸出 '優(yōu)秀'
test(77)  //輸出 '及格'
test(18)  //輸出 '不及格'

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

  • 立即執(zhí)行函數表達式是什么?有什么作用丐巫?

在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執(zhí)行到該行代碼時碑韵,函數會被定義且立即執(zhí)行,叫做立即執(zhí)行函數表達式缎脾。
使用立即執(zhí)行函數表達式可以創(chuàng)建一個獨立的作用域祝闻,形成隔離,避免污染全局遗菠。

  • 求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);
};
//函數表達式需放到調用前6鞲ぁ畔塔!
  • 如下代碼輸出什么? 寫出作用域鏈查找過程偽代碼

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(),開始執(zhí)行:
console.log(a),,此時fncontextAO中a未被賦值沾鳄,輸出undefined译荞;
a = 5;
console.log(a)吞歼,此時fncontextAO中a被賦值為5塔猾,輸出5丈甸;
a++睦擂,fncontextAO中a變?yōu)?;
var a淘正,因為a已經存在鸿吆,故無意義惩淳;
fn3(),執(zhí)行fn3()恕刘,進入fn3context褐着;
console.log(a)含蓉,goblecontextAO中馅扣,a=1着降,故輸出1任洞;
a=200交掏,goblecontextAO中a變?yōu)?00盅弛;
fn2,執(zhí)行fn2()见秽,進入fn2context解取;
console.log(a)肮蛹,fncontextAO中伦忠,a=6,故輸出6气忠;
a=20旧噪,fncontextAO中淘钟,a變?yōu)?0米母;
console.log(a)毡琉,fncontextAO中桅滋,a為20芍碧,故輸出20笋鄙;
fn執(zhí)行完畢萧落;
console.log(a)找岖,goblecontextAO中许布,a為200蜜唾,故輸出200袁余;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末颖榜,一起剝皮案震驚了整個濱河市掩完,隨后出現的幾起案子且蓬,更是在濱河造成了極大的恐慌恶阴,老刑警劉巖存淫,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桅咆,死亡現場離奇詭異岩饼,居然都是意外死亡籍茧,警方通過查閱死者的電腦和手機寞冯,發(fā)現死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門吮龄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漓帚,“玉大人,你說我怎么就攤上這事迅皇⌒耄” “怎么了挺据?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵扁耐,是天一觀的道長婉称。 經常有香客問我王暗,道長俗壹,這世上最難降的妖魔是什么绷雏? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮期吓,結果婚禮上倾芝,老公的妹妹穿的比我還像新娘蛀醉。我一直安慰自己拯刁,他們只是感情好垛玻,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布亿驾。 她就那樣靜靜地躺著账嚎,像睡著了一般郭蕉。 火紅的嫁衣襯著肌膚如雪召锈。 梳的紋絲不亂的頭發(fā)上涨岁,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天蹬铺,我揣著相機與錄音秉撇,去河邊找鬼。 笑死赴邻,一個胖子當著我的面吹牛姥敛,可吹牛的內容都是我干的彤敛。 我是一名探鬼主播墨榄,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼之剧!你這毒婦竟也來了背稼?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贰盗,沒想到半個月后童太,有當地人在樹林里發(fā)現了一具尸體书释,經...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了熄阻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秃殉。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡钾军,死狀恐怖吏恭,靈堂內的尸體忽然破棺而出樱哼,到底是詐尸還是另有隱情唇礁,我是刑警寧澤盏筐,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布琢融,位于F島的核電站漾抬,受9級特大地震影響纳令,放射性物質發(fā)生泄漏平绩。R本人自食惡果不足惜捏雌,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望满败。 院中可真熱鬧算墨,春花似錦米同、人聲如沸面粮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽粱胜。三九已至焙压,卻和暖如春涯曲,著一層夾襖步出監(jiān)牢的瞬間幻件,已是汗流浹背绰沥。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疟位,地道東北人甜刻。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像祥绞,于是被迫代替她去往敵國和親蜕径。 傳聞我的和親對象是個殘疾皇子败京,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內容

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