js函數(shù)初探

基本概念

函數(shù)的定義就是一段可以反復(fù)調(diào)用的代碼塊痪欲,可以接受參數(shù),并且可以根據(jù)不同參數(shù)返回不同的返回值攻礼。js的函數(shù)屬于復(fù)雜類型业踢,屬于Object類型,但是它有自己的構(gòu)造函數(shù)礁扮,且能夠使用typeof運(yùn)算符返回function知举。js中不指定函數(shù)返回值,默認(rèn)返回undefined太伊。函數(shù)的原型鏈經(jīng)過Function.prototype雇锡。

函數(shù)聲明

函數(shù)聲明的方式目前已知的有五種。

  • function fn(a,b){return a+b} function命令聲明具名函數(shù)
  • var fn = function(a,b){return a+b} function命令聲明匿名函數(shù)僚焦,賦值給變量fn
  • var fn = function f(a,b){return a+b} function命令聲明具名函數(shù)锰提,且賦值給fn
  • var fn = new Function('a','b','return a+b') Function構(gòu)造函數(shù)聲明匿名函數(shù),賦值給fn
  • var fn = (a,b)=>{return a+b} 箭頭函數(shù)聲明一個匿名函數(shù),賦值給fn

比較常用的聲明方式是第一立肘,第二边坤,第五種。js的函數(shù)聲明方面還存在著一個比較反常規(guī)的地方谅年,那就是函數(shù)的name屬性茧痒。請看以下示例:

//具名函數(shù)
function fn(a,b){return a+b}
console.log(fn.name) //'fn'
//匿名函數(shù)賦值給變量fn
var fn = function(a,b){return a+b}
console.log(fn.name) //'fn'
//具名函數(shù)賦值給變量fn
var fn = function f(a,b){return a+b}
console.log(fn.name) //'f'
//Function構(gòu)造函數(shù)聲明函數(shù),賦值給fn
var fn = new Function('a','b','return a+b')
console.log(fn.name) //'anonymous'(匿名)
//箭頭函數(shù)聲明一個匿名函數(shù)融蹂,賦值給fn
var fn = (a,b)=>{return a+b}
console.log(fn.name) //'fn'

由此看出旺订,js函數(shù)的聲明與name屬性也有很強(qiáng)的不一致性,容易讓人產(chǎn)生誤解超燃。需要刻意的去記憶区拳。

函數(shù)提升

函數(shù)可以向變量一樣提升到代碼頭部。

fn(); //undefined
var a = 0;
function fn(){
    console.log(a);
}

之所以以上代碼沒有報錯意乓,是因為樱调,整個function被提升到代碼頭部了。以上代碼相當(dāng)于:

var a;
function fn(){
    console.log(a);
}
fn(); //undefined
a = 0;

函數(shù)的調(diào)用

函數(shù)的調(diào)用方式一般有三種直接調(diào)用洽瞬,使用call,使用apply;

直接調(diào)用

函數(shù)直接調(diào)用,傳入?yún)?shù)业汰,函數(shù)內(nèi)部執(zhí)行伙窃,返回需要返回的值。

function fn(){console.log('直接調(diào)用')}
fn()//直接調(diào)用

call方式調(diào)用

call方式調(diào)用以也是比較常見的調(diào)用方式样漆,它接收的第一個參數(shù)內(nèi)部this指定的值为障,若不傳即為undefined,內(nèi)部this自動轉(zhuǎn)為window對象放祟,若使用嚴(yán)格模式use strict鳍怨,則內(nèi)部thisundefined。從第二個參數(shù)開始為函數(shù)所要接收的參數(shù)跪妥。示例:

function fn(a,b){
    console.log(this,a,b);
}
fn.call();  //window undefined undefined
fn.call(undefined,1,2); //window 1 2
fn.call({ff:'f'},1,2);  //{ff:'f'} 1 2

apply方式調(diào)用

apply方式調(diào)用與call基本一致鞋喇,只是接收的參數(shù)有一點區(qū)別,第一個參數(shù)沒差別眉撵,都是指定內(nèi)部this變量侦香,第二個參數(shù),apply接收一個數(shù)組或者偽數(shù)組對象纽疟。示例:

