讀《編寫可維護的JavaScript》第11章總結

這周也是拿到了同程的offer,今後走上了前端之路!感謝個人貴人們。再次記念一下~!

第11章 不是你的對象不要動

11.1 什麼是你的

你的對象:當你的代碼建立了這些對象或者你有職責維護其餘人的代碼的對象時,你就擁有這些對象。前端

不是你的對象:瀏覽器

  • 原生對象(Object、Array等等)
  • DOM對象(例如:Document)
  • 瀏覽器對象模型(BOM)對象(例如: window)
  • 類庫的對象

11.2.1 不覆蓋方法

 JavaScript這門語言也存在着糟粕,那就是覆蓋一個已經存在的方法是難以置信的容易- -即便那個神聖的  document.getElementById()方法也不例外。app

         // 很差的寫法
         document.getElementById = function() { return null;  //引發混亂
         }

 因此這裏不作更多的例子,做者以本身的親身經歷告訴咱們:不覆蓋方法纔是明智的選擇。ide

11.2.2 不新增方法

 做者舉了個Prototype JavaScript類庫的發展歷史的例子說明了:不新增方法一樣也是明智的選擇。
函數

11.2.3 不刪除方法

刪除一個方法有倆種手段:this

一、把方法賦值爲nullspa

二、使用delete操做符來刪除,可是它只能在對象的實例和方法起做用,若是在prototype的屬性和方法上使用delete是不起做用的prototype

做者也十分乾脆:刪除一個已存在對象的方法是糟糕的實踐。code

11.3 更好的途徑

更好的方法就是不直接修改這些對象,而是擴展它,也就是咱們一般所說的繼承。對象

JavaScript中有倆種基本的繼承方式:基於對象的繼承和基於類型的繼承。

① 基於對象的繼承

ECMAScript5中Object.create()方法是實現這種繼承的最簡單的方式(若是你不熟悉,《JS權威指南》第121頁有詳解):

    var person = { name : "Nicholas", sayName : function() { alert(this.name); } }; var myPerson = Object.create(person); myPerson.sayName(); // 彈出"Nicholas"

原理:Object.create這個方法會返回一個空函數的實例,這個空函數的原型屬性(prototype)是person。同時myPerson.prototype指向了空對象的prototype, 這個空對象的prototype也就是person, 因此當在myPerson上調用sayName函數時,Js會順着它的原型鏈向上查找並調用方法。

同時也推薦和感謝慕課網的Bosn老師對於原型和繼承這方面的獨到、深入、犀利的講解!

 ② 基於類型的繼承

基於類型的繼承和基於對象的繼承工做方式是差很少的,它從一個已存在的對象繼承,這裏的繼承是依賴與原型的。所以,基於類型的繼承是經過構造函數實現的,而非對象。這意味着,須要訪問被繼承對象的構造函數。

 function MyError(message) { this.message = message; } MyError.prototype = new Error(); // MyError類繼承自Error(所謂的超類)。給MyError.prototype賦值爲一個Error的實例。而後,每一個MyError實例從Error那裏繼承它的屬性和方法, instanceof也能正常工做。
        var error = new MyError("Something bad happened."); console.log(error instanceof Error); console.log(error instanceof MyError);

11.5 阻止修改

ECMAScript5引入了幾個方法來防止對對象的修改。能夠作到這樣的事情:鎖定這些對象,保證任何人不能有意無心地修改他們不想要的功能。如下三種修改的級別:

   · 防止擴展 ( preventExtension())

     禁止爲對象「添加」屬性和方法,但已存在的屬性和方法是能夠被修改或刪除的

 

   · 密封 ( seal() )

     相似「防止擴展」,並且禁止爲對象「刪除」已存在的屬性和方法

 

    · 凍結  ( freeze() )

     相似密封,並且禁止爲對象「刪除」已存在的屬性和方法

每種鎖定的類型都擁有倆個方法:一個用來實施操做,另外一個用來檢測是否應用了相應的操做。

下面的例子中,鎖定了prevent對象防止被擴展,因此調用Object.isExtensible()函數返回false,試圖爲person對象擴展新增屬性或方法將會悄無聲息的失敗。在嚴格模式下,試圖爲一個不可擴展的對象新增任何屬性或方法都將會拋出一個錯誤。

        var person = { name : "Nicholas" }; // 鎖定對象
 Object.preventExtension(person); console.log(Object.isExtensible(person)); //false
        person.age = 25; //正常狀況悄悄地失敗,除非在strict模式下拋出錯誤

 原理同上面類似,下面是Object.seal()函數

 // 鎖定對象
 Object.seal(person); console.log(Object.isExtensible(person)); // false
        console.log(Object.isSealed(person)); // true
        delete person.name; // 正常狀況悄悄地失敗,除非在strict模式下拋出錯誤
        person.age = 25; // 同上

 使用Object.freeze()函數來凍結一個對象。可使用Object.isFrozen()函數來檢查一個對象是否已被凍結。

 // 鎖定對象
 Object.freeze(person); console.log(Object.isExtensible(person)); // false
      console.log(Object.isSealed(person)); // true
      console.log(Object.isFrozen(person)); // true
      person.name = "Greg"; // 正常狀況下悄悄地失敗,除非在strict模式下拋出錯誤
      person.age = 25; // 同上
      delete person.name; //同上
相關文章
相關標籤/搜索