JavaScript設計模式閱讀隨筆(一)——JavaScript面向對象

JavaScript中的面向對象其實就至關因而將需求抽象成一個對象,這個對象中包含屬性和方法,能夠用來描述或處理某一類實物,這個對象就叫作類。javascript

在Java中面向對象的三要素是:封裝、繼承、多態,在ES6之前雖然沒有class、extend這樣的關鍵字或方法,中一樣能夠實現這三要素。java

建立一個類安全

在ES6以前建立一個類通能夠用:聲明一個函數將其保存在變量中,內部經過對this來添加屬性和方法;也能夠在類的原型上添加屬性和方法。閉包

能夠看到當在控制檯中建立一個Book的類,Book的實例化對象book包含兩個屬性 id 和 name,它的隱身原型__proto__中包含一個constructor屬性,它又指向了Book這個原型對象。函數

若是在Book的原型上添加方法或屬性:比如 Book。prototype.display = function (){ ... } 每一個實例化對象都會經過原型鏈繼承到這個方法,但這並不是是她自有的方法,須要經過prototype訪問。this

現在ES6引入Class能夠這麼建立類,constructor方法是類的默認方法,經過new命令生成對象實例時,自動調用該方法。spa

1 class Book {
2   constructor(id, name) {
3     this.id = id;
4     this.name = name;
5   }
6 }

 

封裝prototype

利用javascript的函數做用域能夠建立類的私有變量和私有方法,經過this建立類的共有屬性和共有方法。一下代碼是我理解中javascript封裝的精髓code

 1 var Book = function (id,name) {
 2   // 安全檢查 判斷執行過程當中是不是當前這個對象
 3   // 避免誤建立全局對象
 4   if (this instanceof Book) {
 5     this.name = name;
 6   } else {
 7     return new Book(id,name);
 8   }
 9   // 私有屬性
10   var num = 1;
11   // 私有方法
12   function checkId() {
13     return num +'個'+ id;
14   }
15   // 公有屬性和公有方法
16   this.id = id;
17   this.copy = function () {}
18   // 特權方法
19   this.setName = function (name){}
20   this.getName = function() {
21     // 能夠訪問公有方法和屬性,也能夠訪問建立對象時的私有方法和屬性
22   }
23   // 構造器
24   this.setName = function (name) {
25     // 在對象建立時,使用特權方法初始化實例對象
26   }
27   // 閉包
28   return checkId; 
29 }

 

繼承對象

繼承就是對原有對象的封裝,從中建立私有屬性、公有屬性等,對於每種屬性和方法特色都不同。能夠被繼承的方法屬性無外乎兩種,一種是在構造函數中,在對象實例化時複製一遍屬性和方法;一種是在類的原型對象中,這類方法和屬性能夠被全部實例化對象共有。

類式繼承:

類式繼承能夠理解爲把父類的實力賦值給子類的原型,經過原型鏈來實現繼承。

1 function SuperClass() {
2     this.books = ['父類book'];
3 }
4 function SubClass() {}
5 Sub.prototype = new SuperClass();
6 
7 var instance1= new SubClass();
8 console.log(instance1.books); //['父類book']

 

用這種方式新建立的對象不只能夠訪問父類原型上的屬性和方法,還能訪問父類構造函數中賦值的屬性和方法,子類的原型還能夠訪問父類原型上的方法.

不足之處是,若是某一個實例化對象修改了books這個屬性,那麼全部實例化的對象books值都會被污染。

構造函數繼承:

構造函數式繼承能夠很好的解決類式繼承中所暴露的問題。它的精髓在於使用call() 這個函數

function SuperClass(id) {
  this.books = ['super'];
  this.id = id;
}
function SubClass(id) {
  SuperClass.call(this,id);
}
var instance1 = new SubClass(10);
var instance2 = new SubClass(11);

