JavaScript - 函數(shù)Function

function

函數(shù)實(shí)際上是一個(gè)對(duì)象。

每個(gè)韓式都是 Function 類型的實(shí)例,而且都與其他引用類型一樣具有屬性和方法。

由于函數(shù)式對(duì)象,因此函數(shù)名實(shí)際上也是一個(gè)指向函數(shù)對(duì)象的指針,不會(huì)與某個(gè)函數(shù)綁定。

函數(shù)定義

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

var sum = function(num1, num2) {
    return num1 + num2;
}

var sum = new Function("num1", "num2", "return num1 + num2") // 不推薦

函數(shù)名是指向函數(shù)的指針,因此函數(shù)名與包含對(duì)象指針的其他變量沒有什么不同。

一個(gè)函數(shù)可以有多個(gè)名字(指針),例如:

function sum(num1, num2) {
    return num1 + num2;
}
alert(sum(10, 10)); // 20

var anotherSum = sum;
alert(anotherSum(10, 10)); //20

sum = null;
alert(anotherSum(10, 10)); //20

上面例子可以看出,指向函數(shù)的變量,實(shí)際上是指向函數(shù)對(duì)象的指針,所以當(dāng)其中一個(gè)賦值為 null 時(shí),并不會(huì)影響另一個(gè)(指針)變量。

沒有重載(深入理解)

將函數(shù)名想象為指針,也有助于理解為什么ECMAScript中沒有函數(shù)重載的概念。

function addSomeNumber(num) {
    return num + 100;
}

function addSomeNumber(num) {
    return num + 200;
}

var result = addSomeNumber(100); // 300
var addSomeNumber = function(num) {
    return num + 100;
}
addSomeNumber = function(num) {
    return num + 200;
}

雖然聲明了兩個(gè)函數(shù),結(jié)果是后面的函數(shù)覆蓋了前面的函數(shù)。

函數(shù)聲明與函數(shù)表達(dá)式

解析器在向執(zhí)行環(huán)境中加載數(shù)據(jù)時(shí),對(duì)函數(shù)聲明和函數(shù)表達(dá)式并非一視同仁。

解析器會(huì)率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用(可以訪問)。

函數(shù)表達(dá)式則必須等到解析器執(zhí)行到它們所在的代碼行,才會(huì)真正被執(zhí)行。

alert(sum(10, 10)); // 20
function sum(num1, num2){
    return num1 + num2;
}

alert(sum1(10, 10)) // 報(bào)錯(cuò):TypeError: sum1 is not a function(…)
var sum1 = function(num1, num2){
    return num1 + num2;
}

除了聲明時(shí)候可以通過變量訪問函數(shù)這一點(diǎn)區(qū)別之外,函數(shù)聲明與函數(shù)表達(dá)式的語法其實(shí)是等價(jià)的。

可以同時(shí)使用函數(shù)聲明和函數(shù)表達(dá)式,不過這種語法在 Safari 中會(huì)導(dǎo)致錯(cuò)誤。

作為值的函數(shù)

因?yàn)楹瘮?shù)本身就是變量,所以函數(shù)也可以作為值來使用。

函數(shù)可以像參數(shù)一樣把一個(gè)函數(shù)傳遞給另一個(gè)函數(shù),而且可以將一個(gè)函數(shù)作為另一個(gè)函數(shù)的結(jié)果返回。

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

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

var result1 = callSomeFunction(add10, 10);
alert(result1); // 20

function getGreetine(name) {
    return "Hello, " + name;
}

var result2 = callSomeFunction(getGreetine, "Bert");
alert(result2); // Hello, Bert

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

函數(shù)內(nèi)部有兩個(gè)特殊對(duì)象:arguments 和 this。

arguments

arguments 是一個(gè)數(shù)組對(duì)象,包含著傳入函數(shù)中的所有參數(shù)。

雖然 arguments 的主要用途是保存函數(shù)參數(shù),但這個(gè)對(duì)象還有一個(gè)名叫 callee 的屬性,該屬性是一個(gè)指針,指向擁有這個(gè) arguments 對(duì)象的函數(shù)。

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

factorial(3) // 6

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

factorial(5) // 120

使用函數(shù)名的階乘如果函數(shù)名變了,遞歸調(diào)用的函數(shù)的名字也要跟著改變。

但是,如果使用的是 arguments.callee 則不管函數(shù)名如何變化,內(nèi)部代碼都不用擔(dān)心會(huì)出現(xiàn)錯(cuò)誤。

this

函數(shù)內(nèi)部的另一個(gè)特殊對(duì)象,其行為與JavaC# 中的 this 大致類似。

this 引用是函數(shù)據(jù)以執(zhí)行的環(huán)境對(duì)象 ---- 或者也可以說是 this 值(當(dāng)在網(wǎng)頁的全局作用域中調(diào)用函數(shù)時(shí),this 對(duì)象引用就是 window)。

window.color = "red";
var o = { color: "blue" };

function sayColor() {
    alert(this.color);
}

sayColor(); // red

o.sayColor = sayColor;
o.sayColor(); // blue

根據(jù)作用域的不同, this 指針指向的對(duì)象也不同。

