JavaScript基礎(chǔ)知識(shí)點(diǎn)解讀—函數(shù)

說起ECMAScript中什么最有意思,我想那莫過于函數(shù)了——而有意思的根源疲扎,則在于函數(shù)實(shí)際上是對(duì)象纪隙。每個(gè)函數(shù)都是Function類型的實(shí)例,而且都與其他引用類型一樣具有屬性和方法等恐。由于函數(shù)是對(duì)象,因此函數(shù)名實(shí)際上也是一個(gè)指向函數(shù)對(duì)象的指針,不會(huì)與某個(gè)函數(shù)綁定课蔬。

如何理解函數(shù)是對(duì)象囱稽?

JavaScript基礎(chǔ)知識(shí)點(diǎn)解讀—對(duì)象這篇文章的后半部分已經(jīng)介紹過JavaScript中函數(shù)和對(duì)象之間的關(guān)系。

創(chuàng)建函數(shù)

有三種基本的函數(shù)創(chuàng)建方式二跋。

// 1 使用function聲明
function add(num1, num2) {
  return num1 + num2;
}

// 2 函數(shù)表達(dá)式
var add = function(num1, num2) {
  return num1 + num2;
}

// 3 使用new Function創(chuàng)建
var add = new Function("num1", "num2", "return num1 + num2"); //不推薦

創(chuàng)建函數(shù)的時(shí)候一定要理解在JavaScript中函數(shù)沒有重載战惊。

什么是重載?

面向?qū)ο缶幊陶Z(yǔ)言的三大基本特征:封裝同欠,繼承和多態(tài)。

實(shí)現(xiàn)多態(tài)的兩種方式:
覆蓋(重寫)横缔,子類重新定義父類中的虛函數(shù)
重載铺遂,是指允許存在多個(gè)同名函數(shù)茎刚,而這些函數(shù)的參數(shù)表不同(或許參數(shù)個(gè)數(shù)不同襟锐,或許參數(shù)類型不同,或許兩者都不同)膛锭。

更多的面向?qū)ο笳Z(yǔ)言的特性就不做更多的解釋粮坞。一定要記住JavaScript中沒有重載。為什么初狰?因?yàn)槭褂胒unction聲明的函數(shù)后面聲明的函數(shù)會(huì)把前面聲明的函數(shù)覆蓋掉莫杈,同一個(gè)函數(shù)名只保留一個(gè)最后一個(gè)定義的函數(shù)體。使用var聲明的函數(shù)表達(dá)同樣存在覆蓋的情況奢入,看下面例子筝闹。

// 1 使用function聲明函數(shù)
function addSomeNumber(num) {
  return num + 100;
}
function addSomeNumber(num) {
  return num + 200;
}
var result = addSomeNumber(100); // 300

// 使用函數(shù)表達(dá)式
var addSomeNumber = function(num) {
  return num + 100;
};
addSomeNumber = function(num) {
  return num + 100;
};
var result = addSomeNumber(100); // 300
函數(shù)聲明和函數(shù)表達(dá)式

思考!函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別腥光?

函數(shù)聲明有函數(shù)提升的作用关顷,即解析器會(huì)率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用(可以訪問)武福。至于函數(shù)表達(dá)式议双,則必須等到解析器執(zhí)行到它所在的代碼行,才會(huì)真正被解釋執(zhí)行捉片。

// 函數(shù)聲明
sum(10, 10); // 20
function sum(num1, num2) {
  return num1 + num2;
}

// 函數(shù)表達(dá)式
sum(10, 10); // 報(bào)錯(cuò) Uncaught TypeError: sum is not a function
var sum = function(num1, num2) {
  return num1 + num2;
}
作為值的函數(shù)

在ECMAScript中平痰,函數(shù)名本身就是變量,所以函數(shù)也可以作為值來使用伍纫。比如下面的程序觉增。

function callSomeFunction(someFn, someArgument) {
  return someFn(someArgument);
}

function add10(num) {
  return num + 10;
}

var result = callSomeFunction(add10, 10);
console.log(result); // 20

這里記住函數(shù)名也是變量,和普通變量的區(qū)別是在函數(shù)名變量后面加上“()”后可以執(zhí)行即可翻斟。

函數(shù)內(nèi)部屬性

在函數(shù)內(nèi)部有兩個(gè)特殊的對(duì)象:argumentsthis逾礁。

