<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 對象 ## 對象使用和屬性 JavaScript 中所有變量都可以當作對象使用,除了兩個例外 [`null`](#core.undefined) 和 [`undefined`](#core.undefined)。 ``` false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} Foo.bar = 1; Foo.bar; // 1 ``` 一個常見的誤解是數字的字面值(literal)不能當作對象使用。這是因為 JavaScript 解析器的一個錯誤, 它試圖將_點操作符_解析為浮點數字面值的一部分。 ``` 2.toString(); // 出錯:SyntaxError ``` 有很多變通方法可以讓數字的字面值看起來像對象。 ``` 2..toString(); // 第二個點號可以正常解析 2 .toString(); // 注意點號前面的空格 (2).toString(); // 2先被計算 ``` ### 對象作為數據類型 JavaScript 的對象可以作為[_哈希表_](http://en.wikipedia.org/wiki/Hashmap)使用,主要用來保存命名的鍵與值的對應關系。 使用對象的字面語法 - `{}` - 可以創建一個簡單對象。這個新創建的對象從 `Object.prototype` [繼承](#object.prototype)下面,沒有任何[自定義屬性](#object.hasownproperty)。 ``` var foo = {}; // 一個空對象 // 一個新對象,擁有一個值為12的自定義屬性'test' var bar = {test: 12}; ``` ### 訪問屬性 有兩種方式來訪問對象的屬性,點操作符或者中括號操作符。 ``` var foo = {name: 'kitten'} foo.name; // kitten foo['name']; // kitten var get = 'name'; foo[get]; // kitten foo.1234; // SyntaxError foo['1234']; // works ``` 兩種語法是等價的,但是中括號操作符在下面兩種情況下依然有效 * 動態設置屬性 * 屬性名不是一個有效的變量名(**[譯者注](http://cnblogs.com/sanshi/):**比如屬性名中包含空格,或者屬性名是 JS 的關鍵詞) **[譯者注](http://cnblogs.com/sanshi/):**在 [JSLint](http://www.jslint.com/) 語法檢測工具中,點操作符是推薦做法。 ### 刪除屬性 刪除屬性的唯一方法是使用 `delete` 操作符;設置屬性為 `undefined` 或者 `null` 并不能真正的刪除屬性, 而**僅僅**是移除了屬性和值的關聯。 ``` var obj = { bar: 1, foo: 2, baz: 3 }; obj.bar = undefined; obj.foo = null; delete obj.baz; for(var i in obj) { if (obj.hasOwnProperty(i)) { console.log(i, '' + obj[i]); } } ``` 上面的輸出結果有 `bar undefined` 和 `foo null` - 只有 `baz` 被真正的刪除了,所以從輸出結果中消失。 ### 屬性名的語法 ``` var test = { 'case': 'I am a keyword so I must be notated as a string', delete: 'I am a keyword too so me' // 出錯:SyntaxError }; ``` 對象的屬性名可以使用字符串或者普通字符聲明。但是由于 JavaScript 解析器的另一個錯誤設計, 上面的第二種聲明方式在 ECMAScript 5 之前會拋出 `SyntaxError` 的錯誤。 這個錯誤的原因是 `delete` 是 JavaScript 語言的一個_關鍵詞_;因此為了在更低版本的 JavaScript 引擎下也能正常運行, 必須使用_字符串字面值_聲明方式。 ## 原型 JavaScript 不包含傳統的類繼承模型,而是使用 _prototype_ 原型模型。 雖然這經常被當作是 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` 將會導致兩個對象共享**相同**的原型。 因此,改變任意一個對象的原型都會影響到另一個對象的原型,在大多數情況下這不是希望的結果。 ``` function Foo() { this.value = 42; } Foo.prototype = { method: function() {} }; function Bar() {} // 設置Bar的prototype屬性為Foo的實例對象 Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World'; // 修正Bar.prototype.constructor為Bar本身 Bar.prototype.constructor = Bar; var test = new Bar() // 創建Bar的一個新實例 // 原型鏈 test [Bar的實例] Bar.prototype [Foo的實例] { foo: 'Hello World' } Foo.prototype {method: ...}; Object.prototype {toString: ... /* etc. */}; ``` 上面的例子中,`test` 對象從 `Bar.prototype` 和 `Foo.prototype` 繼承下來;因此, 它能訪問 `Foo` 的原型方法 `method`。同時,它也能夠訪問**那個**定義在原型上的 `Foo` 實例屬性 `value`。 需要注意的是 `new Bar()` **不會**創造出一個新的 `Foo` 實例,而是 重復使用它原型上的那個實例;因此,所有的 `Bar` 實例都會共享**相同**的 `value` 屬性。 **注意:** **不要**使用 `Bar.prototype = Foo`,因為這不會執行 `Foo` 的原型,而是指向函數 `Foo`。 因此原型鏈將會回溯到 `Function.prototype` 而不是 `Foo.prototype`,因此 `method` 將不會在 Bar 的原型鏈上。 ### 屬性查找 當查找一個對象的屬性時,JavaScript 會**向上**遍歷原型鏈,直到找到給定名稱的屬性為止。 到查找到達原型鏈的頂部 - 也就是 `Object.prototype` - 但是仍然沒有找到指定的屬性,就會返回 [undefined](#core.undefined)。 ### 原型屬性 當原型屬性用來創建原型鏈時,可以把**任何**類型的值賦給它(prototype)。 然而將原子類型賦給 prototype 的操作將會被忽略。 ``` function Foo() {} Foo.prototype = 1; // 無效 ``` 而將對象賦值給 prototype,正如上面的例子所示,將會動態的創建原型鏈。 ### 性能 如果一個屬性在原型鏈的上端,則對于查找時間將帶來不利影響。特別的,試圖獲取一個不存在的屬性將會遍歷整個原型鏈。 并且,當使用 [`for in`](#object.forinloop) 循環遍歷對象的屬性時,原型鏈上的**所有**屬性都將被訪問。 ### 擴展內置類型的原型 一個錯誤特性被經常使用,那就是擴展 `Object.prototype` 或者其他內置類型的原型對象。 這種技術被稱之為 [monkey patching](http://en.wikipedia.org/wiki/Monkey_patch) 并且會破壞_封裝_。雖然它被廣泛的應用到一些 JavaScript 類庫中比如 [Prototype](http://prototypejs.org/), 但是我仍然不認為為內置類型添加一些_非標準_的函數是個好主意。 擴展內置類型的**唯一**理由是為了和新的 JavaScript 保持一致,比如 [`Array.forEach`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach)。 **[譯者注](http://cnblogs.com/sanshi/):**這是編程領域常用的一種方式,稱之為 [Backport](http://en.wikipedia.org/wiki/Backport),也就是將新的補丁添加到老版本中。 ### 總結 在寫復雜的 JavaScript 應用之前,充分理解原型鏈繼承的工作方式是每個 JavaScript 程序員**必修**的功課。 要提防原型鏈過長帶來的性能問題,并知道如何通過縮短原型鏈來提高性能。 更進一步,絕對**不要**擴展內置類型的原型,除非是為了和新的 JavaScript 引擎兼容。 ## `hasOwnProperty` 函數 為了判斷一個對象是否包含_自定義_屬性而_不是_[原型鏈](#object.prototype)上的屬性, 我們需要使用繼承自 `Object.prototype` 的 `hasOwnProperty` 方法。 **注意:** 通過判斷一個屬性是否 `undefined` 是**不夠**的。 因為一個屬性可能確實存在,只不過它的值被設置為 `undefined`。 `hasOwnProperty` 是 JavaScript 中唯一一個處理屬性但是**不**查找原型鏈的函數。 ``` // 修改Object.prototype Object.prototype.bar = 1; var foo = {goo: undefined}; foo.bar; // 1 'bar' in foo; // true foo.hasOwnProperty('bar'); // false foo.hasOwnProperty('goo'); // true ``` 只有 `hasOwnProperty` 可以給出正確和期望的結果,這在遍歷對象的屬性時會很有用。 **沒有**其它方法可以用來排除原型鏈上的屬性,而不是定義在對象_自身_上的屬性。 ### `hasOwnProperty` 作為屬性 JavaScript **不會**保護 `hasOwnProperty` 被非法占用,因此如果一個對象碰巧存在這個屬性, 就需要使用_外部_的 `hasOwnProperty` 函數來獲取正確的結果。 ``` var foo = { hasOwnProperty: function() { return false; }, bar: 'Here be dragons' }; foo.hasOwnProperty('bar'); // 總是返回 false // 使用其它對象的 hasOwnProperty,并將其上下文設置為foo ({}).hasOwnProperty.call(foo, 'bar'); // true ``` ### 結論 當檢查對象上某個屬性是否存在時,`hasOwnProperty` 是**唯一**可用的方法。 同時在使用 [`for in` loop](#object.forinloop) 遍歷對象時,推薦**總是**使用 `hasOwnProperty` 方法, 這將會避免[原型](#object.prototype)對象擴展帶來的干擾。 ## `for in` 循環 和 `in` 操作符一樣,`for in` 循環同樣在查找對象屬性時遍歷原型鏈上的所有屬性。 **注意:** `for in` 循環**不會**遍歷那些 `enumerable` 設置為 `false` 的屬性;比如數組的 `length` 屬性。 ``` // 修改 Object.prototype Object.prototype.bar = 1; var foo = {moo: 2}; for(var i in foo) { console.log(i); // 輸出兩個屬性:bar 和 moo } ``` 由于不可能改變 `for in` 自身的行為,因此有必要過濾出那些不希望出現在循環體中的屬性, 這可以通過 `Object.prototype` 原型上的 [`hasOwnProperty`](#object.hasownproperty) 函數來完成。 **注意:** 由于 `for in` 總是要遍歷整個原型鏈,因此如果一個對象的繼承層次太深的話會影響性能。 ### 使用 `hasOwnProperty` 過濾 ``` // foo 變量是上例中的 for(var i in foo) { if (foo.hasOwnProperty(i)) { console.log(i); } } ``` 這個版本的代碼是唯一正確的寫法。由于我們使用了 `hasOwnProperty`,所以這次**只**輸出 `moo`。 如果不使用 `hasOwnProperty`,則這段代碼在原生對象原型(比如 `Object.prototype`)被擴展時可能會出錯。 一個廣泛使用的類庫 [Prototype](http://www.prototypejs.org/) 就擴展了原生的 JavaScript 對象。 因此,當這個類庫被包含在頁面中時,不使用 `hasOwnProperty` 過濾的 `for in` 循環難免會出問題。 ### 總結 推薦**總是**使用 `hasOwnProperty`。不要對代碼運行的環境做任何假設,不要假設原生對象是否已經被擴展了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看