當(dāng)在全局作用域中調(diào)用 sayColor() 時(shí),this引用的是全局對(duì)象 window;換句話說 this.color 求值會(huì)轉(zhuǎn)換成對(duì) window.color 求值,

當(dāng)把函數(shù)賦給對(duì)象 o 并調(diào)用 o.sayColor() 時(shí), this 引用的是對(duì)象 o,因此對(duì) this.color 求值會(huì)轉(zhuǎn)換成對(duì) o.color 求值,結(jié)果就返回了 bule

注意:函數(shù)的名字僅僅是一個(gè)包含指針的變量而已。因此,即使是在不同的環(huán)境中執(zhí)行,全局的 sayColor() 函數(shù)與 o.sayColor() 指向的仍然是同一個(gè)函數(shù)

caller

ECMAScript 5 也規(guī)范了另一個(gè)函數(shù)對(duì)象的屬性: caller 。除了Opera的早期版本不支持,其他瀏覽器都支持這個(gè) ECMAScript 3 并沒有定義的屬性。

這個(gè)屬性保存著調(diào)用當(dāng)前函數(shù)的函數(shù)的引用,如果是在全局作用域中調(diào)用當(dāng)前函數(shù),他的值為 null。

function outer() {
    inter();
}

function inter() {
    alert(inter.caller);
    alert(arguments.callee.caller);
}

outer()

IE、Firefox、Chrome和Safari的所有版本以及Opera 9.6都支持 caller 屬性。

嚴(yán)格模式下訪問arguments.callee會(huì)導(dǎo)致錯(cuò)誤。

嚴(yán)格模式下不能為函數(shù)caller屬性賦值。

函數(shù)屬性和方法

length

函數(shù)希望接收的命名參數(shù)個(gè)數(shù)

function sayName(name) {
    alert(name);
}

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

function sayHi() {
    alert("hi");
}

alert(sayName.length); // 1
alert(sum.length); // 2
alert(sayHi.length); // 0

prototype

在 ECMAScript 核心所定義的全局屬性中,最耐人尋味的就要數(shù) prototype 屬性了。

對(duì)于 ECMAScript 中的引用類型而言, prototype 是保存它們所有實(shí)例方法的真正所在。

如 toString() 和 valueOf() 等方法實(shí)際上都保存在 prototype 名下,只不過是通過各自對(duì)象的實(shí)例訪問罷了。

在創(chuàng)建自定義引用類型以及實(shí)現(xiàn)繼承時(shí), prototype 屬性的作用是極為重要的。

prototype 屬性是不可枚舉的,因此使用 for-in 無法發(fā)現(xiàn)。

每個(gè)函數(shù)都包含兩個(gè)非繼承而來的方法:apply() 和 call()。

這兩個(gè)方法的用途都是在特定的作用域中調(diào)用函數(shù),實(shí)際上等于設(shè)置函數(shù)體內(nèi)this對(duì)象的值。

apply()

接收兩個(gè)參數(shù):一個(gè)是在其中運(yùn)行函數(shù)的作用域,另一個(gè)是參數(shù)數(shù)組。其中,第二個(gè)參數(shù)可以是 Array 的實(shí)例,也可以是 arguments 對(duì)象。

function sum(num1, num2) {
    return num1 + num2
}

function callSum1(num1, num2) {
    return sum.apply(this, arguments);
}

function callSum2(num1, num2) {
    return sum.apply(this, [num1, num2]);
}

alert(callSum1(10, 10)); // 20
alert(callSum2(10, 10)); // 20

在嚴(yán)格模式下, 未指定環(huán)境對(duì)象而調(diào)用函數(shù),則 this 值不會(huì)轉(zhuǎn)型為 window。除非明確把函數(shù)添加到某個(gè)對(duì)象或者調(diào)用 apply() 或 call(),否則 this 值將是 undefined

call()

call() 方法與 apply() 方法的作用相同,它們的區(qū)別僅在于接受的參數(shù)的方式不同。對(duì)于 call() 方法而言,第一個(gè)參數(shù)是 this 值沒有變化,變化的是其參數(shù)都直接傳遞給函數(shù)。

function sum(num1, num2) {
    return num1 + num2
}

function callSum(num1, num2) {
    return sum.call(this, num1, num2);
}

alert(callSum(10, 10)); // 20

傳遞參數(shù)并非 apply() 和 call() 真正的用武之地;它們真正強(qiáng)大的地方是能夠擴(kuò)充函數(shù)依賴以運(yùn)行的作用域。

window.color = "red";
var o = {color: "blue"};

function sayColor() {
    alert(this.color);
}

sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue

上例說明:使用 call() 或 apply() 來擴(kuò)充作用域的最大好處,就是對(duì)象不需要與方法有任何耦合關(guān)系。

bind()

這個(gè)方法會(huì)創(chuàng)建一個(gè)函數(shù)實(shí)例,其 this 值會(huì)被綁定到傳給 bind() 函數(shù)的值。

window.color = "red";
var o = {color: "blue"};

function sayColor() {
    alert(this.color);
}

var objectSayColor = sayColor.bind(o);
objectSayColor(); // blue

支持 bind() 方法的瀏覽器有 IE9+、Firefox 4+、Safari 5.1+、Opera 12+ 和Chrome。

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

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