arguments,是一個(gè)類數(shù)組對(duì)象,它里面存的是傳入函數(shù)中的所有參數(shù)嘹履。這個(gè)對(duì)象還有一個(gè)名叫callee的屬性腻扇,該屬性是一個(gè)指針,指向擁有這個(gè)arguments對(duì)象的函數(shù)砾嫉。請(qǐng)看下面這個(gè)非常經(jīng)典的階乘函數(shù)幼苛。

function factorial(num) {
  if(num <= 1) {
    return 1;
  } else {
    return num * factorial(num - 1);
  }
}

定義階乘函數(shù)一般都要用到遞歸算法;如上面的代碼所示焕刮,在函數(shù)有名字且名字以后也不會(huì)變的情況下舶沿,這樣定義沒有問題。問題是這個(gè)函數(shù)的執(zhí)行與函數(shù)名factorial緊緊耦合在了一起配并。想要消除這種緊密耦合的現(xiàn)象括荡,可以像下面這樣使用arguments.callee。

function factorial(num) {
  if (num <= 1){
    return 1;
  } else {
    return num * arguments.callee(num - 1);
  }
}

使用arguments.callee到底有什么作用呢溉旋?請(qǐng)看下面的程序畸冲。

var trueFactorial = factorial;
factorial = funciton() { return 0; };
console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0

將factorial函數(shù)的指針賦值給trueFactorial 后,即使原函數(shù)factorial被重新定義观腊,函數(shù)trueFactorial依然可以實(shí)現(xiàn)階乘的功能邑闲。

this,是函數(shù)內(nèi)部的另一個(gè)特殊對(duì)象梧油。this引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對(duì)象苫耸。說到this,頓時(shí)感覺有說不完的話要表達(dá)了儡陨。

思考鲸阔!在程序執(zhí)行的過程中,this到底指向(代表)了什么迄委?

請(qǐng)看下面的程序褐筛,程序有些長(zhǎng),也可以先看下面this指向的規(guī)律后再分析程序叙身。

// 1
var color = "red";
var obj = {
  color: "blue"
};
function getColor() {
  console.log(this.color);
};
getColor(); // "red"
obj.getColor = getColor;
obj.getColor(); // "blue"

// 2
function colorFull() {
  var color = "yellow";
  function getColor() {
    console.log(this.color);
  }
  getColor(); // "red"
}
colorFull();

// 3
var name = "window";
var object = {
  name: "object",
  sayName: function() {
    function innerFunction() {
      console.log(this.name); // "window"
    }
    innerFunction();
    return function() {
      console.log(this.name); // "window"
    }
  }
}
object.sayName()();
// 4
var obj = {
  value: 37,
  fun: function() {
    return this.value;
  }
}
var fun1 = obj.fun;
console.log(fun1()); // undefined
// 原型鏈中的this
var obj = {
  a: 2,
  b: 5,
  fun: function() {
    return this.a + this.b;
  }
}
var o = Object.create(obj);
o.a = 1;
o.b = 2;
console.log(o.fun()); // 3
// 構(gòu)造函數(shù)中的this
function C() {
  this.a = 1;
}
var o1 = new C();
console.log(o1.a); // 1

function C2() {
  this.a = 2;
  return {a: 3}
}
var o2 = new C2();
console.log(o2.a); // 3 好詭異

從上面的程序中我們可以得出使用this的幾條規(guī)律渔扎。

1. this的指向是在函數(shù)執(zhí)行時(shí)候確定的。

2. 函數(shù)如果有直接調(diào)用者對(duì)象(如object.fun())信轿,那么函數(shù)內(nèi)部的this執(zhí)行該調(diào)用者對(duì)象(即object)晃痴;如果函數(shù)沒有直接調(diào)用者對(duì)象,那么函數(shù)內(nèi)部的this對(duì)象指向的是window對(duì)象财忽。原型鏈中的方法的this仍然指向調(diào)用它的對(duì)象

3. 構(gòu)造函數(shù)的this與被創(chuàng)建的新對(duì)象綁定倘核,當(dāng)構(gòu)造器返回的默認(rèn)值是一個(gè)this引用的對(duì)象是,可以手動(dòng)設(shè)置返回其他的對(duì)象即彪,如果返回值不是一個(gè)對(duì)象紧唱,則返回this。

上面是在es5中this的使用,在es6中新增了箭頭函數(shù)漏益。箭頭函數(shù)中的this指向與上述有所不同蛹锰。請(qǐng)看下面的程序。

var name = "window";
var object = {
  name: "objcet",
  sayName: function() {
    return () => {
      console.log(this.name); // "object"
    }
  }
}
object.sayName()();

