JavaScript函數(shù)(二)

目錄

1.函數(shù)的聲明

2.函數(shù)的屬性和方法

3.函數(shù)的作用域

4. 函數(shù)的重載

5.閉包知識點

6.小結


關于函數(shù)钦奋,可以從以下3個方面去理解:
首先座云,數(shù)據(jù)類型上看:函數(shù)在JavaScript中是一種數(shù)據(jù)類型,是對象的一種付材;
其次朦拖,從功能上看:函數(shù)本質(zhì)上是一段反復調(diào)用的代碼塊;
最后厌衔,從地位上看:函數(shù)在JavaScript中和其他基本數(shù)據(jù)類型一樣璧帝,可以作為參數(shù)和賦值,是“第一等公民”


1.函數(shù)的聲明

聲明函數(shù)的方式有三種:

1.聲明式
function fn(){
  console.log(1)
}
fn()//1
2.表達式
var fn = function(args){
    console.log(args)
}
fn(a)//a
3.構造函數(shù)式
var fn =  new Function("arg1","arg2","return arg1+arg2")
fn(1,2)//3

函數(shù)本質(zhì)上是對象的一種葵诈,所以函數(shù)名保存的實際上是指向函數(shù)對象的指針裸弦,第3種構造函數(shù)的方法對于理解“函數(shù)是對象,函數(shù)名是指針”的概念更加直觀作喘,但是第3種方法解析效率較低而且書寫不簡潔理疙,所以一般不用構造函數(shù)方法去聲明函數(shù);
當聲明式和表達式同時聲明同一個函數(shù)時泞坦,表達式會覆蓋聲明式窖贤,原因是函數(shù)作為變量在js解析階段進行變量提升,聲明式和表達式都會提升至當前作用域頭部贰锁,然后表達式會重新為fn賦值赃梧,從而覆蓋聲明式定義的函數(shù);

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

關于return語句的理解豌熄,如果聲明的函數(shù)沒有return語句授嘀,則默認return undefined,否則返回定義的值锣险;函數(shù)會在執(zhí)行完return語句后就立即退出蹄皱,位于return語句的代碼將不會執(zhí)行;

var a  = function(){
    console.log(1)
}
var b = function(){
    return 2;
}
a() === undefined//true

2.函數(shù)的屬性和方法

函數(shù)作為一個對象芯肤,同樣擁有屬性和方法巷折,下面主要歸納一下比較常用和重要的屬性和方法:


  • name屬性:返回該函數(shù)名的字符串;
  • length屬性:返回形參的個數(shù)崖咨,即預期傳入?yún)?shù)的個數(shù)锻拘;
function fn (a,b){
    console.log(fn.name)
    console.log(fn.length)
}
fn()
//"fn"  
//2
  • arguments對象:是包含傳入函數(shù)實參的類數(shù)組對象,只有在函數(shù)執(zhí)行階段并且存在參數(shù)才會有值,未調(diào)用函數(shù)是為null击蹲;
function fn (a,b){
  console.log(arguments)
}
fn(1,2)
//[1,2]


arguments對象的length屬性代表實參的個數(shù)署拟,注意和函數(shù)的length屬性的區(qū)別婉宰,函數(shù)的length代表形參的個數(shù),arguments的length屬性代表實參個數(shù)芯丧;
arguments對象有一個callee屬性芍阎,返回arguments對象所在的函數(shù)指針

可以利用callee實現(xiàn)函數(shù)的遞歸缨恒,例如累加或階乘操作:

function increment(arg){
  if(arg === 1){
    return 1
  }
  return arg+arguments.callee(arg-1)
}
function increMultipler(arg){
  if(arg === 1){
    return 1
  }
  return arg*arguments.callee(arg-1)
}


這里另外提一個函數(shù)的caller屬性,該屬性保存調(diào)用當前函數(shù)的函數(shù)的引用轮听,注意的是如果在全局作用域下讀取該屬性骗露,值為null,因為頂層對象在瀏覽器中為window不是函數(shù)血巍;

function outer(){
  inner();
}
function inner(){
  console.log(arguments.callee.caller)
}
outer();
  • this對象:代表函數(shù)執(zhí)行時的環(huán)境對象萧锉,簡單的說就是誰調(diào)用了該函數(shù),this的指向是動態(tài)的述寡,只有在函數(shù)調(diào)用時this對象才能確定柿隙;
//在瀏覽器全局環(huán)境下,即window對象下
var print = function(){
      console.log(this)
 }