function fn(a,b){
    console.log(this,a,b);
}
fn.apply(); //window undefined undefined
fn.apply(undefined,[1,2]);  //window 1 2
fn.apply({ff:'f'},[1,2]);   //{ff:'f'} 1 2

this

關(guān)于thisjs語言設(shè)計者布蘭登·艾克為了滿足當(dāng)時的需求(長得像Java)而加入的一個屬性罐韩,this指代了屬性和方法'當(dāng)前'所在的對象。剛剛提過污朽,使用call或者apply可以指代調(diào)用函數(shù)時內(nèi)部的this對象散吵。

構(gòu)造函數(shù)中的this

構(gòu)造函數(shù)中的this指代了當(dāng)前的實例。示例:

function F(){
    this.name = 'ff';
    this.t = this;
}
構(gòu)造函數(shù)中的this

函數(shù)中的this

函數(shù)中的this只有在函數(shù)被調(diào)用時,才有意義矾睦。當(dāng)調(diào)用函數(shù)時晦款,我們把調(diào)用方式改為call的形式調(diào)用,可以輕松確定顷锰。示例:

var obj = {
    a: 1,
    b: function(){
        console.log(this)
    }
}
obj.b() // {a:1,b:function(){console.log(this)}}
//等價于 obj.b.call(obj) .call前面的第二個參數(shù)開始往前柬赐,即為函數(shù)內(nèi)部的this

其他情況下的this

在其他情況下,this指向當(dāng)前作用域的對象官紫。示例:

var obj = {
    a: '0',
    b: this
}
obj.b // window
var obj = {
    a: '0',
    b: {
        t:this
    }
}
obj.b.t // window

arguments

arguments可以接收傳給函數(shù)的所有參數(shù)肛宋。arguments本身是一個偽數(shù)組。示例:

function fn(){console.log(arguments)}
fn(1,2,3,'d') // [1,2,3,'d']

調(diào)用棧(call stack)

call stack 是指函數(shù)在執(zhí)行時束世,內(nèi)部的處理方式酝陈。可以幫助理解毁涉,函數(shù)在執(zhí)行過程中沉帮,怎么一步一步執(zhí)行,并且返回到之前的位置的贫堰。請看簡單的示例

調(diào)用棧

作用域

作用域是一個比較難理解的概念穆壕,但是如果結(jié)合數(shù)據(jù)結(jié)構(gòu)去理解,也就直觀了很多其屏。目前喇勋,js中的作用域只有全局作用域window和函數(shù)作用域。

  1. 作用域是一個樹形結(jié)構(gòu)
  2. 若當(dāng)前作用域無變量名所對應(yīng)的變量偎行,則去父作用域中尋找川背,直到根節(jié)點(全局作用域)。若存在則去值蛤袒,若不存在熄云,則取undefined。這就是作用域的就近原則
  3. 在作用域中確定某個變量的值妙真,第一步要做的就是變量提升缴允,然后再去分析變量的值。

典型例題

第一題

var a = 1
function f1(){
    console.log(a)
    var a = 2 
}
f1.call() //undefined

分析:

  1. 變量提升,聲明提升
var a
function f1(){
    var a
    console.log(a)
    a = 2
}
a = 1
f1.call()
  1. 分析作用域
    因為在f1()console.log(a)的作用域是f1珍德,所以在內(nèi)部console.log(a)之前的代碼中尋找a癌椿,發(fā)現(xiàn)aundefined

第二題

var a = 1
function f1(){
    var a = 2
    f2.call()
}
function f2(){
    console.log(a)
}
f1.call()   //1

分析:

  1. 變量提升,提升聲明
var a
function f1(){
    var a
    a = 2
    f2.call()
}
function f2(){
    console.log(a)
}
a = 1
f1.call()
  1. 分析作用域
    因為f1()執(zhí)行時菱阵,內(nèi)部執(zhí)行f2(),而f2()在全局作用域中踢俄。這時f2()中的console.log(a)之前沒有變量a,沿著作用域鏈向上尋找,在全局作用域中有變量a晴及,那么f2()中的console.log(a)即為全局的變量a都办。在執(zhí)行f2()之前,a已經(jīng)被賦值為1,所以打印出1琳钉。

第三題

