JavaScript秘密花園 – Object, Prototype

來源:互聯網
上載者:User
文章目錄
  • 關於作者(The authors)
  • 貢獻者(Contributors)
  • 許可(License)
  • 中文翻譯(Chinese Translation)
  • 對象作為資料類型(Objects as a data type)
  • 訪問屬性(Accessing properties)
  • 刪除屬性(Deleting properties)
  • 屬性名稱的文法(Notation of keys)
  • 屬性尋找(Property lookup)
  • 原型屬性(The prototype property)
  • 效能(Performance)
  • 擴充內建類型的原型(Extension of native prototypes)
  • 總結(In conclusion)

http://bonsaiden.github.com/JavaScript-Garden/zh/#object.forinloop

簡介(Intro)

JavaScript秘密花園是一個不斷更新的文檔,主要關心JavaScript一些古怪用法。 對於如何避免常見的錯誤,難以發現的問題,以及效能問題和不好的實踐給出建議, 初學者可以籍此深入瞭解JavaScript的語言特性。

JavaScript秘密花園不是用來教你JavaScript。為了更好的理解這篇文章的內容, 你需要事先學習JavaScript的基礎知識。在Mozilla開發人員網路中有一系列非常棒的JavaScript學習嚮導。

關於作者(The authors)

這篇文章的作者是兩位Stack Overflow的使用者, Ivo Wetzel(寫作) 和 Zhang Yi Jiang (設計)。

貢獻者(Contributors)
  • Caio Rom?o (拼字檢查)
  • Andreas Blixt (語言修正)
許可(License)

JavaScript花園在MIT license許可協議下發布,並存放在開源社區GitHub。 如果你發現錯誤或者打字錯誤,請file an issue或者pull request。 你也可以在Stack Overflow的聊天室JavaScript room找到我們。

中文翻譯(Chinese Translation)
  • JavaScript Garden - 原文
  • JavaScript Garden - 中文翻譯
  • 譯作者:三生石上

本中文翻譯由三上石上原創,部落格園首發,轉載請註明出處。

對象(Objects) #top

JavaScript中所有變數都是對象,除了兩個例外nullundefined

?
1 <code>false.toString() // 'false'<br>[1, 2, 3].toString(); // '1,2,3'<br><br>function Foo(){}<br>Foo.bar = 1;<br>Foo.bar; // 1<br></code>

一個常見的誤解是數位字面值(literal)不是對象。這是因為JavaScript解析器的一個錯誤, 它試圖將點操作符解析為浮點數字面值的一部分。

?
1 <code>2.toString(); // 出錯:SyntaxError<br></code>

有很多變通方法可以讓數位字面值看起來像對象。

?
1 <code>2..toString(); // 第二個點號可以正常解析<br>2 .toString(); // 注意點號前面的空格<br>(2).toString(); // 2先被計算<br></code>
對象作為資料類型(Objects as a data type)

JavaScript的對象可以作為雜湊表使用,主要用來儲存命名的鍵與值的對應關係。

使用對象的字面文法 - {} - 可以建立一個簡單對象。這個新建立的對象從Object.prototype繼承下面,沒有任何自訂屬性。

?
1 <code>var foo = {}; // 一個Null 物件<br><br>// 一個新對象,擁有一個值為12的自訂屬性'test'<br>var bar = {test: 12};<br></code>
訪問屬性(Accessing properties)

有兩種方式來訪問對象的屬性,點操作符或者中括弧操作符。

?
1 <code>var foo = {name: 'Kitten'}<br>foo.name; // kitten<br>foo['name']; // kitten<br><br>var get = 'name';<br>foo[get]; // kitten<br><br>foo.1234; // SyntaxError<br>foo['1234']; // works<br></code>

兩種文法是等價的,但是中括弧操作符在下面兩種情況下依然有效 - 動態設定屬性 - 屬性名稱不是一個有效變數名(譯者註:比如屬性名稱中包含空格,或者屬性名稱是JS的關鍵詞) (譯者註:在JSLint文法偵查工具中,點操作符是推薦做法)

刪除屬性(Deleting properties)

刪除屬性的唯一方法是使用delete操作符;設定屬性為undefined或者null並不能真正的刪除屬性, 而僅僅是移除了屬性和值的關聯。

?
1 <code>var obj = {<br>    bar: 1,<br>    foo: 2,<br>    baz: 3<br>};<br>obj.bar = undefined;<br>obj.foo = null;<br>delete obj.baz;<br><br>for(var i in obj) {<br>    if (obj.hasOwnProperty(i)) {<br>        console.log(i, '' + obj[i]);<br>    }<br>}<br></code>

上面的輸出結果有bar undefinedfoo null - 只有baz被真正的刪除了,所以從輸出結果中消失。