instance1.books.push('sub');
console.log(instance1.books)    // ['super', 'sub']
console.log(instance2.books)    // ['super', 'sub']
console.log(instance1.id)       // 10
console.log(instance2.id)       // 11

 

能夠看出 經過call()這個函數改變函數的做用環境,在子類中調用父類是將子類中的變量拿到父類中執行了一遍。這一類繼承不涉及到原型,因此父類原型的方法就不能被子類繼承。

組合繼承:

 組合繼承就是結合了類式繼承中原型繼承,以及構造函數式繼承中在子類構造函數環境中執行一次父類 這兩點來繼承的

function SuperClass(id) {
  this.books = ['super'];
  this.id = id;
}
SuperClass.prototype.getId = function () {
  console.log(this.id);
}
function SubClass(id,name) {
    // 構造函數中繼承父類 id屬性
   SuperClass.call(this,id);
   this.name = name;
}
// 類式繼承原型繼承父類
SubClass.prototype = new SuperClass();
// 新增子類原型方法
SubClass.prototype.getName = function () {
  console.log(this.name);
}
var instance1 = new SubClass(10,'sub1');
var instance2 = new SubClass(11,'sub2');
 
instance1.books.push('sub1-1');
console.log(instance1.books)    // ['super', 'sub1-1']
console.log(instance2.books)    // ['super']
instance1.getName()             // 10
instance1.getTime()             // sub2

 

 寄生組合繼承 :

function inheritObject(o) {
  // 過渡對象
  function F() {}
  // 原型繼承
  F.prototype = o;
  // 返回一個原型繼承了父類對象的實例
  return new F();
}
function inheritPrototype(subClass, superClass) {
  // 複製一份父類的原型副本保存在變量中
  var p = inheritObject(superClass.prototype);
  //修正由於重寫子類原型致使子類constructor屬性被修改
  p.constructor = subClass;
  //設置子類的原型
  subClass.prototype = p;
}
function SuperClass(id) {
  this.books = ['super'];
  this.id = id;
}
SuperClass.prototype.getId = function () {
  console.log(this.id);
}
function SubClass(id,name) {
  // 構造函數中繼承父類 id屬性
  SuperClass.call(this,id);
  this.name = name;
}
inheritPrototype(SubClass, SuperClass)
SubClass.prototype.getName = function () {
  console.log(this.name);
}
var instance1 = new SubClass(12,'sub12');
var instance2 = new SubClass(13,'sub13');

 

最大的改變就是子類的原型被賦予了父類的原型的一個引用,此時子類想要添加原型方法必須經過prototype添加。

以上是ES6以前,在使用javascript繼承時大多采用的方法,那麼在ES6當中,咱們能夠採用關鍵字 簡潔明瞭的達到繼承的目的

 1 class ColorPoint extends Point {
 2  constructor(x, y, color) { 3 super(x, y); // 調用父類的constructor(x, y) 4 this.color = color; 5  } 6 7  toString() { 8 return this.color + ' ' + super.toString(); // 調用父類的toString() 9  } 10 }

在子類的構造函數中必須使用 super()來調用父類的構造函數,這是由於子類本身的this對象,必須先經過父類的構造函數構造,獲得與父類一樣的實例屬性和方法,而後再對其進行加工,加上子類本身的實例屬性和方法。若是不調用super方法,子類就得不到this對象。所以只有在調用super之後,子類的this才能正常使用。

多態

多態能夠理解爲,在調用方法時,更具傳遞參數的數量、類型不一樣時,具備多種實現方式。 能夠說根據接口不一樣,呈現不同的結果。 

 

對於ES6之前實現繼承,多態,封裝的原理,主要圍繞原型、原型鏈調用來實現,雖然說目前ES6能夠很好的實現這些靈魂玩法,包括目前大勢的TypeSScript更是把JS 引向了強類型語言的圈子,但萬變不離其宗,瞭解原理,才能更好的運用。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

相關文章
相關標籤/搜索