第五章 引用類型(一)

??在ECMAScript中苫费,引用類型是一種數(shù)據(jù)結(jié)構(gòu)牍汹,用于將數(shù)據(jù)和功能組織在一起钧嘶。它在其他語言中通常被稱作類新荤,但這種稱呼在ECMAScript中并不妥當(dāng),因?yàn)殡m然ECMAScript從技術(shù)上來說是一門面向?qū)ο蟮恼Z言笆呆,但它不具備傳統(tǒng)的面向?qū)ο笳Z言所支持的類和接口等基本結(jié)構(gòu)。引用類型有時(shí)候也被稱作對象定義,因?yàn)樗枋龅氖且活悓ο笏哂械膶傩院头椒ā?/p>

??如前所述味混,對象是某個(gè)特定引用類型的實(shí)例角溃。一個(gè)對象是使用new操作符后接構(gòu)造函數(shù)來創(chuàng)建的茧妒。構(gòu)造函數(shù)本身是一個(gè)函數(shù)萧吠,只不過該函數(shù)是出于創(chuàng)建新對象的目的而定義的。下面是一個(gè)創(chuàng)建對象的例子:

var person = new Object();

上面的代碼創(chuàng)建了Object引用類型的一個(gè)實(shí)例剖毯,然后把該實(shí)例保存在了person變量中逊谋。使用的構(gòu)造函數(shù)是Object()俭令,它只為對象定義了默認(rèn)的屬性和方法。ECMAScript內(nèi)置了許多引用類型(例如Object粟誓,Array等),供開發(fā)人員直接使用蛹头。

1. Object類型

??Object類型是ECMAScript中使用最多的類型顿肺,雖然其不具備太多的功能戏溺,但對于在應(yīng)用程序中存儲和傳輸數(shù)據(jù)來說,確實(shí)是一種非常理想的選擇屠尊。創(chuàng)建Object類型的實(shí)例有兩種方式:

  • new操作符后跟Object構(gòu)造函數(shù)
  • 使用對象字面量表示法

下面是一個(gè)使用new操作符創(chuàng)建Object實(shí)例的例子:

var person = new Object();
person.name = "Ivan";
person.age = 22;

下面是一個(gè)使用對象字面量表示法創(chuàng)建Object實(shí)例的例子:

var person = {
    name: "Ivan",
    age: 22
}

我們可以看到旷祸,使用字面量表示法創(chuàng)建對象,簡化了創(chuàng)建包含大量屬性的對象的過程讼昆。另外肋僧,使用對象字面量語法時(shí),如果留空其花括號控淡,則等價(jià)于new Object()嫌吠,下面是一個(gè)例子:

var person = {};
person.name = "Ivan";
person.age = 22;

在通過字面量定義對象時(shí),實(shí)際上不會調(diào)用Object構(gòu)造函數(shù)掺炭。

??一般來說辫诅,訪問對象屬性時(shí)使用的都是點(diǎn)表示法,這也是很多面向?qū)ο笳Z言通用的語法涧狮。不過炕矮,在JavaScript中,也可以通過方括號([])表示法來訪問對象屬性者冤。在使用方括號表示法時(shí)肤视,應(yīng)該將要訪問的屬性以字符串的形式放在方括號中,如下面的例子所示:

alert(person["name"]);  //等價(jià)于alert(person.name)

從功能上看涉枫,這兩種訪問屬性的方式?jīng)]有任何區(qū)別邢滑。但方括號表示法的優(yōu)點(diǎn)在于可以通過變量來訪問屬性,例如:

var propertyName = "name";
alert(person[propertyName]);

另外愿汰,如果屬性名中包含特殊字符困后,也只能使用方括號表示法:

alert(person["first name"]);  //屬性名包含空格

通常,除非必須使用變量訪問屬性衬廷,否則我們建議使用點(diǎn)表示法摇予。

2. Function類型

??在ECMAScript中,函數(shù)的本質(zhì)實(shí)際上是對象吗跋。每個(gè)函數(shù)都是Function類型的實(shí)例侧戴,并且與其他引用類型一樣擁有屬性和方法。由于函數(shù)是對象跌宛,因此函數(shù)名實(shí)際上是指向函數(shù)對象的指針酗宋。函數(shù)通常使用函數(shù)聲明語法定義,例如:

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