屬性名稱的文法(Notation of keys)?
1 <code>var test = {<br>    'case': 'I am a keyword so I must be notated as a string',<br>    delete: 'I am a keyword too so me' // 出錯:SyntaxError<br>};<br></code>

對象的屬性名稱可以使用字串或者一般字元聲明。但是由於JavaScript解析器的另一個錯誤設計, 上面的第二種聲明方式在ECMAScript 5之前會拋出SyntaxError的錯誤。

這個錯誤的原因是delete是JavaScript語言的一個關鍵詞;因此為了在更低版本的JavaScript引擎下也能正常運行, 必須使用字串字面值聲明方式。

原型(The prototype) #top

JavaScript不包含傳統的類繼承模型,而是使用prototypical原型模型。

雖然這經常被當作是JavaScript的缺點被提及,其實基於原型的繼承模型比傳統的類繼承還要強大。 實現傳統的類繼承模型是很簡單,但是實現JavaScript中的原型繼承則要困難的多。 (It is for example fairly trivial to build a classic model on top of it, while the other way around is a far more difficult task.)

由於JavaScript是唯一一個被廣泛使用的基於原型繼承的語言,所以理解兩種繼承模式的差異是需要一定時間的。

第一個不同之處在於JavaScript使用原型鏈的繼承方式。

注意: 簡單的使用Bar.prototype = Foo.prototype將會導致兩個對象共用相同的原型。 因此,改變任意一個對象的原型都會影響到另一個對象的原型,在大多數情況下這不是希望的結果。

?
1 <code>function Foo() {<br>    this.value = 42;<br>}<br>Foo.prototype = {<br>    method: function() {}<br>};<br><br>function Bar() {}<br><br>// 設定Bar的prototype屬性為Foo的執行個體對象<br>Bar.prototype = new Foo();<br>Bar.prototype.foo = 'Hello World';<br><br>// 修正Bar.prototype.constructor為Bar本身<br>Bar.prototype.constructor = Bar;<br><br>var test = new Bar() // 建立Bar的一個新執行個體<br><br>// 原型鏈<br>test [Bar的執行個體]<br>    Bar.prototype [Foo的執行個體] <br>        { foo: 'Hello World' }<br>        Foo.prototype<br>            {method: ...};<br>            Object.prototype<br>                {toString: ... /* etc. */};<br><br></code>

上面的例子中,test對象從Bar.prototypeFoo.prototype繼承下來;因此, 它能否訪問Foo的原型方法method。但是它不能訪問Foo的執行個體屬性value, 因為這個屬性在Foo的建構函式中定義。 (But it will not have access to the property value of a Foo instance, since that property gets defined in the constructorof Foo. But this constructor has to be called explicitly.)

(譯者註:我認為這個描述是錯誤的,test.value是可以訪問的。 因為在設定Bar.prototype = new Foo();時,value也就成為Bar.prototype上的一個屬性。 如果你有不同觀點,可以到我的部落格評論。)

注意: 不要使用Bar.prototype = Foo,因為這不會執行Foo的原型,而是指向函數Foo。 因此原型鏈將會回溯到Function.prototype而不是Foo.prototype,因此method將不會在Bar的原型鏈上。

屬性尋找(Property lookup)

當尋找一個對象的屬性時,JavaScript會向上遍曆原型鏈,直到找到給定名稱的屬性為止。

到尋找到達原型鏈的頂部 - 也就是Object.prototype - 但是仍然沒有找到指定的屬性,就會返回undefined。

原型屬性(The prototype property)

當原型屬性用來建立原型鏈時,可以把任何類型的值賦給它(prototype)。 然而將原子類型賦給prototype的操作將會被忽略。

?
1 <code>function Foo() {}<br>Foo.prototype = 1; // no effect<br></code>

而將對象賦值給prototype,正如上面的例子所示,將會動態建立原型鏈。

效能(Performance)

如果一個屬性在原型鏈的上端,則對於尋找時間將帶來不利影響。特別的,試圖擷取一個不存在的屬性將會遍曆整個原型鏈。

並且,當使用for-in迴圈遍曆對象的屬性時,原型鏈上的所有屬性都將被訪問。

擴充內建類型的原型(Extension of native prototypes)

一個錯誤特性被經常使用,那就是擴充Object.prototype或者其他內建類型的原型對象。

這種技術被稱之為monkey patching並且會破壞封裝。雖然它被廣泛的應用到一些JS類庫中比如Prototype,但是我仍然不認為為內建類型添加一些非標準的函數是個好主意。

擴充內建類型的唯一理由是為了和新的JavaScript保持一致,比如Array.forEach。 (譯者註:這是編程領域常用的一種方式,稱之為Backport,也就是將新的補丁添加到老版本中。)The only good reason for extending a built-in prototype is to backport  the features of newer JavaScript engines; for example, Array.forEach.

總結(In conclusion)

在寫複雜的JavaScript應用之前,充分理解原型鏈繼承的工作方式是每個JavaScript程式員必修的功課。 要提防原型鏈過長帶來的效能問題,並知道如何通過縮短原型鏈來提高效能。 更進一步,絕對不要擴充內建類型的原型,除非是為了和新的JavaScript引擎相容。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.