var anotherObject = {
  name: "anotherObject"
}
/*
object.sayName()執(zhí)行完后返回的箭頭函數(shù)里面的this已經(jīng)指向了object绰疤,此處的this已經(jīng)固定不會(huì)被更改了
*/
object.sayName().call(anotherObject); // "object"

/*
object.sayName只是一個(gè)函數(shù)指針铜犬,該函數(shù)并未執(zhí)行,其內(nèi)部嵌套的箭頭函數(shù)中的this
*/
object.sayName.call(anotherObject)(); // "anotherObject"

上面的es6中的箭頭函數(shù)轉(zhuǎn)換成es5轻庆,其實(shí)是下面這樣的癣猾。

var name = "window";
var object = {
  name: "object",
  sayName: function() {
    var _this = this;
    return function() {
      console.log(_this.name);
    }
  }
}

箭頭函數(shù)不綁定this,它會(huì)捕捉其所在(即定義的位置)上下文的this值作為自己的this值

var adder = {
  base: 1,
  add: function(a) {
    var f = v => v + this.base; // 此時(shí)已經(jīng)確定了this的值即adder
    return f(a);
  }
  addThruCall: funcntion(a) {
    var f = v => v + this.base;
    var b = {
      base: 2
    }
    return f.call(b, a);
  }
};
console.log(adder.add(1)); // 2
console.log(adder.addThruCall(1)) // 仍然 2余爆,其內(nèi)部的this并沒有因?yàn)閏all() 而改變纷宇,其this值仍然為函數(shù)inFun的this值,指向?qū)ο骯dder

call(), apply(), bind()方法對(duì)于箭頭函數(shù)來說只是傳入?yún)?shù)龙屉,并不影響this的值呐粘。

參考文章

this 指向詳細(xì)解析(箭頭函數(shù))

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末满俗,一起剝皮案震驚了整個(gè)濱河市转捕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唆垃,老刑警劉巖五芝,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異辕万,居然都是意外死亡枢步,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門渐尿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來醉途,“玉大人,你說我怎么就攤上這事砖茸“妫” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵凉夯,是天一觀的道長(zhǎng)货葬。 經(jīng)常有香客問我,道長(zhǎng)劲够,這世上最難降的妖魔是什么震桶? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮征绎,結(jié)果婚禮上蹲姐,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好淤堵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布寝衫。 她就那樣靜靜地躺著,像睡著了一般拐邪。 火紅的嫁衣襯著肌膚如雪慰毅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天扎阶,我揣著相機(jī)與錄音汹胃,去河邊找鬼。 笑死东臀,一個(gè)胖子當(dāng)著我的面吹牛着饥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惰赋,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宰掉,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了赁濒?” 一聲冷哼從身側(cè)響起轨奄,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拒炎,沒想到半個(gè)月后挪拟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡击你,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年玉组,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丁侄。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惯雳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸿摇,到底是詐尸還是另有隱情石景,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布户辱,位于F島的核電站鸵钝,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏庐镐。R本人自食惡果不足惜恩商,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望必逆。 院中可真熱鬧怠堪,春花似錦揽乱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至陌粹,卻和暖如春撒犀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掏秩。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工或舞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蒙幻。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓映凳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親邮破。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诈豌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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

  • 函數(shù)和對(duì)象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語(yǔ)言來說都是核心的概念抒和。通過函數(shù)可以封裝任意多條語(yǔ)句矫渔,而且...
    道無虛閱讀 4,564評(píng)論 0 5
  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值构诚,只能采用變通的方法蚌斩。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,384評(píng)論 0 1
  • 第2章 基本語(yǔ)法 2.1 概述 基本句法和變量 語(yǔ)句 JavaScript程序的執(zhí)行單位為行(line)铆惑,也就是一...
    悟名先生閱讀 4,149評(píng)論 0 13
  • “那劍尊雖然劍術(shù)了得范嘱,一手日月劍敗盡江湖客,可他也有怕的人员魏,”說書先生端起茶缸子潤(rùn)了潤(rùn)嗓子丑蛤,“你們可知是誰(shuí)...
    知難先生閱讀 599評(píng)論 0 5
  • 2018年7月24日上午,深圳分行第七家支行南頭支行舉行了盛大的開業(yè)慶典撕阎,總行吳洪濤行長(zhǎng)應(yīng)邀出席了南頭支行的...
    柚子斐閱讀 5,152評(píng)論 0 0