另一種定義函數(shù)的方式是使用函數(shù)表達(dá)式

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

由于函數(shù)名僅僅是指向函數(shù)對象的指針秩冈,因此它和其他包含對象指針的變量沒有什么不同本缠。換句話來說斥扛,一個(gè)函數(shù)可能會有多個(gè)名字入问。下面是一個(gè)例子:

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

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

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

2.1 沒有重載

??將函數(shù)名想象成指針丹锹,也有助于我們理解ECMAScript中為什么沒有函數(shù)重載的概念。下面是一個(gè)例子:

function increase(num){
    return num + 1;
}
function increase(num){
    return num + 2;
}
alert(increase(100));  //102

上面的例子聲明了兩個(gè)同名函數(shù)芬失,結(jié)果是后面的函數(shù)定義覆蓋了前面一個(gè)楣黍。因?yàn)椋厦娴拇a實(shí)際上與下面的代碼沒有區(qū)別:

var increase = function (num){
    return num + 1;
}
increase  = function (num){
    return num + 2;
}
alert(increase(100));  //102

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

??如前文所述棱烂,函數(shù)定義可以通過兩種方式:函數(shù)聲明函數(shù)表達(dá)式租漂。實(shí)際上,解析器在向執(zhí)行環(huán)境中加載數(shù)據(jù)時(shí)颊糜,對函數(shù)聲明和函數(shù)表達(dá)式并非一視同仁哩治。解析器會率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼前可用(可以訪問)衬鱼;至于函數(shù)表達(dá)式业筏,則必須等到解析器執(zhí)行到它所在的代碼行,才會被真正解釋執(zhí)行鸟赫。請看下面的例子:

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

上面的代碼完全可以正常運(yùn)行蒜胖。因?yàn)樵诖a開始執(zhí)行之前,解析器就通過一個(gè)名為函數(shù)聲明提升(function declaration hoisting)的過程抛蚤,讀取并將函數(shù)聲明添加到執(zhí)行環(huán)境中台谢。然而,將上面的函數(shù)聲明改為等價(jià)的函數(shù)表達(dá)式岁经,就會在執(zhí)行期間產(chǎn)生"unexpected identifier"的錯(cuò)誤朋沮。

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

2.3 作為值的函數(shù)

??由于ECMAScript中的函數(shù)名本身就是變量朽们,所以函數(shù)也可以作為值來使用。也就是說诉位,不僅可以像傳遞參數(shù)一樣將一個(gè)函數(shù)傳遞給另一個(gè)函數(shù)骑脱,也可以將一個(gè)函數(shù)作為另一個(gè)函數(shù)的結(jié)果返回。請看下面的例子:

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

function plus10(num){
    return num + 10;
}
var result1 = callSomeFunction(plus10, 10);
alert(result1);  //20

function getGreeeting(name){
    return "Hello" + name;
}
var result2 = callSomeFunction(getGreeting, "Ivan");
alert(result2);  //"Hello, Ivan"

??另外苍糠,也可以從一個(gè)函數(shù)中返回另一個(gè)函數(shù)叁丧,而且這是一個(gè)極為有用的技術(shù)。下面是一個(gè)根據(jù)傳遞進(jìn)去的對象屬性對一個(gè)對象數(shù)組進(jìn)行排序的例子:

function createComparisionFunction(propertyName){
    return funtion(obj1, obj2){
        var v1 = obj1[propertyName];
        var v2 = obj2[propertyName];
        if (v1 < v2){
            return -1;
       } else if (v1 > v2){
            return 1;
       }else{
            return 0;
       }
    };
}
var persons = [{name: "Ivan", age: 19}, {name: "Roy", age: 22}];
persons.sort(createComparisionFunction("name"));
alert(persons[0].name);  //"Ivan"
persons.sort(createComparisionFunction("age"));
alert(persons[0].age);  //19

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

??在函數(shù)內(nèi)部岳瞭,有兩個(gè)特殊的對象拥娄,分別為argumentsthis。argumnets在前文中已經(jīng)提及瞳筏,它是一個(gè)類數(shù)組對象稚瘾,保存中傳入函數(shù)中的所有參數(shù)。而this對象則引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對象(當(dāng)在網(wǎng)頁的全局作用域中調(diào)用函數(shù)時(shí)姚炕,this對象引用的就是window)摊欠。請看下面的例子:

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

