javascript面向对象的常见写法与优缺点
我们通过表单验证的功能,来逐步演进面向对象的方式. 对于刚刚接触javascript的朋友来说,如果要写一个验证用户名,密码,邮箱的功能, 一般可能会这么写:
//表单验证
var checkUserName = function(){
console.log( '全局checkUserName' );
};
var checkUserEmail = function(){
console.log( '全局checkUserEmail' );
};
var checkUserPwd = function(){
console.log( '全局checkUserPwd' );
};
这种写法,从功能上来说 没有什么问题, 但是在团队协作的时候, 会造成覆盖全局变量的问题, 那要大大降低覆盖的可能性, 一般会在外面套一个对象
var Utils = {
checkUserName : function(){
console.log( 'Utils->checkUserName' );
},
checkUserEmail : function(){
console.log( 'Utils->checkUserEmail' );
},
checkUserPwd : function(){
console.log( 'Utils->checkUserPwd' );
}
}
checkUserEmail();
Utils.checkUserEmail();
上面这种方式,是字面量方式添加,在设计模式里面,也称为单例(单体)模式, 与之类似的可以通过在函数本身添加属性和方法,变成静态属性和方法,达到类似的效果:
var Utils = function(){
}
Utils.checkUserName = function(){
console.log( 'Utils.checkUserName' );
}
Utils.checkUserPwd = function(){
console.log( 'Utils.checkUserPwd' );
}
Utils.checkUserEmail = function(){
console.log( 'Utils.checkUserEmail' );
}
Utils.checkUserEmail();
for( var key in Utils ){
( Utils.hasOwnProperty( key ) ) ? console.log( key ) : '';
}
//加在函数上面的属性和方法,无法通过对象使用
var oUtil = new Utils();
oUtil.checkUserEmail();//错误
还可以通过函数调用方式,返回一个对象,把方法和属性写在对象中, 这种方式 跟面向对象没有什么关系,只是从函数的返回值角度来改造
//使用函数的方式 返回一个对象
var Util = function(){
return {
checkUserName : function(){
console.log( 'userName...' );
},
checkUserPwd : function(){
console.log( 'userPwd...' );
},
checkUserEmail : function(){
console.log( 'userEmail...' );
}
}
}
Util().checkUserEmail();
还可以通过类似传统面向对象语言,使用构造函数方式 为每个实例添加方法和属性, 这种方式,存在一个问题, 不能达到函数共用,每个实例都会复制到方法.
var Util = function(){
this.checkUserName = function(){
console.log('userName');
};
this.checkUserEmail = function(){
console.log('userEmail');
};
this.checkUserPwd = function(){
console.log('userPwd');
};
}
var oUtil1 = new Util();
var oUtil2 = new Util();
console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//false
一般,我们可以通过原型属性(prototype)改造这种方式,达到不同实例共用同一个方法
var Util = function(){
};
Util.prototype.checkUserName = function(){
console.log('userName');
};
Util.prototype.checkUserPwd = function(){
console.log('userPwd');
};
Util.prototype.checkUserEmail = function(){
console.log('userEmail');
};
var oUtil1 = new Util();
var oUtil2 = new Util();
console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//true
也可以把原型对象上的所有方法,使用字面量方式简写
var Util = function(){
};
Util.prototype = {
checkUserEmail : function(){
console.log( 'userEmail' );
},
checkUserName : function(){
console.log( 'userName' );
},
checkUserPwd : function(){
console.log( 'userPwd' );
}
};
var oUtil1 = new Util();
var oUtil2 = new Util();
console.log( oUtil1.checkUserEmail === oUtil2.checkUserEmail );//true
注意: 字面量方式和原型对象一个个添加 这两种不要混用, 否则会产生覆盖
如果我们想把面向对象的使用方式更加的优雅,比如链式调用, 我们应该在每个方法中返回对象本身,才能继续调用方法, 即返回this
var Util = function(){
return {
checkUserName : function(){
console.log( 'userName...' );
return this;
},
checkUserPwd : function(){
console.log( 'userPwd...' );
return this;
},
checkUserEmail : function(){
console.log( 'userEmail...' );
return this;
}
}
}
// 方法中如果没有返回this,下面这种调用方式是错误的
Util().checkUserEmail().checkUserName();
// 方法中返回对象本身,可以链式调用
Util().checkUserEmail().checkUserName().checkUserPwd();
var Util = function(){
this.checkUserName = function(){
console.log('userName');
return this;
};
this.checkUserEmail = function(){
console.log('userEmail');
return this;
};
this.checkUserPwd = function(){
console.log('userPwd');
return this;
};
}
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();
var Util = function(){
};
Util.prototype.checkUserName = function(){
console.log('userName');
return this;
};
Util.prototype.checkUserPwd = function(){
console.log('userPwd');
return this;
};
Util.prototype.checkUserEmail = function(){
console.log('userEmail');
return this;
};
new Util().checkUserEmail().checkUserName().checkUserPwd();
在实际开发中,我们经常需要扩展一些功能和模块。扩展可以在本对象或者父类对象或者原型上
Function.prototype.checkUserName = function(){
console.log('ghostwu');
};
var fn1 = function(){};
var fn2 = function(){};
console.log( 'checkUserName' in fn1 ); //true
console.log( 'checkUserName' in fn2 ); //true
fn1.checkUserName(); //ghostwu
fn2.checkUserName(); //ghostwu
如果我们使用上面这种方式扩展,从功能上来说,是没有问题的,但是确造成了全局污染:通俗点说,并不是说有的函数都需要checkUserName这个方法,而我们这样写,所有的函数在创建过程中都会从父类的原型链上继承checkUserName, 但是这个方法,我们根本不用, 所以浪费性能, 为了解决这个问题,我们应该要在需要使用这个方法的函数上添加,不是所有的都添加,另外关于in的用法,如果不熟悉,可以看下我的这篇文章:立即表达式的多种写法与注意点以及in操作符的作用
Function.prototype.addMethod = function( name, fn ){
this[name] = fn;
}
var fn1 = function(){};
var fn2 = function(){};
fn1.addMethod( 'checkUserName', function(){console.log('ghostwu');});
fn1.checkUserName(); //ghostwu
fn2.checkUserName(); //报错
通过上述的改造,成功解决了全局污染, fn2这个函数上面没有添加checkUserName这个方法,只在fn1上面添加
我们继续把上面的方式,改成链式调用: 这里需要改两个地方, 一种是添加方法addMethod可以链式添加, 一种是添加完了之后,可以链式调用
Function.prototype.addMethod = function( name, fn ){
this[name] = fn;
return this;
};
var fn1 = function(){};
fn1.addMethod( 'checkUserName', function(){
console.log( 'userName:ghostwu' );
return this;
} ).addMethod( 'checkUserEmail', function(){
console.log( 'userEmail' );
return this;
} ).addMethod( 'checkUserPwd', function(){
console.log( 'userUserPwd' );
return this;
} );
fn1.checkUserName().checkUserEmail().checkUserPwd();
上面是属于函数式 链式 调用, 我们可以改造addMethod方法, 在原型上添加函数,而不是实例上, 这样我们就可以达到类式的链式调用
Function.prototype.addMethod = function( name, fn ){
this.prototype[name] = fn;
return this;
};
var fn1 = function(){};
fn1.addMethod( 'checkUserName', function(){
console.log( 'userName:ghostwu' );
return this;
} ).addMethod( 'checkUserEmail', function(){
console.log( 'userEmail' );
return this;
} ).addMethod( 'checkUserPwd', function(){
console.log( 'userUserPwd' );
return this;
} );
new fn1().checkUserName().checkUserEmail().checkUserPwd();
javascript面向对象的常见写法与优缺点的更多相关文章
- javascript:面向对象和常见内置对象及操作
本文内容: 面向对象 常见内置对象及操作 首发日期:2018-05-11 面向对象: JavaScript 是面向对象的编程语言 (OOP).OOP 语言使我们有能力定义自己的对象和变量类型. 对象是 ...
- javascript面向对象的一些写法
因为有闭包,能返回函数,所以针对于面向对象的封装,继承,多态三个特性实现,很舒服. 代码如下: <!DOCTYPE html> <html> <head> < ...
- javascript面向对象系列第四篇——OOP中的常见概念
前面的话 面向对象描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法.本文将从理论层面,介绍javascript面向对象程序程序(OOP)中一些常见的概念 对象 所谓对象,本质 ...
- javascript面向对象的写法03
javascript面向对象的写法03 js一些基础知识的说明 prototype 首先每个js函数(类)都有一个prototype的属性,函数是类.注意类有prototype,而普通对象没有. js ...
- JavaScript面向对象总结
对象(Object)应该算是js中最为重要的部分,也是js中非常难懂晦涩的一部分.更是面试以及框架设计中各出没.本文章,主要参考JavaScript红宝书(JavaScript高级程序设计 第六章)以 ...
- Javascript面向对象(封装、继承)
Javascript 面向对象编程(一):封装 作者:阮一峰 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程( ...
- JavaScript面向对象简介
JavaScript面向对象简介 @(编程) [TOC] 1. 命名空间 命名空间是一个容器,它允许开发人员在一个独特的,特定于应用程序的名称下捆绑所有的功能. 在JavaScript中,命名空间只是 ...
- 转:javascript面向对象编程
作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...
- JavaScript面向对象编程[转]
JavaScript面向对象编程 命名空间 命名空间是一个容器,它允许开发人员在一个独特的,特定于应用程序的名称下捆绑所有的功能. 在JavaScript中,命名空间只是另一个包含方法,属性,对象的对 ...
随机推荐
- C++实现-特征码遍历
#include <stdio.h> #include <stdlib.h> #include <windows.h> union Base { DWORD add ...
- tenda某路由器信息泄露查找
本文作者:i春秋作家——icqb32d3a26 1: 前期准备: (1) 路由器固件 一般获取固件的方法有以下几种 官方网站根据对应版本下载(√),点击下载 在点击更新固件时抓取对应的更新固件链接 拆 ...
- objc_msgSend 作用
C 的函数调用方式 C 语言使用静态绑定,即在编译器就可以决定运行时所应调用的函数. 编译器在编译代码的时候就已经知道程序中有相应的函数,并直接生成调用函数的指令.函数地址硬编码在指令之中. OC 中 ...
- SQL 高效的万能分页存储过程
代码如下: USE [Blog] IF OBJECT_ID('Proc_Paging', 'P') IS NOT NULL --删除同名存储过程 DROP PROC Proc_Paging GO CR ...
- iOS开发总结——协议代理的认识
1.前言 自今年5月底正式转iOS之后,天天get新技能,很多技能在脑子里回旋不吐不快,所以,写点东西整理一下.先从协议代理开始. 2.协议方法的声明 @protocol EventMenuBarDe ...
- Python小白学习之路(十一)—【局部变量和全局变量】【关键字global】【关键字nonlocal】
写在前面: 几乎有一周没有更新学习笔记了吧 上周一周身体都不怎么舒服 然后还得写开题报告 然后还得看文献 天天就是写写写写写写~~~~~~改改改改改改~~~~~~~~~ 今天又开始学习了 希望之前的没 ...
- 课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 1、经常提及的问题
Frequently Asked Questions Congratulations to be part of the first class of the Deep Learning Specia ...
- 【Java】认识 JDK,JRE,JVM
JDK,JRE,JVM 今天我们讨论下这三个Java工具 JDK 全称Java Development ToolKit(Java 开发工具包). JDK是整个JAVA的核心,其包括了Java运行环境( ...
- Vue中子组件调用父组件的方法
Vue中子组件调用父组件的方法 相关Html: <!DOCTYPE html> <html lang="en"> <head> <meta ...
- win7安装docker报错:error during connect: Get http ..... the system cannot find the file specified
因为是win7 所以使用了官方网站的dockertoolbox 安装一路顺利,结果启动就报上面的错误, 因为安装包附带安装了virtualbox 上面的错误后来排查出来是 virtualboox的问题 ...