print()//this指向Window鲫凶,因為這是Window對象調(diào)用了print方法
//在特定對象的環(huán)境下
var o = {
    print: function(){
      console.log(this)
  }
}
o.print()//this指向o禀崖,因為這是o對象調(diào)用print方法

函數(shù)提供callapplybind3種方法可以改變this對象螟炫;

1.call方法
function fn(){
    return this
}
var o = {}
fn() === this//true波附,this指向window對象
fn.call(o) === o//true,this指向o對象
//call方法還可以傳入?yún)?shù)昼钻;
function add(x,y){
  return x+y
}
add.call(null,1,2)
2.apply方法掸屡,與call不同的是apply傳入的參數(shù)為數(shù)組
var arr = [1,2]
function add(x,y){
  return x+y
}
add.apply(null,arr)

實際上,apply和call的區(qū)別只在于傳遞參數(shù)的不同然评,它們真正強大的地方在于能夠擴充函數(shù)賴以運行的作用域仅财,比如slice函數(shù)原本只存在于數(shù)組當中,當中通過使用call方法碗淌,可以實現(xiàn)不同作用域下調(diào)用該方法盏求;

function fn(a,b){
      console.log(Array.prototype.slice.call(arguments))
 }
fn(1,2)//[1,2]

bind方法會創(chuàng)建一個函數(shù)實例,并將該函數(shù)的this對象綁定到傳入該方法的參數(shù)贯莺;

function fn(){
    return this
}
var o = {}
var newFn =fn.bind(o) 
newFn() === o//true

更多this的相關介紹风喇,詳見【what's this???】

3.函數(shù)的作用域

作用域指的是變量存在的范圍,作用域可分為全局作用域和局部作用域缕探,變量在全局范圍可訪問到魂莫;局部作用域由函數(shù)所構造,變量只能在函數(shù)內(nèi)部可訪問到爹耗;

var a =1//a處于全局作用域

function fn(){
   var a = 2//a處于局部作用域耙考,外部無法訪問谜喊;
  return a;
}
a//1
fn()//2

值的注意的是,函數(shù)執(zhí)行時所在的作用域是定義時所在的作用域倦始,而不是調(diào)用時所在的作用域斗遏;

var a = 1;
function fn(){
  console.log(a)
}
function fn2(){
  var a = 2;
  fn()
}
fn2()//1

4.函數(shù)的重載

JavaScript的函數(shù)無法實現(xiàn)重載,所謂重載是為同一個函數(shù)編寫兩個不同的定義簽名(接受的參數(shù)的類型和數(shù)量)鞋邑;
JavaScript函數(shù)之所以沒有重載诵次,是因為其參數(shù)受包含零個或多個值的arguments對象表示的,也就是說函數(shù)不存在函數(shù)簽名的特性枚碗;

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

上述代碼聲明了同一個函數(shù)逾一,雖然二者的函數(shù)簽名不同,但是js引擎在解析時會把后面的函數(shù)覆蓋前面的函數(shù)肮雨;
實際上遵堵,在JavaScript中參數(shù)在內(nèi)部是用arguments對象存儲,它不介意你定義時設定1個怨规、2個或多個參數(shù)陌宿,它只在意函數(shù)在執(zhí)行階段時傳遞的實際參數(shù);



函數(shù)定義時設定參數(shù)唯一目的是為了對開發(fā)者編寫代碼和維護更加友好波丰,即使你不定義函數(shù)簽名照樣可以引用參數(shù)壳坪;



但是,一般在定義函數(shù)時是建議命名形參的呀舔,這樣更加符合編程規(guī)范弥虐;
可以利用JavaScript函數(shù)的以上特性,模擬出函數(shù)的重載功能媚赖;
function fn(){
  if(arguments.length === 1){
      return arguments[0]
  };
  if(arguments.length ===2){
      return arguments[0]+arguments[1]    
  }
}
fn(5);
fn(5,10)

5. 閉包知識點

關于閉包的知識點霜瘪,將會單獨開一章節(jié)詳談,具體請看《JavaScript閉包(三)》


6.小結