function sayColor(){
    alert(this.color); 
}
 
sayColor();     //"red" 
o.sayColor = sayColor; 
o.sayColor();   //"blue" 

上面的代碼在全局作用域中定義了一個(gè)函數(shù)sayColor()丢烘,由于在調(diào)用函數(shù)前,無法確定函數(shù)的執(zhí)行環(huán)境些椒,因此this可能在代碼執(zhí)行過程中引用不同的對象播瞳。當(dāng)在全局作用域中調(diào)用sayColor()函數(shù)時(shí),this引用全局對象window免糕,因此對this.color求值就會轉(zhuǎn)換為對window.color求值赢乓,因此輸出"red"。而當(dāng)把這個(gè)函數(shù)賦值給對象o并調(diào)用o.sayColor()方法時(shí)石窑,this引用的對象是o牌芋,因此this.color求值就會轉(zhuǎn)換為對o.color求值,因此輸出"blue"松逊。

2.5 函數(shù)屬性和方法

??如前文所說姜贡,ECMAScript中的函數(shù)是對象,因此函數(shù)也有屬性和方法棺棵。每個(gè)函數(shù)都包含兩個(gè)屬性:lengthprototype楼咳。其中,length表示函數(shù)希望接收的命名參數(shù)個(gè)數(shù)烛恤。而prototype屬性則存在于所有的引用類型中母怜,保存了該引用類型的所有實(shí)例方法。因此缚柏,在自定義引用類型和實(shí)現(xiàn)繼承時(shí)苹熏,prototype屬性是極其重要的。

??另外币喧,每個(gè)函數(shù)都包含了兩個(gè)非繼承而來的方法:apply()call()轨域。這兩個(gè)方法的用途都是使函數(shù)運(yùn)行在特定的作用域中,實(shí)際上是設(shè)置函數(shù)體內(nèi)this對象的值杀餐。首先apply()方法接收兩個(gè)參數(shù):第一個(gè)參數(shù)是在其中運(yùn)行函數(shù)的作用域干发,第二個(gè)參數(shù)是一個(gè)參數(shù)數(shù)組(或者arguments對象)。下面是一個(gè)例子:

function sum (num1, num2){
     return num1 + num2;
}
fucntion callSum1(num1, num2){
    return sum.apply(this, arguments);
}
function callSum2(num1, num2){
    return sum.apply(this, [num1, num2]);
}
callSum1(10, 10);  //20
callSum2(10, 10);  //20

在上面這個(gè)例子中史翘,callSum1()在執(zhí)行 sum()函數(shù)時(shí)傳入了 this 作為 this 值(因?yàn)槭窃谌肿饔糜蛑姓{(diào)用的枉长,所以傳入的就是 window 對象)和 arguments 對象。而 callSum2 同樣也調(diào)用了 sum()函數(shù)琼讽,但它傳入的則是 this 和一個(gè)參數(shù)數(shù)組必峰。這兩個(gè)函數(shù)都會正常執(zhí)行并返回正確的結(jié)果。

??call()方法與apply()方法的作用完全相同钻蹬,唯一的區(qū)別在于call()方法接收的是命名參數(shù)列表而不是參數(shù)數(shù)組吼蚁。call()方法和apply()方法真正強(qiáng)大的地方在于它們能夠擴(kuò)充函數(shù)賴以運(yùn)行的作用域。請看下面的例子:

window.color = "red"; 
var o = { color: "blue" };  
function sayColor(){
    alert(this.color); 
}  
sayColor();  //red 
sayColor.call(this);  //red
sayColor.call(window);  //red 
sayColor.call(o);  //blue

上面的例子在全局環(huán)境中定義了一個(gè)函數(shù):sayColor()问欠。直接在全局環(huán)境中調(diào)用時(shí)肝匆,this指向此函數(shù)運(yùn)行的全局環(huán)境粒蜈,因此對this.color的求值會轉(zhuǎn)換為對window.color的求值。而sayColor.call(this)和sayColor.call(window)則是顯示的設(shè)置此函數(shù)運(yùn)行時(shí)的執(zhí)行環(huán)境术唬,此處設(shè)置為在全局環(huán)境中運(yùn)行sayColor()函數(shù)薪伏,因此也輸出"red"滚澜。而最后使用sayColor.call(o)調(diào)用則將執(zhí)行環(huán)境切換到對象o粗仓,此時(shí)函數(shù)體內(nèi)的 this 對象指向了 o,因此結(jié)果顯示的是"blue"设捐。

