[目錄]
- 面向過程寫函數(shù)
- 什么是面向過程顺少?什么是面向對象?
- 【面向過程】和【面向對象】寫函數(shù)的不同
- 【面向過程】寫函數(shù)的優(yōu)缺點
- 面向對象寫函數(shù)
- 單個對象寫函數(shù)
- 構造函數(shù)寫函數(shù)(類)
- 給構造函數(shù)的原型對象寫函數(shù)
面向過程寫函數(shù)
什么是面向過程?什么是面向對象嗦玖?
面向過程和面向對象都是一種編程的思想澜掩,也可以理解為一種代碼的組織形式贯涎。面向過程主要關注于解決問題需要一步一步實現(xiàn)的過程谴麦,而面向對象主要關注于把解決的不同問題分給不同的對象管理蠢沿,面向對象不關注于解決問題的步驟,只關注于解決問題的對象匾效。
面向過程和面向對象寫函數(shù)的不同
- 面向對象是相對于面向過程發(fā)展來的舷蟀;
- 面向過程是在代碼量比較少、功能簡單的場景中適用面哼;面向過程一般適用于項目規(guī)則較大野宜,代碼量較多;
- 面向過程所有的事情都是需要我們自己來完成的魔策,親歷親為匈子;面向對象是完成一件事情,只需要找到某個對象闯袒,讓它幫我們完成即可旬牲;
- 面向過程中我們處于執(zhí)行者的角色;面向對象中我們處于一個調度者的角色搁吓;
- 面向過程的方式要比面向對象的方式代碼執(zhí)行效率高原茅;但是面向對象對于大型項目來說,有利于多人合作開發(fā)堕仔、項目代碼的維護和更新迭代
以js和jq為例進行以下簡單分析:
//js面向過程實現(xiàn)一個將一個標簽添加到頁面中的一個功能
//第一步:創(chuàng)建一個p標簽
var p = document.createElement('p');
//第二步: 用最原始的方式創(chuàng)建一個文本節(jié)點
var txt = document.createTextNode('creat TEXT');
//第三步:將文本節(jié)點添加到p標簽中
p.appendChild(txt);
//ps:這個方法我們平時不常用擂橘,因為我們經(jīng)常使用innerText方法,可以看作innerText中封裝了createTextNode方法
//第四步:將p標簽添加到頁面中去
document.body.appendChild(p);
//jq是面向對象編程的
//找到jq對象摩骨,使用jq對象的append方法
$('body').append('<p>create TEXT</p>');
【面向過程】寫函數(shù)的優(yōu)缺點
- 優(yōu)點:面向過程的方式要比面向對象的方式代碼執(zhí)行效率高通贞,簡單易懂,沒有復雜的邏輯結構恼五。
- 缺點:不利于合作開發(fā)昌罩,不利于代碼的維護和擴展。最重要的是會造成嚴重的全局污染灾馒。
寫方法我們一般會經(jīng)歷下面的幾個步驟:
//一開始我們寫函數(shù)都是這樣聲明的
function checkName(){
console.log("name");
}
function checkEmail(){
console.log("email");
}
function checkPassword(){
console.log("key");
}
//同理茎用,也可以使用變量聲明
var checkName = function(){
console.log("name");
}
var checkEmail = function(){
console.log("email");
}
var checkPassword = function(){
console.log("key");
}
//調用方式
checkName();//name
這兩種方式效果都是一樣的,但是這樣聲明了3個全局變量睬罗。全局污染很容易造成命名沖突的問題轨功,聲明全局變量就會有定義了相同的方法,后面的就把原來的進行覆蓋了容达。
比如:
function happy(){
console.log("hello!");
}
function happy(){
console.log("world!");
}
happy();
//輸出結果為 world古涧! 后面的方法將前面的覆蓋了,導致前面的不能使用
不僅如此花盐,全局污染 的問題是開發(fā)中值得關注的問題羡滑。
所以我們使用一個對象菇爪,對象有自己的屬性和方法,如果我們要訪問它的屬性和方法柒昏,訪問這個對象點出來屬性和方法就可以了凳宙,所以我們可以創(chuàng)建一個對象,然后把方法放在里面:
var CheckObj = {
checkName:function(){
console.log("name");
},
checkEmail:function(){
console.log("email");
},
checkPassword:function(){
console.log("key");
}
}
//這樣我們使用的時候就用對象點方法
CheckObj.checkName(); //name
當然還有另一種形式昙楚,因為在js中近速,函數(shù)也是對象
var CheckObj = function(){};
CheckObj.checkName = function(){
console.log("name");
}
CheckObj.checkEmail = function(){
console.log("email");
}
CheckObj.checkPassword = function(){
console.log("key");
}
//使用的方式還是和以前是一樣的
CheckObj.checkName(); //name
這樣雖然可以滿足我的需求诈嘿,但是當別人想用我寫的方法時就麻煩了堪旧。因為這個對象不能復制,或者說在new一個實例對象出來的時候奖亚,并不能去繼承這些方法淳梦。
所以要想使用這些方法,就要寫到一個函數(shù)對象(構造函數(shù))中:
var CheckObj = function(){
return {
checkName : function(){
console.log("name");
},
checkEmail : function(){
console.log("email");
},
checkPassword : function(){
console.log("key");
}
}
}
//這樣寫的原理是昔字,每次在調用這個函數(shù)的時候爆袍,都把對象返回出來,每次調用這個函數(shù)就返回一個新的對象作郭。
//這樣在執(zhí)行的是CheckObj,但實際上返回了一個新的對象陨囊。這樣使用的時候就互不影響了。
var user = CheckObj();
user.checkName(); //name
//new 也可以繼承了夹攒,但是一般不這么寫
var user1 = new CheckObj();
user1.checkEmail(); //name
雖然這個創(chuàng)建了新的對象完成了我們的需求蜘醋,但是他不是一個真正意義上類的創(chuàng)建方式,并且上面創(chuàng)建的user和CheckObj沒有任何的關系
所以需要進行改造:
var CheckObj = function(){
this.checkName = function(){
console.log("name");
}
this.checkEmail = function(){
console.log("email");
}
this.checkPassword = function(){
console.log("key");
}
}
//這樣就是一個類了咏尝,也是我們說的構造函數(shù),下面的user就是這個構造函數(shù)的實例對象压语,每一個new出來的實例對象都繼承了CheckObj的屬性和方法
var user = new CheckObj();
user.checkName(); //name
我們將所有的方法放到函數(shù)的內部,通過this定義编检,每一個實例對象創(chuàng)建的時候都會對類的this上的屬性進行復制(這種復制是一種深拷貝的復制)胎食。所以這些新創(chuàng)建的對象都有一套自己的方法,驗證如下:
var user = new CheckObj();
user.checkName(); //name
user.checkEmail = function(){
console.log("happy")
} //對user的checkEmail方法重新進行聲明
var user1 = new CheckObj();
user1.checkEmail(); //email
user.checkEmail(); //happy
//由此可以看出允懂,修改其中一個實例對象的方法的時候厕怜,并沒有影響原來的方法,復制是深拷貝的蕾总。
深拷貝的話酣倾,有時候會造成不必要的消耗,以為會復制很多的相同的對象
解決的辦法就是將這些方法都放到這個構造函數(shù)的原型對象上去:
var CheckObj = function(){};
CheckObj.prototype.checkName = function(){
console.log("name");
}
CheckObj.prototype.checkEmail = function(){
console.log("email");
}
CheckObj.prototype.checkPassword = function(){
console.log("key");
}
//簡潔一點也可以這么寫
CheckObj.prototype = {
checkName : function(){
console.log("name");
},
checkEmail : function(){
console.log("email");
},
checkPassword : function(){
console.log("key");
}
}
//這樣創(chuàng)建出來的對象所擁有的方法就是一個了谤专,因為它們都要到這個對象的原型鏈上去尋找其原型對象的方法躁锡。
寫個例子明白一下:
var Happy = function(){};
Happy.prototype = {
hello : function(){
console.log("hello");
},
world : function(){
console.log("world");
}
}
var happy = new Happy();
var unHappy = new Happy();
happy.hello(); // hello
unHappy.hello(); //hello
Happy.prototype.hello = function(){
console.log("heheda");
}
happy.hello(); //heheda 這說明剛才那個方法把前面的原型對象里面的方法覆蓋掉了,所以進行不要混用置侍。
unHappy.hello(); //heheda
//這樣也可以說明了映之,happy和unHappy用的是一個方法
上面的聲明拦焚,如果要進行函數(shù)的調用,會連續(xù)寫很多次杠输,可以進行修改赎败,鏈式調用
var CheckObj = function(){};
CheckObj.prototype = {
checkName : function(){
console.log("name");
return this;
},
checkEmail : function(){
console.log("email");
return this;
},
checkPassword : function(){
console.log("key");
return this;
}
}
//使用
var check = new CheckObj();
check.checkName().checkEmail().checkPassword(); //name email key
上面基本上就是面向對象的一種方式,下面是更高級的
prototype.js
是一款前端框架蠢甲,里面可以封裝很多方法僵刮,其最大的特點就是對源生對象的擴展,源生對象有什么鹦牛?Function,Array,Object
在原型鏈中搞糕,每一個function 都是由Function對象new出來的,所以如果把方法寫到Function的原型對象中曼追,那么只要是函數(shù)窍仰,就可以繼承這個方法。上個例子:
//在Function的原型對象上面聲明一個方法
Function.prototype.checkEmail = function(){
console.log("email");
}
//聲明一個函數(shù)礼殊,里面就可以繼承這個方法
var f = function(){};
f.checkEmail();
//或者
var ff = new Function();
ff.checkEmail();
But!!!!!!這種方式是不允許的驹吮,因為這樣會污染原生對象!!!!!
所以要抽象出一個統(tǒng)一添加方法的功能方法:
Function.prototype.addMethod = function(name,fn){
this[name] = fn;
return this; //返回的是Function所創(chuàng)建出來的實例對象
}
//添加方法(函數(shù)式的調用方式)
var method = function(){}; //或者 var method = new Function();
var m = method.addMethod('checkName',function(){
console.log("name");
})
console.log(m); // m接收的是method對象
//所以可以進行鏈式編程
method.addMethod('checkName',function(){
console.log("name");
return this; //this返回的是method函數(shù)對象
}).addMethod('checkEmail',function(){
console.log("email");
return this;
}).addMethod('checkPassword',function(){
console.log("key");
return this;
})
//調用
methods.checkEmail().checkName();// email name 之所以可以鏈式編程是因為返回的還是
//-------------------------------------------------------------------
//!!!!!類的調用方式!!!!!
Function.prototype.addMethod = function(name,fn){
this.prototype[name] = fn;//給Methods的原型對象上面添加方法
return this; //返回的是Method,Function創(chuàng)建出來的實例對象
}
var Methods = function(){}; //Function創(chuàng)建出來構造函數(shù)Methods
Methods.addMethod('checkName',function(){//之所以可以鏈式編程是因為返回的還是Methods
console.log("name");
return this; //返回的是m,Methods創(chuàng)建出來的實例對象
}).addMethod('checkEmail',function(){
console.log("email");
return this;
});
var m = new Methods(); //Methods構造函數(shù)創(chuàng)建出來實例對象m,m繼承了所有Methods的原型對象的所有方法
m.checkEmail().checkName();// email name 之所以可以鏈式編程是因為返回的還是m
下面完成作業(yè)
1.鏈式編程的話在函數(shù)體里面記得寫return this
2.給函數(shù)添加多個方法的addMethod方法
Function.prototype.addMethod = function(name,fn){
this[name] = fn;
return this;
}
var me = function(){};
me.addMethod("happy",function(a){
console.log("happy"+a);
return this;
}).addMethod("unHappy",function(){
console.log("rain");
return this;
})
me.happy(" time").unHappy(); //happy time , rain
3.既可以為函數(shù)原型添加方法又可以為其自身添加方法的addMethod的方法
Function.prototype.addMethod = function(name,fn){
this[name] = fn;
this.prototype[name] = fn;
return this;
}
var Me = function(){};
Me.addMethod("happy",function(a){
console.log("hello" + a);
return this;
}).addMethod("unHappy",function(){
console.log("no");
return this;
})
Me.happy("Me").unHappy(); //helloMe no
var m = new Me();
m.happy("m").unHappy(); //hellom no
但是上面那種方法晶伦,調用一次addMethod方法會在函數(shù)自身和原型對象上加兩個相同的方法碟狞,這樣是不科學的。我目前想到的方法是再傳一個參數(shù)婚陪,判斷是給原型對象加還是給自己加族沃,但是我覺得應該是addMethod里面有兩個不同的方法,然后調用的時候調用addMethod中的不同方法就可以了近忙。
下面你們有什么高見竭业,可以題出來探討 ^ ^