標籤:java 使用 os io 資料 for art cti
面向過程編程,物件導向編程和函數式編程
> 定義一個類
方法1:
function Anim(){
}
Anim.prototype.start = function(){ .. };
Anim.prototype.stop = function(){ .. };
或者
方法2:
function Anim(){ .. }
Anim.prototype = {
start: function(){.. },
stop: function(){ .. },
constructor: Anim
}
或者
方法3:
//從視覺上 整個類都在建構函式中定義
function Anim(){
...
if(!Anim.prototype.version){ //假設version是這個類 肯定具備的方法
Anim.prototype.version = ‘1.0‘;
Anim.prototype.start = function(){..};
Anim.prototype.stop = function(){...};
}
}
new Anim(); //第1次new的時候 完成對原型對象的定義
或者
方法4:
把向函數原型對象添加方法的流程定義為函數,如:
Function.prototype.method = function(name, fn){
this.prototype[name] = fn;
return this; //使可以鏈式調用
}
//與第1中方法沒什麼差別
function Anim(){...}
Anim.method(‘start‘, function(){..});
Anim.method(‘stop‘, function(){..});
> js的資料類型:原始類型 number string boolean null undefined, 參考型別 object ( array, function, regexp, math, number, string, boolean)
未經處理資料類型按值傳遞; 參考型別按引用傳遞(即引用地址)
資料類型轉換:
toString();
parseInt();
parseFloat();
!!number
注意 js的隱式類型轉換
> 函數是一等對象,可以儲存在變數中,可以作為參數傳遞,可以作為函數傳回值返回。
匿名函數可以激發一個範圍,無影響全域環境,實現資料封裝
(function(){
var foo = 10;
var bar = 2;
alert(foo * bar);
})();
var result = (function(foo, bar){
return foo * bar
})(20, 10);
js具有函數範圍,js的範圍是詞法範圍(函數運行在定義它的範圍中,而不是在調用它的範圍中)
匿名函數最有趣的用途是建立閉包。
用匿名函數建立閉包的例子:
var baz;
(function(){
var foo = 10;
var bar = 2;
baz = function(){
return foo * bar;
}
})();
baz(); //20
> js的對象都是易變的
/* class Person */
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype = {
getName: function(){ reutn this.name },
getAge: function(){ return this.age },
constructor: Person
}
/* instantiate the class */
var alice = new Person(‘Alice‘, 19);
/* modify the class */
Person.prototype.geeting = function(){ return ‘Hi,‘ + this.getName + ‘!‘};
/* modify the instance */
alice.displayGeeting = function(){
alert(this.geeting());
}
js中,任何東西都能夠在運行時修改
> 繼承
原型式繼承 和 類式繼承 兩種繼承範型
在js中使用設計模式的好處:可維護性,效能,程式員間溝通;缺點:複雜性 效能(有的模式對效能有負面影響,有的能提高效能)
-----------------------------------
介面
-----------------------------------
介面:提供了一種說明一個對象應該具有什麼方法的手段
假設一批對象實現了相同的介面,那麼即使他們彼此不相關都可以被同樣對待
如: 一批對象都實現了 comparable介面, 那麼就可以調用 obj.compare(obj2);
介面可以告訴程式員一個類實現了哪些方法,介面說明了一個類具有哪些特性和操作
> js中的模仿介面的方法: 注釋法,屬性檢查法,鴨式辨型
1.注釋法:
/*
interface Composite{
function add(child);
function remove(child);
function getChild(index);
}
interface FormItem{
function save();
}
*/
var CompositeForm = function(id, method, action){//implements Composite, FormItem
...
};
//implement the Composite interface
CompositeForm.prototype.add = function(child){ .. };
CompositeForm.prototype.remove = function(child){ .. };
CompositeForm.prototype.getChild = function(index){ ..};
//implement the FormItem interface
CompositeForm.prototype.save = function(){...};
依靠程式員自覺遵守介面約定,不影響執行效能;但是沒有錯誤提示
2.屬性檢查法:
/*
interface Composite{
function add(child);
function remove(child);
function getChild(index);
}
interface FormItem{
function save();
}
*/
var CompositeForm = function(id, method, action){
this.implementsInterfaces = [‘Composite‘, ‘FormItem‘];//自稱實現了哪些介面
...
}
function addForm(formInstance){// 調用執行個體的一個方法
if(!implements(formInstance,‘Composite‘, ‘FormItem‘)){//檢查執行個體是否實現了指定的介面
throw new Error(‘instance do not implement the required interfaces‘);
}
...
}
//檢查所需介面是否在執行個體對象自稱實現的介面數組中能找到
~~ 檢查傳入的介面名,是否都在自稱實現的介面數組中能找到
function implements(object){
for(var i=1; i<arguments.length; i++){ //遍曆傳入的介面
var interfaceName = argument[i];
var interfaceFound = false;
for(var j = 0; j < object.implementsInterfaces.length; j++){
if(object.implementsInterfaces[j] == interfaceName){
interfaceFound = true;
break;
}
}
if(!interfaceFound) {return false;}
}
return true; //沒有中途退出 即所有介面都能找到
}
3.鴨式辨型:走路嘎嘎叫的就是鴨子
如果對象具有與介面定義的方法同名的所有方法,就認為它實現了這個介面
/* class Interface */
var Composite = new Interface(‘Composite‘,[‘add‘, ‘remove‘, ‘getChild‘]);
var FormItem = new Interface(‘FormItem‘,[‘save‘]);
//class CompositeForm
var CompositeForm = function(id, method, action){
...
}
function addForm(formInstance){
ensureImplements(formInstance, Composite, FormItem);
...
}
保證類真正實現了介面定義的方法,缺點:類沒有聲明自己實現了哪些介面
比較好的方法是結合注釋法 + 鴨式辨型 如:
// Interfaces
var Composite = new Interface(‘Composite‘,[‘add‘, ‘remove‘, ‘getChild‘]);
var FormItem = new Interface(‘FormItem‘,[‘save‘]);
//class CompositeForm
var CompositeForm = function(id, method, action){ //implements Composite, FormItem
...
}
function addForm(formInstance){
ensureImplements(formInstance, Composite, FormItem);
...
}
/** class Interface **/
function Interface(name, methods){
if(arguments.length !== 2){
throw new Error(‘expect 2 arguments‘);
}
this.name = name;
this.methods = [];
if(methods.constructor !== Array){ throw new Error(‘expect an array for methods param‘)}
for(var i =0, len=methods.length; i<len; i++){
if(typeof methods[i] !==‘string‘){
throw new Error(‘expect string value‘);
}
this.methods.push(methods[i]);
}
}
/** ensureImplements method **/
function ensureImplements(object){
if(arguments.length < 2){ throw new Error(‘expect arguments at least 2‘); }
for(var i=1, len=arguments.length; i<len; i++){
var interface = arguments[i];//遍曆介面
if(interface.constructor !== Interface){
throw new Error(‘expect this argument to be Interface instance‘);
}
for(var j=0,mLen=interface.methods.length; j<mLen; j++){//遍曆介面的方法
var method = interface.methods[j];
if(!object[method] || typeof object[method] !==‘function‘){
//若object沒有跟介面方法同名的方法 則拋出異常
throw new Error(‘not the method:‘+method);
}
}
}
}
介面降低了對象間的耦合度,提高了代碼的靈活性,不要求對象間有繼承關係,只要它們實現了同樣的介面,就可以同等對待。
介面記載著api,可作為程式員交流的工具
應用情境:對外部提供的服務api如搜尋 地圖 郵件等,建立一個Interface對象,對接收到每個對象做介面檢查,如:
var DynamicMap = new Interface(‘DynamicMap‘,[‘centerOnPoint‘,‘zoom‘,‘draw‘]);
function displayRoute(mapInstance){//自己用到的執行個體方法做成介面,保證傳入的執行個體確實有這些方法
ensureImplements(mapInstance, DynamicMap);
mapInstance.centerOnPoint(12,34);
mapInstance.zoom(3);
mapInstance.draw();
...
}
是否需要使用介面做檢查,取決於項目的大小,和做檢查的必要性。
對傳入對象做介面檢查(是否實現某個介面)比做類檢查(是否某個類),要有保證和靈活一點。
依賴於介面的設計模式
原廠模式、組合模式、裝飾者模式、命令模式
>> 封裝和資訊隱藏
為對象建立私人成員是物件導向語言最基本和最有用的特性之一。封裝是物件導向的基石。
js中的封裝是通過閉包來實現的。
資訊隱藏有助於減輕功能模組間的依賴度,只需要獲得結果,不需要知道具體的內部實現。
封裝:對對象內部資料和實現細節的隱藏,許多物件導向語言用關鍵字聲明 該屬性或方法為隱藏的(私人的), JAVA中private
,js中用閉包
封裝:隱藏對象內部的資料和實現細節,只能用已定義的方法訪問對象的資料。
>> 建立對象的基本模式
> 門戶大開型對象 (對象的所有屬性都是公用成員)
var Book = function(isbn, title, author){
if(isbn == undefined) throw new Error(‘isbn is required‘); //沒檢查isbn是否正確,可能影響資料庫檢索和display圖書資訊
//to => if(!this.checkIsbn(isbn)) throw new Error(‘isbn is invalid‘);
this.isbn = isbn;
this.title = title || ‘no title specified‘;
this.author = author || ‘no author specified‘;
}
Book.prototype.display = function(){
... //產生顯示圖書資訊的元素
}
Book.prototype.checkIsbn = function(){
...
}
---------
改為:只能通過getter,setter訪問門戶大開型對象的屬性
var Publication = new Interface(‘Publication‘,[‘getIsbn‘,‘setIsbn‘,‘getTitle‘,‘setTitle‘,‘getAuthor‘, ‘setAuthor‘,‘display‘]);
var Book = function(isbn, title, author){
this.setIsbn(isbn);
this.setTitle(title);
this.setAuthor(author);
}
Book.prototype = {
constructor: Book,
getIsbn: function(){return this.isbn},
setIsbn: function(isbn){ if(!this.checkIsbn(isbn) ){ throw new Error(‘invalid isbn‘)}else{ this.isbn = isbn } },
getTitle: function(){ return this.title},
setTitle:function(title){ return this.title = title || ‘no specified title‘},
getAuthor: function(){ return this.author},
setAuthor:function(Author){ return this.author = author || ‘no specified Author‘},
display: function(){...},
checkIsbn: function(){..}
}
但是
book = new Book(‘0-234-234-034-9‘,‘something in life‘, ‘kitty‘);
book.isbn = ‘0-000-000-000-2‘; //執行個體對象的屬性還是可以任意修改的
優點:簡單,易於理解
缺點:所有屬性和方法公開 無法保護內部資料,getter,setter增加代碼量
> 用命名規範區別私人成員 ( 屬性名稱加_首碼表明其為私人,如:_name = ‘kitty book‘ )
var Book = function(isbn, title, author){
this.setIsbn(isbn);
this.setTitle(title);
this.setAuthor(author);
}
Book.prototype = {
constructor: Book,
getIsbn: function(){return this._isbn},
setIsbn: function(isbn){ if(!this.checkIsbn(isbn) ){ throw new Error(‘invalid isbn‘)}else{ this._isbn = isbn } },
getTitle: function(){ return this._title},
setTitle:function(title){ return this._title = title || ‘no specified title‘},
getAuthor: function(){ return this._author},
setAuthor:function(Author){ return this._author = author || ‘no specified Author‘},
display: function(){...},
checkIsbn: function(){..}
}
> 範圍 嵌套函數和閉包
js只有函數範圍,而且是詞法範圍,函數是運行在定義它們的範圍,而不是調用它們的範圍的。
返回一個內嵌函數是建立閉包的常用方法。
var Book = function(newIsbn, newTitle, newAuthor){// implements Publication
var isbn, title, author; //私人屬性
function checkIsbn(isbn){...} //私人方法
this.getIsbn = function(){ return isbn }; //特權方法
this.setIsbn = function(newIsbn){ if(checkIsbn(newIsbn)) isbn = newIsbn; };//特權方法
this.getTitle = ..
this.setTitle = ..
this.getAuthor = ..
this.setAuthor = ..
//初始化對象私人資料
this.setIsbn(newIsbn);
this.setTitle(newTitle);
this.setAuthor(newAuthor);
}
Book.prototype = {
construcor: Book,
display: function(){..} //公用方法,非特權方法
}