javascript是一門典型的動態類語言javascript
一:鴨式辨型(指導咱們關注對象的行爲,而不關注對象自己)。java
var duck = { duckString: function(){ console.log("嘎嘎") } }; var chicken = { duckString: function(){ console.log("嘎嘎") } } var choir = []; //合唱團 var joinChoir = function( animal ){ if (animal && typeof animal.duckString === 'function') { choir.push(animal); console.log('恭喜加入合唱團') console.log('合唱團已經有的數量:'+ choir.length) } } joinChoir(duck) joinChoir(chicken)
對於加入合唱團,無需關心他們的類型,而只是確保它有duckString方法。api
二:多態瀏覽器
多態的實際含義是,同一操做做用於不一樣的對象上面,能夠產生不一樣的解釋,執行不一樣的結果。 (其實是把「作什麼」和「誰去作」分離開來)函數
var makeSound = function( animal ) { if ( animal instanceof Dcuk) { console.log("嘎嘎") } else if ( animal instanceof Chiken) { console.log("咯咯") } } var Dcuk = function(){}; var Chiken = function(){}; makeSound(new Dcuk) makeSound(new Chiken)
(1多態的度複雜性this
var makeSound = function( animal ) { animal.sound() } var Dcuk = function() {}; var Chiken = function() {}; var Dog = function() {}; Dcuk.prototype.sound = function() { console.log("嘎嘎嘎") } Dog.prototype.sound = function() { console.log("汪汪汪") } makeSound(new Dcuk) makeSound(new Dog)
將行爲分享在各個對象中,並讓這些對象各自負責本身的行爲,這正是面向對象優勢google
假設咱們要編寫一個地圖應用,如今有兩家可選的地圖api提供商供咱們接入本身的應用。目前咱們選擇谷歌地圖,谷歌地圖中提供show()方法,負責在頁面上展現整個地圖。spa
var googleMap = { show: function() { console.log('開始渲染地圖') } } var renderMap = function() { googleMap.show() } renderMap()
後來由於某些緣由,咱們要將谷歌地圖轉化爲百度地圖,爲了讓renderMap函數保持必定的彈性,咱們使用一些條件分支來讓renerMap函數同時支持谷歌地圖和百度地圖prototype
var googleMap = { show: function() { console.log("渲染谷歌地圖") } } var baiduMap = { show: function() { console.log("渲染百度地圖") } } var renderMap = function( type ){ if ( type === 'google') { googleMap.show() } else if ( type === 'baidu') { baiduMap.show() } } renderMap('baidu') renderMap('google')
雖然renderMpa函數保持了必定的彈性 ,可是這種彈性是很脆弱的,一旦替換成搜狗地圖,那無疑須要改動renderMap()函數,繼續往裏邊堆砌條件分支語句。code
var renderMap = function ( map ){ if (map.show instanceof Function) { map.show(); } } var sosoMap = { show: function() { console.log("搜搜地圖開始渲染") } } renderMap(googleMap) renderMap(baiduMap) renderMap(sosoMap)
如今咱們來找找這段代碼的多態性,當咱們向谷歌地圖對象和百度地圖對象發出「展現地圖的」請求時。會分別調用他們的show()方法。會產生不一樣的執行結果。對象的多態性提示咱們,「作什麼」和「怎麼去作」是能夠分開的,即便之後增長了搜搜地圖,renderMap函數任然不須要作出什麼改變。
三 封裝
封裝的目的是將信息隱藏,通常而言,咱們討論的封裝是封裝數據和封裝實現。
這裏咱們將說明下更廣義的封裝,不只包括封裝數據和封裝實現,還包括封裝類型和封裝變化
1。封裝數據
在許多語言的對象系統中,封裝數據是由語法解析實現的,這些語言提供了private, public, protected等關鍵字來提供不一樣的訪問權限
javascript沒有提供對這些關鍵字的支持,咱們只能依賴變量的做用域來實現封裝特性,並且只能模擬出public,private這兩種封裝。
除了ES6的let以外,咱們通常經過函數來建立做用域。
var myObject = (function() { var _name = 'seven'; //私有private變量 return { getName : function() { //公開public變量 return _name; } } })(); console.log(myObject._name) ;//undefined console.log(myObject.getName()) ;//seven
另外,在ES6中,還能夠經過Symbol建立私有屬性
四:使用克隆的原型模式
若是使用原型模式,咱們只須要負責克隆的方法,變能完成一樣的功能。
原型模式使用的關鍵,是語言自己是否提供了克隆的方法,ES5提供了Object.create方法,代碼以下
var Plane = function() { this.blood = 100; this.attackLevel = 1; this.defenseLevel = 1; }; var _plane = new Plane() _plane.blood = 500; _plane.attackLevel = 2; _plane.defenseLevel = 2; var clonePlane = Object.create( _plane ); console.log( clonePlane ) // {blood: 500, attackLevel: 2, defenseLevel: 2} //不支持Object.create方法的瀏覽器中,能夠使用如下代碼 Object.create = Object.create || function( obj ) { var F = function() {}; F.prototype = obj; return new F(); }
原型繼承
在javascript語言裏,咱們並不關心克隆的細節,由於這是引擎內部實現的。咱們只是顯式的調用
var object1 = new Object()或者 var object2 = {};此時,引擎內部會從Object.protype上面克隆出一個對象來,咱們最終獲得的就是這個對象。
咱們看看經過new運算符從構造器中獲得一個對象,下面的代碼最熟悉不過了。
function Preson( name ) { this.name = name; } var a = new Preson("seven2"); console.log(a.name) //seven2 Preson.prototype.getName = function() { return this.name } console.log(a.getName()) //seven2
對象會記住它的原型。
var b = new Object(); console.log(b.__proto__ === Object.prototype) ;//true
附上咱們最經常使用的原型繼承方式
var obj = {name:'seven3'}; var A = function(){}; A.prototype = obj; //{name:'seven3'}; var aa = new A() console.log(aa.name)
咱們常指望一個類繼承另一個類時 ,每每使用如下代碼來模擬
var AA = function() {}; AA.prototype = {name:"seven4"} var BB = function() {}; BB.prototype = new AA() var bb = new BB(); console.log(bb.name);//seven4