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