javascript面向物件的常見寫法與優缺點
我們通過表單驗證的功能,來逐步演進面向物件的方式. 對於剛剛接觸javascript的朋友來說,如果要寫一個驗證使用者名稱,密碼,郵箱的功能, 一般可能會這麼寫:
1 //表單驗證 2 var checkUserName = function(){ 3 console.log( '全域性checkUserName' ); 4 }; 5 var checkUserEmail = function(){ 6 console.log( '全域性checkUserEmail' );7 }; 8 var checkUserPwd = function(){ 9 console.log( '全域性checkUserPwd' ); 10 };
這種寫法,從功能上來說 沒有什麼問題, 但是在團隊協作的時候, 會造成覆蓋全域性變數的問題, 那要大大降低覆蓋的可能性, 一般會在外面套一個物件
1 var Utils = { 2 checkUserName : function(){ 3 console.log( 'Utils->checkUserName' );4 }, 5 checkUserEmail : function(){ 6 console.log( 'Utils->checkUserEmail' ); 7 }, 8 checkUserPwd : function(){ 9 console.log( 'Utils->checkUserPwd' ); 10 } 11 } 12 13 checkUserEmail();14 Utils.checkUserEmail();
上面這種方式,是字面量方式新增,在設計模式裡面,也稱為單例(單體)模式, 與之類似的可以通過在函式本身新增屬性和方法,變成靜態屬性和方法,達到類似的效果:
1 var Utils = function(){ 2 3 } 4 Utils.checkUserName = function(){ 5 console.log( 'Utils.checkUserName' ); 6 } 7 Utils.checkUserPwd = function(){ 8 console.log( 'Utils.checkUserPwd' ); 9 } 10 Utils.checkUserEmail = function(){ 11 console.log( 'Utils.checkUserEmail' ); 12 } 13 14 Utils.checkUserEmail(); 15 16 for( var key in Utils ){ 17 ( Utils.hasOwnProperty( key ) ) ? console.log( key ) : ''; 18 } 19 20 //加在函式上面的屬性和方法,無法通過物件使用 21 var oUtil = new Utils(); 22 oUtil.checkUserEmail();//錯誤
還可以通過函式呼叫方式,返回一個物件,把方法和屬性寫在物件中, 這種方式 跟面向物件沒有什麼關係,只是從函式的返回值角度來改造
1 //使用函式的方式 返回一個物件 2 var Util = function(){ 3 return { 4 checkUserName : function(){ 5 console.log( 'userName...' ); 6 }, 7 checkUserPwd : function(){ 8 console.log( 'userPwd...' ); 9 }, 10 checkUserEmail : function(){ 11 console.log( 'userEmail...' ); 12 } 13 } 14 } 15 Util().checkUserEmail();
還可以通過類似傳統面嚮物件語言,使用建構函式方式 為每個例項新增方法和屬性, 這種方式,存在一個問題, 不能達到函式共用,每個例項都會複製到方法.
1 var Util = function(){ 2 this.checkUserName = function(){ 3 console.log('userName'); 4 }; 5 this.checkUserEmail = function(){ 6 console.log('userEmail'); 7 }; 8 this.checkUserPwd = function(){ 9 console.log('userPwd'); 10 }; 11 } 12 13 var oUtil1 = new Util(); 14 var oUtil2 = new Util(); 15 console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//false
一般,我們可以通過原型屬性(prototype)改造這種方式,達到不同例項共用同一個方法
1 var Util = function(){ 2 3 }; 4 Util.prototype.checkUserName = function(){ 5 console.log('userName'); 6 }; 7 Util.prototype.checkUserPwd = function(){ 8 console.log('userPwd'); 9 }; 10 Util.prototype.checkUserEmail = function(){ 11 console.log('userEmail'); 12 }; 13 var oUtil1 = new Util(); 14 var oUtil2 = new Util(); 15 console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//true
也可以把原型物件上的所有方法,使用字面量方式簡寫
1 var Util = function(){ 2 3 }; 4 Util.prototype = { 5 checkUserEmail : function(){ 6 console.log( 'userEmail' ); 7 }, 8 checkUserName : function(){ 9 console.log( 'userName' ); 10 }, 11 checkUserPwd : function(){ 12 console.log( 'userPwd' ); 13 } 14 }; 15 var oUtil1 = new Util(); 16 var oUtil2 = new Util(); 17 console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//true
注意: 字面量方式和原型物件一個個新增 這兩種不要混用, 否則會產生覆蓋
如果我們想把面向物件的使用方式更加的優雅,比如鏈式呼叫, 我們應該在每個方法中返回物件本身,才能繼續呼叫方法, 即返回this
1 var Util = function(){ 2 return { 3 checkUserName : function(){ 4 console.log( 'userName...' ); 5 return this; 6 }, 7 checkUserPwd : function(){ 8 console.log( 'userPwd...' ); 9 return this; 10 }, 11 checkUserEmail : function(){ 12 console.log( 'userEmail...' ); 13 return this; 14 } 15 } 16 } 17 // 方法中如果沒有返回this,下面這種呼叫方式是錯誤的 18 Util().checkUserEmail().checkUserName(); 19 20 // 方法中返回物件本身,可以鏈式呼叫 21 Util().checkUserEmail().checkUserName().checkUserPwd();
1 var Util = function(){ 2 this.checkUserName = function(){ 3 console.log('userName'); 4 return this; 5 }; 6 this.checkUserEmail = function(){ 7 console.log('userEmail'); 8 return this; 9 }; 10 this.checkUserPwd = function(){ 11 console.log('userPwd'); 12 return this; 13 }; 14 } 15 16 new Util().checkUserEmail().checkUserName().checkUserPwd();
var Util = function(){ }; Util.prototype = { checkUserEmail : function(){ console.log( 'userEmail' ); return this; }, checkUserName : function(){ console.log( 'userName' ); return this; }, checkUserPwd : function(){ console.log( 'userPwd' ); return this; } }; new Util().checkUserEmail().checkUserName().checkUserPwd();
1 var Util = function(){ 2 3 }; 4 Util.prototype.checkUserName = function(){ 5 console.log('userName'); 6 return this; 7 }; 8 Util.prototype.checkUserPwd = function(){ 9 console.log('userPwd'); 10 return this; 11 }; 12 Util.prototype.checkUserEmail = function(){ 13 console.log('userEmail'); 14 return this; 15 }; 16 17 new Util().checkUserEmail().checkUserName().checkUserPwd();
在實際開發中,我們經常需要擴充套件一些功能和模組。擴充套件可以在本物件或者父類物件或者原型上
1 Function.prototype.checkUserName = function(){ 2 console.log('ghostwu'); 3 }; 4 5 var fn1 = function(){}; 6 var fn2 = function(){}; 7 8 console.log( 'checkUserName' in fn1 ); //true 9 console.log( 'checkUserName' in fn2 ); //true 10 11 fn1.checkUserName(); //ghostwu 12 fn2.checkUserName(); //ghostwu
如果我們使用上面這種方式擴充套件,從功能上來說,是沒有問題的,但是確造成了全域性汙染:通俗點說,並不是說有的函式都需要checkUserName這個方法,而我們這樣寫,所有的函式在建立過程中都會從父類的原型鏈上繼承checkUserName, 但是這個方法,我們根本不用, 所以浪費效能, 為了解決這個問題,我們應該要在需要使用這個方法的函式上新增,不是所有的都新增,另外關於in的用法,如果不熟悉,可以看下我的這篇文章:立即表示式的多種寫法與注意點以及in操作符的作用
1 Function.prototype.addMethod = function( name, fn ){ 2 this[name] = fn; 3 } 4 5 var fn1 = function(){}; 6 var fn2 = function(){}; 7 8 fn1.addMethod( 'checkUserName', function(){console.log('ghostwu');}); 9 10 fn1.checkUserName(); //ghostwu 11 fn2.checkUserName(); //報錯
通過上述的改造,成功解決了全域性汙染, fn2這個函式上面沒有新增checkUserName這個方法,只在fn1上面新增
我們繼續把上面的方式,改成鏈式呼叫: 這裡需要改兩個地方, 一種是新增方法addMethod可以鏈式新增, 一種是新增完了之後,可以鏈式呼叫
1 Function.prototype.addMethod = function( name, fn ){ 2 this[name] = fn; 3 return this; 4 }; 5 6 var fn1 = function(){}; 7 8 fn1.addMethod( 'checkUserName', function(){ 9 console.log( 'userName:ghostwu' ); 10 return this; 11 } ).addMethod( 'checkUserEmail', function(){ 12 console.log( 'userEmail' ); 13 return this; 14 } ).addMethod( 'checkUserPwd', function(){ 15 console.log( 'userUserPwd' ); 16 return this; 17 } ); 18 fn1.checkUserName().checkUserEmail().checkUserPwd();
上面是屬於函式式 鏈式 呼叫, 我們可以改造addMethod方法, 在原型上新增函式,而不是例項上, 這樣我們就可以達到類式的鏈式呼叫
1 Function.prototype.addMethod = function( name, fn ){ 2 this.prototype[name] = fn; 3 return this; 4 }; 5 6 var fn1 = function(){}; 7 8 fn1.addMethod( 'checkUserName', function(){ 9 console.log( 'userName:ghostwu' ); 10 return this; 11 } ).addMethod( 'checkUserEmail', function(){ 12 console.log( 'userEmail' ); 13 return this; 14 } ).addMethod( 'checkUserPwd', function(){ 15 console.log( 'userUserPwd' ); 16 return this; 17 } ); 18 new fn1().checkUserName().checkUserEmail().checkUserPwd();
相關推薦
javascript面向物件的常見寫法與優缺點
我們通過表單驗證的功能,來逐步演進面向物件的方式. 對於剛剛接觸javascript的朋友來說,如果要寫一個驗證使用者名稱,密碼,郵箱的功能, 一般可能會這麼寫: 1 //表單驗證 2 var checkUserName = function(){ 3
面向對象的常見寫法與優缺點
his 性能 不同 ons www property .html ... html 我們通過表單驗證的功能,來逐步演進面向對象的方式. 對於剛剛接觸javascript的朋友來說,如果要寫一個驗證用戶名,密碼,郵箱的功能, 一般可能會這麽寫: 1 /
JavaScript面向物件(三)——繼承與閉包、JS實現繼承的三種方式
前 言 JRedu 在之前的兩篇部落格中,我們詳細探討了JavaScript OOP中的各種知識點(JS OOP基礎與JS 中This指向詳解 、 成員屬性、靜態屬性、原型屬性與JS原型鏈)。今天我們來繼續探討剩餘的內容吧。 我們都知道,面向物件的三大特徵——封裝、繼承、多型。 封裝無非就是屬性和
javascript 面向物件的幾種常見寫法(轉)
//定義Circle類,擁有成員變數r,常量PI和計算面積的成員函式area() 文章轉自:http://www.iteye.com/topic/434462 1.工廠方式 var Circle = function() { var obj = new Object
JavaScript 面向物件概念與寫法比對
面向物件的概念1.面向物件就是使用物件,面向物件開發就是使用隊形開發2.面向過程就是使用過程的方式開發,面向物件是對面向過程進行封裝面向物件的特性1.抽象性2.封裝性3.繼承性## 抽象性所謂抽象性就是:如果對一個物件描述一個數據,需要抽取這個物件的核心資料1.提出需要的核心
JavaScript 面向物件之一 —— 物件(物件與JSON的區別)
本系列文章根據《愛前端邵山歡老師深入淺出的js面向物件》視訊整理歸納 物件與JSON的區別 JSON 就是 JavaScript object notation ,JavaScript 物件表示法。是 JavaScript 物件的嚴格子集。 JSON 要求所有
javascript面向物件系列第四篇——OOP中的常見概念
前面的話 面向物件描述了一種程式碼的組織結構形式——一種在軟體中對真實世界中問題領域的建模方法。本文將從理論層面,介紹javascript面向物件程式程式(OOP)中一些常見的概念 物件 所謂物件,本質上就是指事物(包括人和物)在程式設計語言中的表現形式。這裡的事物可以是任何東西(如某個客觀
javascript面向物件——幾種常見的設計模式
工廠模式: 這種模式比較簡單,其實就是在函式中建立一個物件,給物件新增屬性及其屬性值或屬性方法然後在講這個物件用return返回出來。 如下面的例項: function myfile(name,work){ var myself = new Object();
JavaScript 面向物件程式設計實現
JavaScript 面向物件程式設計實現 本文主要講述js面向物件的實現方式(繼承) 面向物件本來就是把某些問題(邏輯),用物件的方式描述,使得業務邏輯能更加清晰,提高維護性,降低實現複雜度。 面向物件的三大特徵:封裝,多型,繼承。(JavaScript 是沒有多型的特性的
javascript面向物件程式設計--惰性載入函式(瀏覽器相容性處理)
因為各大瀏覽器所使用的JS引擎不同,所以在實現某一個功能時都或多或少的存在差異,導致在寫程式碼時要針對每一個功能給出相容瀏覽器的不同實現方式,這樣在執行程式碼時就會造成效能的損耗。所以就出現了惰性載入函式的概念。原理就是:當前瀏覽器第一次支援以該方法實現某功能,那麼在這個頁面執行期間會一直都支援該方
javascript面向物件程式設計--繼承--多重繼承+摻元類(多親繼承)
繼承一般包括 單向繼承 和 多重繼承 多重繼承:一個子類繼承多個超類 function A(x){this.x=x;} A.prototype.getx=function(){return this.x;} function B(y){this.y=y;}
javascript面向物件程式設計--設計超類和子類,設計元類
在javascript中,Object物件是通用類,其他所有內建物件和自定義構造物件都是專用類,即Object物件是超類,其他內建物件和自定義物件都是Object的子類,所有在javascript語言中,所有的物件都繼承Object定義的屬性和方法 Object.prototype.name='
javascript面向物件程式設計--安全構造物件
建構函式 其實就是一種 使用new運算子的函式 function Person(name,age,job){ this.name=name; this.age=age; this.job=
javascript面向物件程式設計--惰性例項化(實現按需例項化)
javascript是以物件為基礎,以函式為模型,以原型為繼承機制的開發模式 惰性例項化:避免在頁面中使用javascript初始化執行時就例項化類,而是將一些類的例項化推遲到需要時候才去例項化,避免資源過早的消耗 var myNamespace=function(){ &
javascript面向物件程式設計--建構函式 實現動態構造
在面向物件過程中,構造和析構是類的兩個重要特性,建構函式在物件建立時候呼叫,解構函式在物件銷燬時被呼叫 建構函式: function F(x,y){ this.x=x;this.y=y} var f=new F(1,2); alert(f.co
javascript面向物件程式設計--多型
方法過載和覆蓋(重寫) 過載:同名方法可以有多個實現,根據引數的型別,引數值,引數個數決定執行行為 var map=function(arr,callback,pThis){ var len=arr.length; var rlt=new Ar
javascript面向物件程式設計--靜態方法
在面向物件程式設計中,類是不能夠直接訪問的,必須例項化後才可以訪問,大多數方法和屬性與類的例項產生聯絡。但是靜態屬性和方法與類本身直接聯絡,可以從類訪問,如javascript的核心物件中的Math和Global都是靜態物件,不需例項化,可以直接訪問 類的靜態成員(屬性和方法)包括私有和共有兩種
javascript面向物件程式設計--繼承--複製繼承+克隆繼承 混合繼承(常用)
複製繼承:利用for/in語句遍歷物件成員,逐一複製給另一個物件 funciton F(x,y){ this.x=x; this.y=y; this.add=function(){ return this.x+th
javascript面向物件程式設計--繼承--例項繼承
類繼承和原型繼承的弊端: 它們在客戶端是無法繼承DOM物件的,同時他們也不支援繼承系統物件和方法 類繼承: function D(){ Date.apply(this.arguments);} var d=new D
面向物件構建方法以及優缺點
面向物件 // 1.物件字面量的方式建立物件 var obj = {}; // 使用場景:作為函式的引數,臨時使用一次, obj.name = 'lisi'; obj.say = function()