??使用 call()(或 apply())來擴(kuò)充作用域的大好處借浊,就是對象不需要與方法有任何耦合關(guān)系。在前面例子的第一個(gè)版本中萝招,我們是先將 sayColor()函數(shù)放到了對象 o 中蚂斤,然后再通過 o 來調(diào)用它的;而在這里重寫的例子中槐沼,就不需要先前那個(gè)多余的步驟了曙蒸。

??ECMAScript 5還定義了一個(gè)方法:bind()。這個(gè)方法會創(chuàng)建一個(gè)函數(shù)的實(shí)例岗钩,其 this 值會被綁 定到傳給 bind()函數(shù)的值纽窟。例如:

window.color = "red"; 
var o = { color: "blue" }; 
function sayColor(){
    alert(this.color); 
} 
var objectSayColor = sayColor.bind(o); 
objectSayColor();    //blue 

在這個(gè)例子中,sayColor()調(diào)用 bind()并傳入對象 o兼吓,創(chuàng)建了 objectSayColor()函數(shù)臂港。object- SayColor()函數(shù)的 this 值等于 o,因此即使是在全局作用域中調(diào)用這個(gè)函數(shù)视搏,也會看到"blue"审孽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市浑娜,隨后出現(xiàn)的幾起案子佑力,更是在濱河造成了極大的恐慌,老刑警劉巖筋遭,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搓萧,死亡現(xiàn)場離奇詭異,居然都是意外死亡宛畦,警方通過查閱死者的電腦和手機(jī)瘸洛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來次和,“玉大人反肋,你說我怎么就攤上這事√な” “怎么了石蔗?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵罕邀,是天一觀的道長。 經(jīng)常有香客問我养距,道長诉探,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任棍厌,我火速辦了婚禮肾胯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘耘纱。我一直安慰自己敬肚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布束析。 她就那樣靜靜地躺著艳馒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪员寇。 梳的紋絲不亂的頭發(fā)上弄慰,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機(jī)與錄音蝶锋,去河邊找鬼陆爽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛牲览,可吹牛的內(nèi)容都是我干的墓陈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼第献,長吁一口氣:“原來是場噩夢啊……” “哼贡必!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起庸毫,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤仔拟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后飒赃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體利花,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年载佳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炒事。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蔫慧,死狀恐怖挠乳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤睡扬,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站卖怜,受9級特大地震影響屎开,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜马靠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一奄抽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虑粥,春花似錦如孝、人聲如沸宪哩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锁孟。三九已至彬祖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間品抽,已是汗流浹背储笑。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留圆恤,地道東北人突倍。 一個(gè)月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像盆昙,于是被迫代替她去往敵國和親羽历。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

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

  • 引用類型的值(對象)是引用類型的一個(gè)實(shí)例淡喜。在ECMScript中秕磷,引用類型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)據(jù)和功能組織在一...
    dudu_du閱讀 306評論 0 0
  • 引用類型的值時(shí)引用類型的一個(gè)實(shí)例炼团。在ECMAScript中澎嚣,引用類型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)據(jù)和功能組織在一起瘟芝。有...
    cooore閱讀 285評論 0 1
  • 引用類型 引用類型的值( 對象 )是引用類型的一個(gè)實(shí)例易桃。在ECMAScript中,引用類型是一種數(shù)據(jù)結(jié)構(gòu)锌俱,用于將數(shù)...
    極奏閱讀 297評論 0 1
  • 第五章:引用類型 5.1 Object 類型 5.1 .1 創(chuàng)建 Object 實(shí)例的方式有兩種 5.2 Arra...
    杜小飛saya閱讀 255評論 0 0
  • 引用類型的值(對象)是引用類型的一個(gè)實(shí)例晤郑。也就是說,對象是某個(gè)特定引用類型的實(shí)例。如: 一贩汉、 Object類型 對...
    Annie_d04e閱讀 132評論 0 1