通過《JavaScript函數(shù)(二)》惧磺,我們大致了解關于函數(shù)的知識點如下:

  • 函數(shù)本質(zhì)上是一段反復調(diào)用的代碼塊颖对,是對象的一種,在js中作為“第一等公民”磨隘,可以賦值和傳參缤底;
  • 函數(shù)聲明的方法有3種:聲明式、表達式和構造函數(shù)式番捂;其中構造函數(shù)是能夠直觀理解函數(shù)的“函數(shù)是對象个唧,函數(shù)名是指針”的概念;當表達式和聲明式同時聲明同名函數(shù)時设预,表達式會覆蓋聲明式徙歼,原因是變量提升的作用;
  • 函數(shù)作為對象,同樣具有屬性和方法魄梯;name返回該函數(shù)名的字符串桨螺,length返回形參的個數(shù);
  • arguments對象是包含傳入函數(shù)的實參的類數(shù)組對象酿秸,只有在執(zhí)行階段該對象才有值灭翔,未調(diào)用函數(shù)時為null,arguments.length表示實參的個數(shù)辣苏,arguments.callee返回arguments對象所在的函數(shù)的指針肝箱;
  • 函數(shù)的caller返回調(diào)用當前函數(shù)的函數(shù)的指針,在全局作用域下讀取該屬性為null稀蟋;
  • this對象代表當前函數(shù)執(zhí)行時的環(huán)境對象狭园,this對象只有在函數(shù)執(zhí)行階段才能確定;
  • 可以使用call糊治、apply和bind改變this的指向;call和apply的區(qū)別在于二者傳遞的參數(shù)不同罚舱,call為零散的數(shù)據(jù)井辜,apply為數(shù)組,二者最大的用處是擴展函數(shù)的作用域管闷;bind方法可以返回一個函數(shù)的實例粥脚,并綁定this對象至傳入bind的參數(shù);
  • 函數(shù)可以開辟一個獨立的作用域包个,這使得js當中經(jīng)典的閉包得以實現(xiàn)提供可能性刷允;此外,函數(shù)執(zhí)行時所在的作用域是在定義時所在的作用域碧囊,而不是調(diào)用時所在的作用域树灶;
  • JavaScript的函數(shù)是無法實現(xiàn)重載功能的,但可以通過函數(shù)的結合arguments對象的特性模擬出重載的效果糯而;

參考資料

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末天通,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子熄驼,更是在濱河造成了極大的恐慌像寒,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓜贾,死亡現(xiàn)場離奇詭異诺祸,居然都是意外死亡,警方通過查閱死者的電腦和手機祭芦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門筷笨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事奥秆⊙放恚” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵构订,是天一觀的道長侮叮。 經(jīng)常有香客問我,道長悼瘾,這世上最難降的妖魔是什么囊榜? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮亥宿,結果婚禮上卸勺,老公的妹妹穿的比我還像新娘。我一直安慰自己烫扼,他們只是感情好曙求,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著映企,像睡著了一般悟狱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堰氓,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天挤渐,我揣著相機與錄音,去河邊找鬼双絮。 笑死浴麻,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的囤攀。 我是一名探鬼主播软免,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抚岗!你這毒婦竟也來了或杠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤宣蔚,失蹤者是張志新(化名)和其女友劉穎向抢,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胚委,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡挟鸠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亩冬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艘希。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡硼身,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出覆享,到底是詐尸還是另有隱情佳遂,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布撒顿,位于F島的核電站丑罪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凤壁。R本人自食惡果不足惜吩屹,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拧抖。 院中可真熱鬧煤搜,春花似錦、人聲如沸唧席。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淌哟。三九已至厌衙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绞绒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工榕暇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蓬衡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓彤枢,卻偏偏與公主長得像狰晚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缴啡,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 三壁晒、閉包和高階函數(shù) 3.1 閉包 3.1.1 變量的作用域 所謂變量的作用域,就是變量的有效范圍业栅。通過作用域的劃分...
    梁同學de自言自語閱讀 1,450評論 0 6
  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品秒咐,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式碘裕。簡單...
    舟漁行舟閱讀 7,729評論 2 17
  • 第一部分 準入訓練 第1章 進入忍者世界 js開發(fā)人員通常使用js庫來實現(xiàn)通用和可重用的功能携取。這些庫需要簡單易用,...
    如201608閱讀 1,345評論 1 2
  • 繼承 一帮孔、混入式繼承 二雷滋、原型繼承 利用原型中的成員可以被和其相關的對象共享這一特性,可以實現(xiàn)繼承,這種實現(xiàn)繼承的...
    magic_pill閱讀 1,054評論 0 3
  • 其實我很喜歡你 像天上的云飄不進海里 看到倒影還空歡喜
    Maureenife閱讀 212評論 0 0