摘要:在中有四種調(diào)用模式方法調(diào)用模式函數(shù)調(diào)用模式構(gòu)造器調(diào)用模式和調(diào)用模式。構(gòu)造一個(gè)的實(shí)例目標(biāo)就是結(jié)合前綴來調(diào)用的函數(shù),被稱為構(gòu)造函數(shù)。
正文久違的博文,貌似距離我上一篇也算是有些年歲(加班的日子真是度日如年啊T^T)了,所以呢,現(xiàn)在是時(shí)候回歸正道了,還是歡迎各位IT道友多多交(tu)流(cao)哈!
首先,說到 JavaScript 函數(shù),我們就要先理解下一些很可能被忽視的小概念:函數(shù)對(duì)象 和 函數(shù)字面量。
函數(shù)對(duì)象我們知道,在JavaScript中 函數(shù) 就是 對(duì)象。對(duì)象是“名/值”的集合,并擁有一個(gè)連到原型對(duì)象的隱藏連接。其中,對(duì)象字面量產(chǎn)生的對(duì)象連接到 Object.prototype,而函數(shù)對(duì)象連接到 Function.prototype (注:該原型對(duì)象本身連接到 Object.prototype )。每個(gè)函數(shù)在創(chuàng)建時(shí),都附有兩個(gè)附加的隱藏屬性: 函數(shù)的上下文 和 實(shí)現(xiàn)函數(shù)行為的代碼 。
另外,每個(gè)函數(shù)對(duì)象在創(chuàng)建時(shí),也隨帶有一個(gè) prototype 屬性,他的值是一個(gè)擁有 constructor 屬性,而且其值即為該函數(shù)的對(duì)象。這和隱藏連接到 Function.prototype 完全不同,而這個(gè)令人費(fèi)解的構(gòu)造過程的意義,我先埋個(gè)坑,以后在繼承篇的相關(guān)文章中再來填好了。
因?yàn)楹瘮?shù)是對(duì)象,所以它可以像其他值一樣被使用,比如,可以存放在變量、對(duì)象和數(shù)組中,可以被當(dāng)做參數(shù)傳遞給其他函數(shù),也可以在函數(shù)中返回函數(shù),而且,更因?yàn)楹瘮?shù)是對(duì)象,因此 函數(shù)也可以擁有方法。
函數(shù)字面量函數(shù)對(duì)象可以通過函數(shù)字面量來創(chuàng)建:
var add = function (a, b) { return a + b; }
函數(shù)字面量包括四個(gè)部分:
第一部分,是 保留字 function。
第二部分,是 函數(shù)名,它可以省略不寫。函數(shù)可以用它的名字來 遞歸 地調(diào)用自己。此名字也能被調(diào)試器和開發(fā)工具來識(shí)別函數(shù)(如:FireBug、Chrome console 等)。如果沒有給函數(shù)命名,比如上面的例子,它會(huì)認(rèn)為是 匿名函數(shù)。
第三部分,是包圍在圓括號(hào)中的一組 參數(shù),其中每個(gè)參數(shù)之間用逗號(hào)隔開,這些參數(shù)(也稱形式參數(shù),即形參)將被定義為函數(shù)中的變量,但是,它們不像普通變量那樣被初始化為 undefined,而是在該函數(shù)被調(diào)用時(shí)初始化為實(shí)際提供的參數(shù)的值(也稱實(shí)際參數(shù),即實(shí)參)。
第四部分,是包圍在花括號(hào)中的一組語句,這些語句就是 函數(shù)主體,它們?cè)诤瘮?shù)被調(diào)用時(shí)執(zhí)行。
函數(shù)字面量可以出現(xiàn)在任何允許表達(dá)式出現(xiàn)的地方。當(dāng)然,函數(shù)也可以嵌套在其他函數(shù)中,這樣的話,一個(gè)內(nèi)部函數(shù)不僅可以訪問自己的參數(shù)和變量,同時(shí)也可以方便地訪問它被嵌套的那個(gè)外部函數(shù)的參數(shù)和變量。
通過函數(shù)字面量創(chuàng)建的函數(shù)對(duì)象包含一個(gè)連到外部上下文的連接,這被稱為 閉包。它是 JavaScript 強(qiáng)大表現(xiàn)力的根基。而關(guān)于閉包的詳細(xì)原理和使用方法,以后會(huì)發(fā)布一些專門的文章進(jìn)行說明,敬請(qǐng)期待 ( ^_^ ) ~~
調(diào)用葷割線之后,接下來就是本文的重頭戲 -- 關(guān)鍵字 this 上場(chǎng)。眾所周知,這個(gè)老(son)伙(of)計(jì)(bit ch)可以說是JavaScript中的一大深坑,至于如何華麗麗地跳出這個(gè)坑,還請(qǐng)各位搬好板凳,備好瓜子,聽我慢慢道來。
當(dāng)我們調(diào)用一個(gè)函數(shù)時(shí),將暫停當(dāng)前函數(shù)的執(zhí)行,將傳遞控制器與參數(shù)給新函數(shù)。然而,除了聲明時(shí)定義的形參,每個(gè)函數(shù)接收兩個(gè)附加的參數(shù):this 和 arguments。參數(shù) this 在面向?qū)ο缶幊讨惺欠浅V匾?,它的值取決于調(diào)用的模式。在JavaScript中有四種調(diào)用模式:方法調(diào)用模式、函數(shù)調(diào)用模式、構(gòu)造器調(diào)用模式和apply調(diào)用模式。
調(diào)用運(yùn)算符,就是跟在任何一個(gè)函數(shù)值的表達(dá)式之后的一對(duì)圓括號(hào),它可以包含零個(gè)或者多個(gè)用逗號(hào)隔開的表達(dá)式,每個(gè)表達(dá)式產(chǎn)生一個(gè)參數(shù)值,每個(gè)參數(shù)值被賦予函數(shù)聲明時(shí)定義的形式參數(shù)名,而當(dāng)實(shí)際參數(shù)(arguments)的個(gè)數(shù)與形式參數(shù)(parameters)的個(gè)數(shù)不匹配時(shí),不會(huì)導(dǎo)致運(yùn)行時(shí)報(bào)錯(cuò)。比如說,如果實(shí)參值過多,超出的參數(shù)值將被忽略,如果實(shí)參值過少,缺失的值將會(huì)被替換為 undefined。并且,對(duì)參數(shù)值不會(huì)進(jìn)行類型檢查,即任何類型的值都可以被傳遞給參數(shù)。
方法調(diào)用模式當(dāng)一個(gè)函數(shù)被保存為對(duì)象的一個(gè)屬性時(shí),我們稱之為方法。當(dāng)一個(gè)方法被調(diào)用時(shí),this 會(huì)被綁定到該對(duì)象,即this就是該對(duì)象。如果一個(gè)調(diào)用表達(dá)式包含一個(gè)屬性存取表達(dá)式(即一個(gè) . 點(diǎn)表達(dá)式 或者 [subscript] 下標(biāo)表達(dá)式),那么它將被當(dāng)做一個(gè)方法來調(diào)用。
// 創(chuàng)建 myObject。它有一個(gè) value 屬性 和一個(gè) increment 方法 // increment 方法接收一個(gè)可選的參數(shù),若參數(shù)不是數(shù)字型,則默認(rèn)使用數(shù)字 1。 var myObject = { value: 0, increment: function (inc) { this.value += typeof inc === "number" ? inc : 1; } }; // 不傳參 myObject.increment(); console.log(myObject.value); // 1 // 傳非數(shù)字型 myObject.increment("a"); console.log(myObject.value); // 2 // 傳數(shù)字型 myObject.increment(2); console.log(myObject.value); // 4
方法可以使用 this 去訪問對(duì)象,所以它能從對(duì)象中取值或者修改該對(duì)象。this 到對(duì)象的綁定,發(fā)生在調(diào)用的時(shí)候。這個(gè)“超級(jí)”遲綁定(very late binding)使得函數(shù)可以對(duì) this 高度復(fù)用。通過 this 可取得它們所屬對(duì)象的上下文的方法,稱為公共方法。
函數(shù)調(diào)用模式當(dāng)一個(gè)函數(shù)并非一個(gè)對(duì)象的屬性(即方法)時(shí),那么它將被當(dāng)做一個(gè)函數(shù)來調(diào)用。
function add (a, b) { return a + b; } var sum = add(3,4); console.log(sum); // 7
當(dāng)函數(shù)以此模式調(diào)用時(shí),this 被綁定到全局對(duì)象(即 window 對(duì)象),這是語言設(shè)計(jì)上的一個(gè)重大的錯(cuò)誤?。。∪绻O(shè)計(jì)正確的話,當(dāng)內(nèi)部函數(shù)被調(diào)用時(shí),this 應(yīng)該仍然綁定到外部函數(shù)的 this 變量才對(duì)。這個(gè)錯(cuò)誤設(shè)計(jì)的后果是,方法不能利用內(nèi)部函數(shù)來幫助他工作,因?yàn)閮?nèi)部函數(shù)的 this 被綁定了錯(cuò)誤的值,或者說綁定了我們不想要的值,所以不能共享該方法對(duì)于對(duì)象的訪問權(quán)。不過,幸運(yùn)的是,有一個(gè)很容易的解決方案:如果該方法定義一個(gè)變量并給它賦值為this,那么內(nèi)部函數(shù)就可以通過那個(gè)變量訪問到 this,而這個(gè)變量我們通常命名為 that。
function add (a, b) { return a + b; } // 給 myObject 增加一個(gè)double方法 myObject.double = function () { var that = this; console.log(that); var helper = function () { that.value = add(that.value, that.value); }; // 以函數(shù)的形式調(diào)用 helper helper(); }; // 以方法的形式調(diào)用 double myObject.double(); console.log(myObject.getValue()); // 8構(gòu)造器調(diào)用模式
JavaScript 是一門基于原型繼承的語言,這就意味著對(duì)象可以直接從其它對(duì)象繼承屬性或方法,而該語言也是無類別的。
如果在一個(gè)函數(shù)前面加上一個(gè) new 來調(diào)用,那么將會(huì)創(chuàng)建一個(gè)隱藏連接到該函數(shù)的 prototype 成員的新對(duì)象(或者稱之為該對(duì)象的實(shí)例),同時(shí),this 將會(huì)被綁定到那個(gè)新對(duì)象(實(shí)例)上。
然而,new 前綴也會(huì)改變 return 語句的行為,這個(gè)我們以后再做詳細(xì)解析。
Quo.prototype.get_status = function () { return this.status; }; // 構(gòu)造一個(gè) Quo 的實(shí)例 var myQuo = new Quo("success"); console.log(myQuo.get_status()); // success
目標(biāo)就是結(jié)合 new 前綴來調(diào)用的函數(shù),被稱為構(gòu)造函數(shù)。按照約定,它們保存在以首字母大寫命名的變量里。如果調(diào)用構(gòu)造函數(shù)時(shí),沒有在前面加上 new,可能會(huì)發(fā)生非常糟糕的事情(如,實(shí)例無法調(diào)用該原型對(duì)象的方法,等),這樣既沒有編譯時(shí)警告,也沒有運(yùn)行時(shí)警告,所以加 new 前綴和大寫約定,是非常、非常、非常重要的(重要話,說三遍)。
然并卵,實(shí)際使用中,我們并不推薦這種形式的構(gòu)造器函數(shù),以后將在JavaScript的繼承篇為各位提供更好的解決方案。
Apply 調(diào)用模式因?yàn)?JavaScript 是一門函數(shù)式的面向?qū)ο蟮木幊陶Z言,所以函數(shù)可以擁有方法。
apply 方法讓我們構(gòu)建一個(gè)參數(shù)數(shù)組并用其去調(diào)用函數(shù),它也允許我們選擇 this 的取值。apply 方法接收兩個(gè)參數(shù),第一個(gè)是將被綁定給 this 的值,第二個(gè)就是一個(gè)參數(shù)數(shù)組。
// 1.構(gòu)造一個(gè)帶有兩個(gè)數(shù)字的數(shù)組,將之相加 var arr = [3, 4]; var sum = add.apply(null, arr); console.log(sum); // 7 // 2.構(gòu)造一個(gè)含有 status 成員的對(duì)象 var statusObj = { status: "right" }; var status = Quo.prototype.get_status.apply(statusObj); console.log(status); // right
這里第二個(gè)例子的代碼,通過了 apply 方法替換 Quo 對(duì)象中的 this 指針。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85982.html
摘要:前言由于最近的項(xiàng)目用到了一些的代碼,所以我?guī)е闷嫘?,認(rèn)真閱讀了這本書,粗略地了解語言的基本結(jié)構(gòu)和特性,對(duì)于一些不熟悉的新概念,以記錄的形式加強(qiáng)印象,也是對(duì)學(xué)習(xí)的反思總結(jié)。 前言 由于最近的項(xiàng)目用到了一些js的代碼,所以我?guī)е闷嫘?,認(rèn)真閱讀了這本書,粗略地了解js語言的基本結(jié)構(gòu)和特性,對(duì)于一些不熟悉的新概念,以記錄的形式加強(qiáng)印象,也是對(duì)學(xué)習(xí)的反思總結(jié)。 一、字面量(literals...
摘要:對(duì)之前看高級(jí)程序設(shè)計(jì)時(shí)沒有注意到的一些知識(shí)點(diǎn),結(jié)合本書做以補(bǔ)充語法注釋源于的型既可以出現(xiàn)在字符串字面量中,也可能出現(xiàn)在正則表達(dá)式字面量中,如故一般建議使用型注釋保留字語句變量參數(shù)屬性名運(yùn)算符和標(biāo)記等標(biāo)識(shí)符不允許使用保留字,此外在對(duì)象字面量中 對(duì)之前看《JavaScript高級(jí)程序設(shè)計(jì)》時(shí)沒有注意到的一些知識(shí)點(diǎn),結(jié)合本書做以補(bǔ)充 語法 注釋 源于PL/I的/* */型既可以出現(xiàn)在字符串字...
摘要:但采用構(gòu)造器調(diào)用模式,即是使用了前綴去調(diào)用一個(gè)函數(shù)時(shí),函數(shù)執(zhí)行的方式會(huì)改變。對(duì)象包含構(gòu)造器需要構(gòu)造一個(gè)新的實(shí)例的所有信息。構(gòu)造器的變量和內(nèi)部函數(shù)變成了該實(shí)例的私有成員。 JavaScript 是一門弱類型語言,從不需要類型轉(zhuǎn)換。對(duì)象繼承關(guān)系變得無關(guān)緊要。對(duì)于一個(gè)對(duì)象來說重要的時(shí)它能夠做什么,而不是它從哪里來。 閱讀《javascript語言精粹》筆記! 偽類 js的原型存...
摘要:調(diào)用函數(shù)時(shí),被綁定到全局對(duì)象。如果使用構(gòu)造器調(diào)用有前綴,且返回不是一個(gè)對(duì)象,則返回該新對(duì)象。閉包會(huì)導(dǎo)致原有作用域鏈不釋放,造成內(nèi)存泄漏。當(dāng)采用構(gòu)造器調(diào)用模式,函數(shù)執(zhí)行的方式會(huì)被修改。 內(nèi)容 ECMAScript核心語法結(jié)構(gòu):1.語法2.對(duì)象3.函數(shù)4.繼承5.數(shù)組6.正則表達(dá)式7.方法8.附錄A-毒瘤9.附錄B-糟粕 一、語法 1.類型、值和變量 1) 類型:區(qū)分?jǐn)?shù)據(jù)類型 在JS中使...
摘要:調(diào)用函數(shù)時(shí),被綁定到全局對(duì)象。如果使用構(gòu)造器調(diào)用有前綴,且返回不是一個(gè)對(duì)象,則返回該新對(duì)象。閉包會(huì)導(dǎo)致原有作用域鏈不釋放,造成內(nèi)存泄漏。當(dāng)采用構(gòu)造器調(diào)用模式,函數(shù)執(zhí)行的方式會(huì)被修改。 內(nèi)容 ECMAScript核心語法結(jié)構(gòu):1.語法2.對(duì)象3.函數(shù)4.繼承5.數(shù)組6.正則表達(dá)式7.方法8.附錄A-毒瘤9.附錄B-糟粕 一、語法 1.類型、值和變量 1) 類型:區(qū)分?jǐn)?shù)據(jù)類型 在JS中使...
閱讀 3735·2021-11-24 09:39
閱讀 1894·2021-11-16 11:45
閱讀 623·2021-11-16 11:45
閱讀 1045·2021-10-11 10:58
閱讀 2489·2021-09-09 11:51
閱讀 1949·2019-08-30 15:54
閱讀 700·2019-08-29 13:13
閱讀 3477·2019-08-26 12:18