博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript面向对象的常见写法与优缺点
阅读量:5937 次
发布时间:2019-06-19

本文共 8829 字,大约阅读时间需要 29 分钟。

我们通过表单验证的功能,来逐步演进面向对象的方式.   对于刚刚接触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 ); //true10 11         fn1.checkUserName(); //ghostwu12         fn2.checkUserName(); //ghostwu

如果我们使用上面这种方式扩展,从功能上来说,是没有问题的,但是确造成了全局污染:通俗点说,并不是说有的函数都需要checkUserName这个方法,而我们这样写,所有的函数在创建过程中都会从父类的原型链上继承checkUserName, 但是这个方法,我们根本不用, 所以浪费性能, 为了解决这个问题,我们应该要在需要使用这个方法的函数上添加,不是所有的都添加,另外关于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(); //ghostwu11         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();

 

转载地址:http://jvvtx.baihongyu.com/

你可能感兴趣的文章
java中string和int互相转化
查看>>
什么是序列化,为什么要序列化
查看>>
Java保留小数点后有效数字
查看>>
CommonHelper
查看>>
excel操作for(lutai)
查看>>
Codeforces Round #162 (Div. 2) C. Escape from Stones
查看>>
2017 Multi-University Training Contest - Team 4 phone call(树+lca+并查集)
查看>>
Struts2文件下载
查看>>
error LNK2019: 无法解析的外部符号 _PhInitializePhLib,该符号在函数 _EnumHandle 中被引用...
查看>>
新学期的合作
查看>>
使用JavaScript获取CSS伪元素属性
查看>>
正则化
查看>>
javascript弹窗
查看>>
结对编程项目作业2-结对编项目设计文档
查看>>
百度地图实现思路--------未实践------未验证
查看>>
final域的内存语义
查看>>
C++链接两个cpp 文件
查看>>
Commons DbUtils: JDBC Utility Component
查看>>
设计一个学生类&班级类
查看>>
响应式网页设计:互联网web产品RWD概念
查看>>