JavaScript作為一門動態(tài)類型語言,它在編譯(解釋)時沒有類型檢查的過程纯路,既沒有檢查創(chuàng)建創(chuàng)建的對象類型或油,有沒有檢查傳遞的參數(shù)類型。
我的讀書筆記感昼,我想來記錄一下自己認識的JavaScript的多態(tài)装哆,多態(tài)是面向?qū)ο缶幊陶Z言中最最重要的技術(shù),個人理解多態(tài)就是把“做什么”和“誰去做”分離出來,歸根結(jié)底就是消除類型之間的耦合關(guān)系蜕琴。
畢竟大部分人都不關(guān)心雞是怎么叫萍桌,也不想知道鴨是怎么叫。
多態(tài)的最根本的好處在于凌简,你不必再向?qū)ο笤儐枴澳闶鞘裁搭愋汀鄙涎祝蟾鶕?jù)得到的答案調(diào)用某個對象的行為--你只管調(diào)用該行為就是了,其他的一切多態(tài)機制都會為你安排妥當雏搂!
將行為分布在各個對象中藕施,并讓這些對象各自負責自己的行為,這正是面向?qū)ο笤O(shè)計的特點
1.多態(tài)
/*
* 編寫一個地圖的應(yīng)用凸郑,我們可能需要調(diào)用百度地圖裳食,搜狗地圖,谷歌地圖等應(yīng)用
* 那么我們現(xiàn)在就來完成對多態(tài)的體現(xiàn)的代碼應(yīng)用
* */
var googleMap = {
show:function () {
console.log("開始渲染谷歌地圖");
}
}
var baidudMap={
show:function () {
console.log("開始選擇百度地圖");
}
}
//建立渲染的方法
var renderMap = function(map/*傳遞地圖對象*/){
//判斷你調(diào)用的show的類型是否為函數(shù)芙沥?
if(map.show instanceof Function){
map.show();
}
}
//測試
renderMap(googleMap);
renderMap(baidudMap);
翻譯如下: 當我們想谷歌地圖對象和百度地圖對象分別發(fā)出“展示地圖”的消息時候诲祸,分別調(diào)用他們的show方法,就會產(chǎn)生不同的執(zhí)行結(jié)果而昨。對象的多態(tài)性提示我們救氯,“做什么”和“怎么做”是可以分開的,以后增加搜狗地圖歌憨,renderMap函數(shù)仍然不需要做任何變化着憨!
2.封裝
在多數(shù)的對象語言中,封裝數(shù)據(jù)是由語法解析實現(xiàn)的务嫡。例如我們學(xué)習的Java語言提供了private甲抖、public、protected等關(guān)鍵字來提供不同的訪問權(quán)限
但是植袍,JavaScript中并沒提供這些訪問權(quán)限的關(guān)鍵字惧眠,我們只能依賴 變量的作用域來實現(xiàn)封裝特性,而且只能模擬出public和private這兩種封裝性
var hpObject = (function () {
var __name="胖先森";//私有(private)變量
return {
getName:function () {// 公開(public)方法
return __name;
}
}
})();
console.log(hpObject.getName()); // 輸出:胖先森
console.log(hpObject.__name); // 輸出:undefined
目前通過函數(shù)創(chuàng)建作用域比較常見于个,如果你使用的ECMAScript 6 抱歉我沒有研究,但是知道其提供了 let 關(guān)鍵字暮顺,定義私有變量
上面僅僅是一個封裝數(shù)據(jù)的示例厅篓,但是不要說封裝等同于封裝數(shù)據(jù),這樣就是井底之蛙捶码!
封裝實現(xiàn)的目的:將信息隱藏羽氮,封裝應(yīng)該被視為“任何形式的封裝”,也就是說惫恼,封裝不僅僅是隱藏數(shù)據(jù)档押,還包括隱藏實現(xiàn)細節(jié),設(shè)計細節(jié)以及隱藏對象的類型等挺邀。
什么時候使用封裝呢祠斧? 個人的理解為:找到變化并封裝之饥侵,這里就涉及到設(shè)計模式(面試題:一共有多少設(shè)計模式呢尸变?)哗总,還有如果工作一些年了琳轿,你應(yīng)該知道重構(gòu)代碼的重要性户侥!
通過封裝剔猿,我們要達到什么目的呢癞松?就是把系統(tǒng)中 穩(wěn)定不變的部分 和 容易變化的部分 隔離爽撒!
3.繼承
主要說一下JavaScript的原型繼承,這里自己也是剛剛?cè)腴T响蓉,如果不太好的地方見諒硕勿!
需要大家記住,原型編程的基本準則:
- 所有數(shù)據(jù)都是對象 “萬物皆對象”
- 要得到一個對象枫甲,不是通過 實例化源武,而是找到一個對象作為原型并 克隆它
- 對象會記住它的原型(你的父親你不記得?)
- 如果對象無法響應(yīng)某個請求言秸,它會把這個請求委托給它自己的原型软能。(例如,自己克隆自己)
(1)所有數(shù)據(jù)都是對象
JavaScript的數(shù)據(jù)類型機制: 基本類型和對象類型
基本類型包括:
- 特殊數(shù)據(jù)類型
- undefined
- null
- 基本數(shù)據(jù)類型
- string
- boolean
- number
- 復(fù)雜數(shù)據(jù)類型
- object
- function (這個好像不算)
ECMAScript 6 里面增加了一個數(shù)據(jù)類型 symbol
JavaScript作者本意是除了undefined以外举畸,一切都是對象查排!為了實現(xiàn)這個目標number、boolean抄沮、string這幾種基本數(shù)據(jù)類型也是通過“包裝類(學(xué)Java的時候有類似的概念)”的方式變成對象類型數(shù)據(jù)來處理跋核。
我們不能說JavaScript的多有數(shù)據(jù)都是對象,但是絕大部分都是對象叛买。那么JavaScript中一定會有一個 根對象 存在
事實上砂代,JavaScript中的跟對象是 Object.prototype 對象。Object.prototype 對象是一個 空的對象率挣,實際上都是從 Object.prototype 對象克隆而來的刻伊。
var hp01 = new Object();//聲明一個對象
var hp02 = {};// 創(chuàng)建一個對象,推薦方式
//利用 Object.getPrototypeOf方法檢測原型
console.log(Object.getPrototypeOf(hp01) === Object.prototype);// 輸出:true
console.log(Object.getPrototypeOf(hp02) === Object.prototype);// 輸出:true
(2)要得到一個對象椒功,不是通過實例化類捶箱,而是找到一個對象作為原型并克隆它
在JavaScript語言中,我們不需要關(guān)心克隆的細節(jié)动漾,而是由引擎內(nèi)部負責實現(xiàn)的丁屎。
那么,我就有一個疑問:new 運算符不是實例化嗎旱眯? 我們看一下下面的經(jīng)典代碼:
function Person( name ){
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
var a = new Person("胖先森");
console.log(a.name); // 輸出:胖先森
console.log(a.getName()); //輸出:胖先森
//檢查對象
console.log(Object.getPrototypeOf(a) === Person.prototype);// 輸出:true
在JavaScript中沒有類的概念晨川,這句話必須要時刻保持警惕证九!
但是,剛才明明不是已經(jīng)調(diào)用了 new Person() 嗎共虑?如果按照Java的理解愧怜,這不就是實例化對象嗎?
在這里Person不是類看蚜,而是 函數(shù)構(gòu)造器叫搁,JavaScript的函數(shù)既可以作為 普通函數(shù) 被調(diào)用 ,也可以作為 構(gòu)造函數(shù) 被調(diào)用供炎。用 new 運算符來創(chuàng)建對象的過程渴逻,實際上是
先克隆了 Object.prototype 對象 ,再進行一些其他額外的操作過程:
JavaScript是通過克隆 Object.prototype 來得到新的對象音诫,但是實際上不是每次都真正克隆一個新對象惨奕。
從內(nèi)存方面考慮出發(fā),JavaScript還是做了一些額外的處理竭钝。
(3)對象會記住它的原型
記桌孀病:JavaScript給對象提供了隱藏屬性 __proto__ ,某個對象的 __proto__ 屬性會默認指向它的構(gòu)造器的 原型對象 ,即 {Constructor}.prototype 香罐。
var hp = new Object();
console.log(hp.__proto__ === Object.prototype);
__proto__就是對象跟“對象構(gòu)造器的原型” 聯(lián)系起來的紐帶卧波。
這個地方我理解的還是不夠透徹,在后面的學(xué)習中庇茫,繼續(xù)努力港粱!
(4)如果對象無法響應(yīng)某個請求,它會把這個請求委托給它自己的原型
JavaScript中每個對象都是從 Object.prototype 對象克隆而來旦签。如果這樣的話查坪,就特別像我們之前學(xué)習的Java一樣就成為了單一繼承,即每個對象都繼承了 Object.prototype , 顯示這樣的設(shè)計是受到了一定的限制宁炫。
實際上偿曙,雖然JavaScript的對象最初都是由Object.prototype對象克隆而來,但是對象 構(gòu)造器的言行并不是限于Object.prototype 上羔巢,而是可以 動態(tài) 指向其他對象望忆。
一段比較經(jīng)典的繼承寫法:
var root = {name:"胖先森"};
var A = function () {
}
A.prototype = root;
var a = new A();
console.log(a.name);
比較常用的方式
說在后面的話:
花了一天時間,整理出來一點筆記竿秆! 如果感覺好炭臭,請記得打賞一下!