摘要:中的首先,是一個(gè)操作符,它可以用來創(chuàng)建兩種對(duì)象的實(shí)例,一種是用戶定義的對(duì)象類型,另一種則是擁有構(gòu)造函數(shù)的內(nèi)建對(duì)象類型。這就是原型繼承構(gòu)造函數(shù)被調(diào)用并傳入指定的參數(shù)示例二中的,然后被綁定給新創(chuàng)建的對(duì)象。
JavaScript 中的 new
首先,new 是一個(gè)操作符,它可以用來創(chuàng)建兩種對(duì)象的實(shí)例,一種是用戶定義的對(duì)象類型,另一種則是擁有構(gòu)造函數(shù)的內(nèi)建對(duì)象類型。
創(chuàng)建用戶定義的對(duì)象需要兩個(gè)步驟:
通過編寫函數(shù)來定義對(duì)象類型;
使用 new 來創(chuàng)建對(duì)象實(shí)例。
示例一:
var Person = function(personName) { this.name = personName; };
這是一個(gè)典型的通過編寫函數(shù)來定義對(duì)象類型的范例,我們可以這樣來表述其行為:
Person 函數(shù)定義了一種對(duì)象類型,其 類型名稱 就叫 Person。
在使用 Person 函數(shù)創(chuàng)建對(duì)象實(shí)例的時(shí)候可以傳入變量 personName,該變量會(huì)成為對(duì)象實(shí)例的一個(gè)屬性,這個(gè)屬性的名字叫 name。
為對(duì)象實(shí)例定義 name 屬性的過程發(fā)生在 Person 函數(shù)的函數(shù)體內(nèi);this 即指代將被創(chuàng)建的對(duì)象實(shí)例。
值得初學(xué)者注意的是,在現(xiàn)實(shí)中你更多地會(huì)看到這樣的代碼:
var Person = function(name) { this.name = name; };
有些人會(huì)搞不清楚究竟哪一個(gè) name 才是對(duì)象的屬性,在這里詳細(xì)解釋如下:
function(name) 里的 name 是待傳入?yún)?shù)的名字,通常被稱作:形式參數(shù)(Formal Parameter),或簡(jiǎn)稱 形參 ——因?yàn)樗皇谴韰?shù)的形式而并非真正傳入的參數(shù)(后者則被稱作:實(shí)際參數(shù)(Actual Parameter),或簡(jiǎn)稱 實(shí)參)。
this.name 的 name 是對(duì)象的屬性名字。
= name 的 name 還是形參,和 1. 里的 name 等價(jià);這就是所謂的 參數(shù)傳遞,或傳參。
示例二:
var albert = new Person("Albert"); albert.name; // "Albert" albert["name"]; // "Albert"
這是承接示例一,使用定義好的 Person 對(duì)象類型來實(shí)例化對(duì)象的范例,這個(gè)范例的表述相對(duì)容易一些:
定義一個(gè)變量 albert,然后實(shí)例化一個(gè)新的 Person 類型的對(duì)象,并將變量 albert 指向這個(gè)新的對(duì)象。
如果你對(duì) 形參 和 實(shí)參 還不夠清楚的話,看到這里就應(yīng)該完全明了了。保險(xiǎn)起見再加以解釋如下:
在示例二中,new Person("Albert") 中的 "Albert" 即對(duì)應(yīng)著示例一中 function(name) 中的 name,同時(shí)也是接下來一行中等號(hào)右邊的 name。
因此,"Albert" 就是 實(shí)際參數(shù),name 就是 形式參數(shù)。
示例二中還演示了兩種對(duì)象屬性的獲取方法,分別為 object.property 和 object["property"]。前一種比較常用,不過后一種由于可以用字符串來訪問對(duì)象屬性,因此在某些場(chǎng)合下非常有用(比如說用字符串傳遞了對(duì)象的屬性)。
回到 new 的話題。
當(dāng) new Person("Albert") 執(zhí)行的時(shí)候,會(huì)有如下事情發(fā)生:
創(chuàng)建一個(gè)新的對(duì)象,其類型是 Person 并繼承 Person.prototype 的所有屬性。這就是 原型繼承;
構(gòu)造函數(shù) Person 被調(diào)用并傳入指定的參數(shù)(示例二中的 "Albert"),然后 this 被綁定給新創(chuàng)建的對(duì)象。另外,若構(gòu)造函數(shù)不需要參數(shù),則 new Person 等價(jià)于 new Person();
若構(gòu)造函數(shù)沒有明確的返回值,那么新創(chuàng)建的對(duì)象就是整個(gè) new 表達(dá)式的結(jié)果;反之,若構(gòu)造函數(shù)內(nèi)顯式定義了返回值,則該返回值為整個(gè) new 表達(dá)式的結(jié)果。
關(guān)于第三點(diǎn),舉例示之:
示例三:
var Person = function(name) { return { name: "Mr. " + name } }; var albert = new Person("Albert"); albert.name; // "Mr. Albert"
var Person = function(name) { return { rawName: name, getName: function(gender) { if (gender === "male") { return "Mr. " + name; } else { return "Mrs. " + name; } } } }; var albert = new Person("Albert"); albert.getName("male"); // "Mr. Albert" albert.getName("female"); // "Mrs. Albert"
var Person = function(name, gender) { return { rawName: name, name: (function() { if (gender === "male") { return "Mr. " + name; } else { return "Mrs. " + name; } }()) } }; var albert = new Person("Albert", "male"); albert.rawName; // "Albert" albert.name; // "Mr. Albert" var annie = new Person("Annie", "female"); annie.rawName; // "Annie" annie.name; // "Mrs. Annie"
示例三演示了三種看起來相似但實(shí)際上具有顯著差異的對(duì)象類型定義和對(duì)象實(shí)例化的例子:
第一種:在 new Person("Albert") 時(shí)返回自定義的對(duì)象,而不是默認(rèn)由 new 創(chuàng)建的新對(duì)象。在這個(gè)自定義對(duì)象里,沒有簡(jiǎn)單地把參數(shù) name 賦給屬性 this.name,而是做了進(jìn)一步的修改。這種修改很顯然是非常簡(jiǎn)單但卻不夠靈活,為了改進(jìn)它,看下面兩個(gè)例子:
第二種:同樣返回自定義對(duì)象,這一次定義了兩個(gè)屬性,一個(gè)是 rawName,保存實(shí)例化時(shí)傳遞的參數(shù);另一個(gè)是 getName,它是一個(gè)函數(shù)聲明,因此不能直接用 albert.getName 或 albert["getName"] 來訪問(只會(huì)返回函數(shù)聲明本身,但不會(huì)有返回值)。不過你可以用albert.getNam("male") 或 albert["getName"]("male") 的方式來執(zhí)行這個(gè)函數(shù)并求得結(jié)果,這就是所謂的 方法。
如果不想用方法調(diào)用,但仍然希望像方法聲明體內(nèi)那樣做一些邏輯判斷是否可以呢?可以,繼續(xù)看第三種:
第三種:這一次 name 屬性又可以像以前那樣直接訪問了,原因是 name 指向的函數(shù)聲明使用了 IIFE(Immediately Invoked Function Expression) 技巧,該技巧使得函數(shù)聲明直接轉(zhuǎn)變成了函數(shù)表達(dá)式(并即刻執(zhí)行)。我們知道,函數(shù)表達(dá)式是能夠直接返回值的,而函數(shù)聲明則需要執(zhí)行(調(diào)用)才能返回值,于是 name 屬性獲得了返回值,就可以像原來那樣直接訪問了。
這種屬性定義方式有時(shí)被稱之為 計(jì)算后屬性(Computed Property),顧名思義:不是直接返回實(shí)例化時(shí)傳遞的值,而是對(duì)值進(jìn)行了一定的處理(計(jì)算)之后才返回。
屬性與方法:很多人都以為對(duì)象有 屬性 和 方法,其中屬性是可以直接訪問到值的,而方法是需要執(zhí)行才能獲得值的。但有的時(shí)候也會(huì)聽到“方法也是屬性”這樣的說法,這是為什么呢?
其實(shí)原因在于對(duì)術(shù)語的翻譯不夠準(zhǔn)確。英文里的 property 和 attribute 都被我們翻譯為屬性,然而在談及對(duì)象時(shí)這兩者是不同的。在一個(gè)對(duì)象里,attribute 和 method 被統(tǒng)稱為 property,直接保存值的 property 稱之為 attribute,保存函數(shù)聲明可以用來執(zhí)行的 property 才是 method。在用中文描述時(shí)很容易把兩種“屬性”搞混,需要注意分辨清楚。
補(bǔ)充說明:本文發(fā)表出去之后,有人感謝我?guī)退智辶?屬性 和 方法 在一些書中的歧義性,也有人拿著別的書來向我表示疑惑。以再版的 Object Oriented in JavaScript 為例,該書中在講解面向?qū)ο蠡A(chǔ)的時(shí)候,明確地指出:保存數(shù)據(jù)的屬性叫做 Property,保存行為的屬性叫做 Method,根本就不使用 Attribute。這倒是也簡(jiǎn)單明了,這樣一來就不存在 Method 也是 Property 一說了。
老實(shí)說,對(duì)此我也不知該如何回應(yīng)。不同的書用不同的術(shù)語,不同的作者也有不同的理解,我沒有“統(tǒng)一業(yè)界術(shù)語”的能量,所以也只能把它們一一列舉出來。對(duì)于初學(xué)者若造成理解上的偏差我表示道歉,總而言之你要記?。?strong>一個(gè)對(duì)象有兩類東西:一類記錄數(shù)據(jù),另一類記錄方法(方法總是做一件什么事,其中也包括返回新的數(shù)據(jù)),至于這兩類在不同的情境中叫法不一,也就要靠你自己去分辨了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77968.html
摘要:在他的重學(xué)前端課程中提到到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系中的重要崗位之一。大部分前端工程師的知識(shí),其實(shí)都是來自于實(shí)踐和工作中零散的學(xué)習(xí)。一基礎(chǔ)前端工程師吃飯的家伙,深度廣度一樣都不能差。 開篇 前端開發(fā)是一個(gè)非常特殊的行業(yè),它的歷史實(shí)際上不是很長(zhǎng),但是知識(shí)之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的。 winter在他的《重學(xué)前端》課程中提到: 到現(xiàn)在為止,前端工程師已經(jīng)成為研...
摘要:在他的重學(xué)前端課程中提到到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系中的重要崗位之一。大部分前端工程師的知識(shí),其實(shí)都是來自于實(shí)踐和工作中零散的學(xué)習(xí)。一基礎(chǔ)前端工程師吃飯的家伙,深度廣度一樣都不能差。開篇 前端開發(fā)是一個(gè)非常特殊的行業(yè),它的歷史實(shí)際上不是很長(zhǎng),但是知識(shí)之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的。 winter在他的《重學(xué)前端》課程中提到: 到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系...
摘要:作用域鏈的作用就是做標(biāo)示符解析。事件循環(huán)還有個(gè)明顯的特點(diǎn)單線程。早期都是用作開發(fā),單線程可以比較好當(dāng)規(guī)避同步問題,降低了開發(fā)門檻。單線程需要解決的是效率問題,里的解決思想是異步非阻塞。 0、前言 本人在大學(xué)時(shí)非常癡迷java,認(rèn)為java就是世界上最好的語言,偶爾在項(xiàng)目中會(huì)用到一些javascript,但基本沒放在眼里。較全面的接觸javascript是在實(shí)習(xí)的時(shí)候,通過這次的了解發(fā)現(xiàn)...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...
摘要:是文檔的一種表示結(jié)構(gòu)。這些任務(wù)大部分都是基于它。這個(gè)實(shí)踐的重點(diǎn)是把你在前端練級(jí)攻略第部分中學(xué)到的一些東西和結(jié)合起來。一旦你進(jìn)入框架部分,你將更好地理解并使用它們。到目前為止,你一直在使用進(jìn)行操作。它是在前端系統(tǒng)像今天這樣復(fù)雜之前編寫的。 本文是 前端練級(jí)攻略 第二部分,第一部分請(qǐng)看下面: 前端練級(jí)攻略(第一部分) 在第二部分,我們將重點(diǎn)學(xué)習(xí) JavaScript 作為一種獨(dú)立的語言,如...
摘要:一棧數(shù)據(jù)結(jié)構(gòu)與不同,中并沒有嚴(yán)格意義上區(qū)分棧內(nèi)存與堆內(nèi)存。引用數(shù)據(jù)類型的值是保存在堆內(nèi)存中的對(duì)象。不允許直接訪問堆內(nèi)存中的位置,因此我們不能直接操作對(duì)象的堆內(nèi)存空間。為了更好的搞懂變量對(duì)象與堆內(nèi)存,我們可以結(jié)合以下例子與圖解進(jìn)行理解。 showImg(https://segmentfault.com/img/remote/1460000009784102?w=1240&h=683); ...
閱讀 2578·2021-11-22 09:34
閱讀 3559·2021-11-15 11:37
閱讀 2361·2021-09-13 10:37
閱讀 2120·2021-09-04 16:40
閱讀 1603·2021-09-02 15:40
閱讀 2472·2019-08-30 13:14
閱讀 3342·2019-08-29 13:42
閱讀 1917·2019-08-29 13:02