//有6個li
var liTags = document.querySelectorAll('li')
for(var i = 0; i<liTags.length; i++){
    liTags[i].onclick = function(){
        console.log(i) // 點擊第3個 li 時势木,打印 2 還是打印 6?
    }
}

分析:

  1. 變量提升歌懒,提升聲明
var liTags
var i
liTags = document.querySelectorAll('li')
for(i=0;i<liTags.length;i++){
    liTags[i].onclick = function(){
        console.log(i)
    }
}
  1. 當(dāng)點擊第三li的時候啦桌,會執(zhí)行函數(shù)function(){console.log(i)}。因為i變量在當(dāng)前函數(shù)中并不存在及皂,所以要去父作用域(全局作用域)尋找甫男,找到了全局的i,這時循環(huán)已經(jīng)結(jié)束,而i的值已經(jīng)變?yōu)?code>liTags.length验烧。所以打印出6

閉包

閉包就是一個函數(shù)是用來它范圍外的變量板驳,那么 這個函數(shù) + 這個變量 就組成了 閉包。示例:

function a(){
    var aa = 'aa'
    function b(){
        bb = aa;
    }
}

總結(jié)

函數(shù)是整個js的核心碍拆,必須完全弄明白若治。這對以后的工作和提升會有很大的影響。再者就是數(shù)據(jù)結(jié)構(gòu)是可以幫助理解抽象化知識感混,使抽象化的知識在大腦中形成一個更加明確的結(jié)構(gòu)端幼。
本文僅供交流與學(xué)習(xí)使用,轉(zhuǎn)載請注明出處弧满。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末婆跑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子谱秽,更是在濱河造成了極大的恐慌洽蛀,老刑警劉巖摹迷,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疟赊,死亡現(xiàn)場離奇詭異,居然都是意外死亡峡碉,警方通過查閱死者的電腦和手機(jī)近哟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲫寄,“玉大人吉执,你說我怎么就攤上這事〉乩矗” “怎么了戳玫?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長未斑。 經(jīng)常有香客問我咕宿,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任府阀,我火速辦了婚禮缆镣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘试浙。我一直安慰自己董瞻,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布田巴。 她就那樣靜靜地躺著钠糊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪固额。 梳的紋絲不亂的頭發(fā)上眠蚂,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機(jī)與錄音斗躏,去河邊找鬼逝慧。 笑死,一個胖子當(dāng)著我的面吹牛啄糙,可吹牛的內(nèi)容都是我干的笛臣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼隧饼,長吁一口氣:“原來是場噩夢啊……” “哼沈堡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起燕雁,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诞丽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拐格,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僧免,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年捏浊,在試婚紗的時候發(fā)現(xiàn)自己被綠了懂衩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡金踪,死狀恐怖浊洞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胡岔,我是刑警寧澤法希,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站靶瘸,受9級特大地震影響苫亦,放射性物質(zhì)發(fā)生泄漏尖淘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一著觉、第九天 我趴在偏房一處隱蔽的房頂上張望村生。 院中可真熱鬧,春花似錦饼丘、人聲如沸趁桃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卫病。三九已至,卻和暖如春典徘,著一層夾襖步出監(jiān)牢的瞬間蟀苛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工逮诲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留帜平,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓梅鹦,卻偏偏與公主長得像裆甩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子齐唆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

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

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)嗤栓,也就是一...
    悟名先生閱讀 4,151評論 0 13
  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,835評論 0 38
  • 第一部分 準(zhǔn)入訓(xùn)練 第1章 進(jìn)入忍者世界 js開發(fā)人員通常使用js庫來實現(xiàn)通用和可重用的功能。這些庫需要簡單易用箍邮,...
    如201608閱讀 1,354評論 1 2
  • 繼承 一茉帅、混入式繼承 二、原型繼承 利用原型中的成員可以被和其相關(guān)的對象共享這一特性锭弊,可以實現(xiàn)繼承堪澎,這種實現(xiàn)繼承的...
    magic_pill閱讀 1,064評論 0 3
  • 今日覺察: 當(dāng)我想到一個同事氣喘吁吁給我打電話,我覺察到她很生氣廷蓉,是她的什么需要沒有得到滿足呢全封? 我說聽起來你很生...
    瑞成大哥閱讀 236評論 0 0