前端開發之面向對象
【一】 面向對象的基本概念
面向對象的英文全稱叫做Object Oriented,簡稱OO。OO其實包括OOA(Object Oriented Analysis,面向對象分析)、OOD(Object Oriented Design,面向對象設計)和OOP(Object Oriented Programming,面向對象的程序設計)。
通常所說的面向對象是指OOP, OOP是一種圍繞真實世界的概念來組織模型的程序設計方法,它采用對象來描述問題空間的實體。在使用計算機解決問題時,對象是作為計算機模擬真實世界的一個抽象,一個對象就是一個物理實體或邏輯實體,它反映了系統為之保存信息和(或)與它交互的能力。使其具有自己的屬性和行為, 從而簡化對復雜事物的描述,更有利于工程的可維護性和擴展性。
OOP同結構化程序設計相比最大的區別就在于: 前者首先關心的是所要處理的數據,而后者首先關心的是功能。
【二】 面向對象三個基本特征
封裝 (Encapsulation) 將數據以及相關的操作組織在一起,成為獨立的構件。外部無法直接訪問這些封裝了的數據,從而保證了這些數據的正確性。封裝的目的是為了內部數據表現形式和實現細節的隱藏,信息隱藏是為了減少系統各部分間的依賴性,各部分間必須通過明確的通道傳送信息,也就是對象間的接口.這樣一來,隱藏了部分內部的細節,極大方便系統的開發,維護和擴展。
繼承 (Inheritance) 繼承是一種聯結類的層次模型,并且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。一個新類可以從現有的類中派生,這個過程稱為類的繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那里繼承方法和實例變量,并且派生類可以修改或增加新的方法使之更適合特殊的需求。繼承性很好地解決了軟件的可重用性問題。
多態 (Polymorphism) 多態是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是允許類與類之間相同方法名的指針得以調用, 這樣很好地解決了應用程序函數同名問題。實現多態,有二種方式,覆蓋,重載。
【三】 Javascript 面向對象
javascript本身是一種基于對象(object-based)的語言,我們日常編碼過程中用到的所有東西幾乎都是對象(Number, String, Boolean, etc.)。但是,相對于一些流行的面向對象語言(C++, C#, java),它又不是一種真正的面向對象編程(OOP)語言,因為它的語法中沒有class的概念。
Keyword: class, object, `this`, closure, constructor, prototype
幾種對象封裝的方法
- 繼承
- 多態體現
之一、幾種對象封裝的方法
1. 對象封裝 – 原始模式
假定我們把貓看成一個對象,它有”name”和”color”兩個屬性, “etc” 行為。
var Cat = { name: '' color: '', eat: function() {} };
現在,我們需要根據這個原型對象的規格(schema),生成兩個實例對象。
function eat() { console.log('I\'m eta fish'); } var cat1 = {name: 'Kitty', color: 'white', eat: eat}; var cat2 = {name: 'Smokey', color: 'black', eat: eat}; // var cat3, cat4 ,...
不方便創建多個實例對象,擴展性差, 實例(cat1, cat2)之間找不到聯系。…
2. 對象封裝 – 構造函數模式
“構造函數”,就是一個普通函數,但是內部使用了 `this` 變量。對函數使用 `new` 運算符,就能生成實例,并且 `this` 變量會綁定在實例對象上。
使用構造器創建出來的對象會有一個 `constructor` 屬性,指向它們的構造函數。
`Class` 只是一個模板,創建出來的來實例都是由模板生成。
比如,貓的原型對象現在可以這樣寫:
function Cat(name,color){ this.name = name; this.color = color; this.eat = function() { console.log('eat fish'); }; } var cat1 = new Cat('Kitty', 'black'); console.log(cat1.name); // Kitty console.log(cat1 instanceof Cat); // TRUE // 這時 cat1 實例會自動含有一個 `constructor` 屬性,指向它們的構造函數 `Cat`。 var cat2 = Cat('Smokey', 'white'); console.log(cat2); // undefined
3. 對象封裝 – Prototype 模式
`prototype` 是 `Function` 對象的一個屬性,這個屬性指向另一個對象。 這個對象的所有屬性和方法,都會被構造函數的實例繼承。
同時 `prototype` 又存在一個指向構造函數的引用 `constructor`,這樣就成功的構成一個循環引用的原型鏈結構。
我們可以把那些不變的屬性和方法,直接定義在 `prototype` 對象上, 節省內存開銷。
function Cat(name, color) { this.name = name; this.color = color; } Cat.prototype.type = 'mammal'; Cat.prototype.eat = function() { console.log('eat fish'); }; var cat1 = new Cat('Kitty', 'white'); var cat2 = new Cat('Smokey', 'black'); console.log(cat1.type); // mammal console.log(cat1.eta === cat2.eta); // TRUE, same reference console.log(cat1.constructor === Cat) // TRUE, from Person.prototype
之二、繼承 (Inheritance)
將持有共性特點的屬性或行為抽象出一個基本類, 可以按不同層次結構的業務分組抽象出多個基礎類。
Cat, Bird
1. 繼承 – 構造函數綁定
使用call或apply方法,將父對象的構造函數綁定在子對象上。
function Animal() { this.species = 'animal'; this.sleep = function() { console.log('I\'m sleep at night'); }; } function Cat(name, color) { this.name = name; this.color = color; }
讓`Cat` 繼承 `Animal` 的特性:
/** @class Cat */ function Cat(name, color) { Animal.apply(this); this.name = name; this.color = color; } var cat1 = new Cat('Kitty', 'white'); cat1.sleep(); // I am sleep at night
2. 繼承 – 原型鏈繼承
如果”貓”的prototype對象,指向一個Animal的實例,那么所有”貓”的實例,就能繼承Animal了。
/** @class Cat */ function Cat(name, color) { this.name = name; this.color = color; } Cat.prototype = new Animal; Cat.prototype.eta = function() { console.log('fish is my delicious'); };
它相當于完全刪除了prototype 對象原先的值,然后賦予一個新值
// 任何一個prototype對象都有一個constructor屬性,指向它的構造函數 Cat.prototype.constructor = Cat; // fix prototype chains var cat = new Cat('Kitty', 'fish'); cat.eat(); // fish is my delicious cat.sleep(); // I'm sleep at night' console.log(cat instanceof Cat); // TRUE console.log(cat instanceof Animal); // TRUE
需要創建父類實列來實現 `prototype` 繼承
3. 繼承 (Inheritance) – 利用空對象作為中介實現原型繼承
var F = function() {}; F.prototype = Animal.prototype; Cat.prototype = new F(); Cat.prototype.constructor = Cat;
我們將上面的方法,封裝成一個函數,便于使用。
function extend(ctor, superctor, px) { if (!superctor || !ctor) throw Error('extend failed, verify dependencies'); var F = function() {}; F.prototype = superctor.prototype; ctor.prototype = new F(); ctor.prototype.constructor = ctor; ctor.superclass = superctor.prototype; // cache super class proto reference. if (px) { // extend class implements for (var k in px) { if (px.hasOwnProperty(k)) ctor.prototype[k] = px[k]; } } return ctor; }
4 繼承 – 借住工具方法實現繼承
/** @class Mammal */ extend(Cat, Animal, { eat: function() { Cat.superclass.eat.call(this); // call super method console.log('Also i like some ofther food, such as beef and more.'); } }); var cat = new Cat('Smokey', 'fish'); cat.sleep(); cat.eat(); console.log(cat instanceof Animal); console.log(cat instanceof Cat);
之三、多態
1. 多態 – 通過重寫原型方法來實現方法重名調用
/** @class Cat */ extend(Cat, Animal, { eat: function() { Cat.superclass.eat.call(this); // call super method console.log('Also i like some ofther food, such as beef and more.'); } });
2. 多態 (Polymorphism) – 原型繼承 `prototype` 鏈上的方法、屬性查找
【四】總結 Summary
Constructor
Prototype
Inheritance