js的兩面-面向過程和面向對象


js是面向過程還是面向過程?一直以來,頂級大師各有各的說法,這里不敢妄加評論。
面向過程就是函數式編程,按照傳統流程編寫一個又一個的函數來解決需求的方式。
面向過程適合一個人的項目,如果是團隊合作,別人想修改你的代碼就不利於維護了。所以下面着重聊聊面向對象。
面向對象就是講你的需求抽象成一個對象,然后針對這個對象分析其屬性和方法。
面向對象的主要特點就是封裝,繼承,多態。
**一,封裝**
封裝就是把所需要的功能都放到一個對象里。例如
var News=function(id,product,group){
this.id=id;
this.product=product;
this.group=group;
}
也可以通過原型來添加屬性和方法。如:
News.prototype.display=function(){
//顯示新聞
}
這樣我們將所需要的屬性和方法都封裝到我們抽象的News類里面,當使用功能和方法時,我們不能直接使用News這個類,需要使用new關鍵字來實例化
新的對象。例如:
var normal_news=new News(1024,"今日頭條","北京事業組");
上面this添加的屬性和方法是在當前對象上添加的,然而原型創建對象都有prototype,用於指向其繼承的屬性,方法。這樣通過prototype繼承的方法
並不是對象自身的,所以在使用這些方法時,需要通過prototype一級一級查找來得到。這樣你會發現通過this定義的屬性或者方法是該對象自身擁有的,
所以我們每次通過類創建一個新對象時,this指向的屬性和方法都會得到相應的創建,而通過prototype繼承的屬性或者方法是每個對象通過prototype
訪問到,所以我們每次通過類創建一個新對象時這些屬性和方法不會再次創建。如圖所示:

這里寫圖片描述

通過new關鍵字創建的對象實質是對新對象this的不斷賦值,並將prototype指向類的prototype所指向的對象,而類的構造函數外面通過點語法定義的屬性
方法是不會添加到新創建的對象上去的。因此要想在新創建的對象中使用display就得通過News類使用而不能通過this,如News.display,而類得原型
prototype上定義得屬性在新對象里就可以直接使用,這是因為新對象的prototype和類的prototype指向的是同一個對象。

由於每次實例化對象的時候都需要用 new 關鍵字,所以js實例化有一種安全模式。如下
var News=function(id,product,group){
if(this.instanceof News){
this.id=id;
this.product=product;
this.group=group;
}else{
return new News(id,product,group);
}
}
這樣就不用擔心忘記使用new關鍵字的問題了。

二,繼承
每個類都有三部分,第一部分是構造函數內的,這是供實例化對象復制用的,第二部分是構造函數外的,直接通過點語法添加的,這是供類使用的看,
實例化對象時訪問不到的,第三部分是類的原型中的,實例化對象可以通過其原型鏈間接地訪問到,也是為供所有實例所共用的。然而在繼承中所涉
及的不僅僅是一個對象。
在JavaScript中沒有繼承這一現有的機制,那怎么實現呢!
2.1 子類的原型對象--類式繼承
//類式繼承
//聲明父類
function SuperClass(){
this.superValue=true;
}
//為父類添加共有方法
SuperClass.prototype.getSuperValue=function(){
return this.superValue;
}
//聲明子類
function SubClass(){
this.subValue=false;
}
//繼承父類
SubClass.prototype=new SuperClass();
SubClass.prototype.getSubValue=function(){
return this.subValue;
};
繼承很簡單,就是聲明兩個類而已,不過類式繼承需要將第一個類的實例賦值給第二個類的原型。
類的原型對象的作用就是為類的原型添加共有方法,但類不能直接訪問這些屬性和方法,必須通過原型prototype來訪問。而我們實例化一個父類的時候,
新創建的對象復制了父類的構造函數內的屬性與方法並且將原型__proto__指向了父類的原型對象,這樣就擁有了父類的原型對象上的屬性和方法,
並且這個新創建的對象可直接訪問到父類原型對象上的屬性和方法,如果我們將這個新創建的對象賦值給予類的原型,那么子類的原型就可以訪問到父類
的原型屬性和方法,新創建的對象不僅僅可以訪問父類原型上的屬性和方法,同樣也可訪問從父類構造函數中復制的屬性和方法。你將這個對象賦值給予
類的原型,那么這個子類的原型同樣可以訪問父類原型上的屬性和方法與從父類構造函數中復制的屬性和方法。
2.2 創建即繼承--構造函數繼承
//構造函數式繼承
//聲明父類
function SuperClass(id){
//引用類型共有屬性
this.books=['JavaScript','html','css'];
//值類型共有屬性
this.id=id;
}
//父類聲明原型方法
SuperClass.prototype.showBooks=function(){
console.log(this.books);
}
//聲明子類
function SubClass(id){
//繼承父類
SuperClass.call(this,id);
}
//創建第一個子類的實例
var instance1=new SubClass(10);
//創建第二個子類的實例
var instance2=new SubClass(11);

instance1.books.push("設計模式");
console.log(instance1.books); //['JavaScript','html','css',‘設計模式’]
console.log(instance1.id); //10
console.log(instance2.books);//['JavaScript','html','css']
console.log(instance2.id);//11
instance1.showBooks(); //TypeError

由於call這個方法可以更改函數的作用環境,因此在子類中,對superClass調用這個方法就是將子類中的變量在父類中執行一遍,由於父類中是給this
綁定屬性的,因此子類自然也就繼承了父類的共有屬性。由於這種類型的繼承沒有涉及原型的prototype.所以父類的原型方法自然不會被子類繼承,
而如果要想被子類繼承就必須要放在構造函數中,這樣創建出來的每個實例都會單獨擁有一份而不能共用,這樣就違背了代碼復用的原則。為了綜合這兩
種模式的優點,就有了組合式繼承。
2.3 將優點為我所用--組合式繼承
//組合式繼承
//聲明父類
function SuperClass(name){
//值類型共有屬性
this.name=name;
//引用類型共有屬性
this.books=['html','css','javaScript'];
}
//父類原型共有方法
SuperClass.prototype.getName=function(){
console.log(this.name);
};
//聲明子類
function SubClass(name,time){
console.log(this.name);
};
//聲明子類
function SubClass(name,time){
//構造函數式繼承父類name屬性
SuperClass.call(this,name);
//子類中新增共有屬性
this.time=time;
}
//類式繼承 子類原型繼承父類
SubClass.prototype=new SuperClass();
//子類原型方法
SubClass.prototype.getTime=function(){
console.log(this.time);
}

在子類構造函數中執行父類構造函數,在子類原型上實例化父類就是組合模式這樣就融合了類式繼承和構造函數繼承的有點,並過濾掉其缺點。

三,多態
多態就是同一個方法多種調用方式。
//多態
function add(){
var arg=arguments,len=arg.length;
switch(len){
case 0:
return 10;
case 1:
return 10+arg[0];
case 2:
return arg[0]+arg[1];
}
}
對於多態就是根據傳參不同做相應運算。將不同運算方法封裝在類內,這樣代碼更容易懂。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com