分享几个Javascript 封装方法
基本封装方法
请看下面的例子:
var Person = function(name,age){
this.name = name;
this.age = age || "未填写";
this.hobbys = [];
}
Person.prototype = {
sayName:function(){
console.log(this.name);
},
sayAge:function(){
console.log(this.age);
},
addHobby:function(hobbys){
this.hobbys = this.hobbys.concat(hobbys);
}
}
var person1 = new Person("Jane","20");
var person2 = new Person("TabWeng","21");
person1.addHobby(['sing','drawing']);
person2.addHobby(['football','study','running']);
person1.sayName();
console.log(person1.hobbys.toString());
person2.sayName();
console.log(person2.hobbys.toString());
运行结果:
Jane
sing,drawing
TabWeng
football,study,running
这在JavaScript创建对象中讲过,把可以共用的属性和方法写在原型上,需要每个实例各自都有的副本的属性和方法放在构造函数中。
现在有个问题,名称的输入不能有数字,要怎么解决呢?解决的方法可以写一个检查名称的函数,这个函数写在原型上。
var Person = function(name,age){
//校验名称
if(this.checkName(name)){
throw new Error("名字 "+name+" 不能存在数字");
}
this.name = name;
this.age = age || "未填写";
this.hobbys = [];
}
Person.prototype = {
//校验函数
checkName:function(name){
re = /\d/;
return re.test(name);
},
sayName:function(){
console.log(this.name);
},
sayAge:function(){
console.log(this.age);
},
addHobby:function(hobbys){
this.hobbys = this.hobbys.concat(hobbys);
}
}
var person1 = new Person("Helen666","20");
var person2 = new Person("TabWeng","21");
person1.addHobby(['sing','drawing']);
person2.addHobby(['football','study','running']);
person1.sayName();
console.log(person1.hobbys.toString());
person2.sayName();
console.log(person2.hobbys.toString());
这段代码中,我们写了一个checkName()
函数,来校验名称,暂且只是校验不能有数字吧,然后再构造函数里的第一行代码中进行校验,若校验不通过,则抛出异常。 这里我传入一个名称Helen666,结果抛出如下异常:
Error: 名字 Helen666 不能存在数字
这样就做到了一个基本的封装,实现内部校验。
但是又有个问题,我们还可以这样来定义名称:
var person1 = new Person("Helen","20");
person1.name = "Helen666";
person1.sayName(); //Helen666
这样名称还是可以修改为不合法的名称,于是我们想到用get方法 和set方法来做控制,只能通过set方法来赋值,同时通过set方法进行校验,而通过get方法来获得值。现在的代码修改如下:
// Interface
var People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);
var Person = function(name,age){ //implement People
this.setName(name);
this.setAge(age);
this._hobbys = [];
}
Person.prototype = {
//校验函数
checkName:function(name){
re = /\d/;
return re.test(name);
},
sayName:function(){
console.log(this._name);
},
sayAge:function(){
console.log(this._age);
},
addHobby:function(hobbys){
this._hobbys = this._hobbys.concat(hobbys);
},
getHobby:function(){
return this._hobbys;
},
setName:function(name){
if(this.checkName(name)){
throw new Error("名字 "+name+" 不能含有数字");
}
this._name = name;
},
getName:function(){
return this._name;
},
setAge:function(age){
this._age = age || "未设置";
},
getAge:function(){
return this._age;
}
}
var person1 = new Person("Helen","20");
person1.addHobby(['sing','drawing']);
function record(person){
Interface.ensureImplements(person,People);
person.sayName();
console.log(person.getHobby().toString());
}
record(person1);
运行结果:
Helen
sing,drawing
首先,这段代码我们使用了接口,定义了People接口,而person来实现这个接口,注意注释的内容。(关于接口,请看这篇 JavaScript使用接口) 其次,我们使用了get方法 和 set方法来取值和赋值,我们可以约定程序员只能通过set来赋值,而在set方法里面我们对所赋予的值进行了校验,以确保准确。但是这仅仅是一种约定,程序员依然可以通过 person1.name = "123"
来赋值,修改内部属性。 为了规范和起到提醒作用,我们把内部属性的命名进行规范,在这些属性前面加上“_”,比如 **_name** 、**_age** ,这样如果程序员要直接修改属性,那么他就必须这样写person1._name = "123"
,这明显是一种故意的做法,一般程序员不会这么做,起到规范和提醒的作用。
尽管如此,这种仅仅是用规定进行约束,还是无法阻止通过person1._name
进行修改,下面的方法可以做到把内部属性真正做到私有化。
通过闭包进行封装
如果对闭包不太理解,请阅读JavaScript函数表达式以及JavaScript变量和作用域,我们来看一下如何实现:
// Interface
var People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);
var Person = function(name,age){ //implement People
// 私有变量
var _name,_age,_hobbys = [];
this.addHobby = function(hobbys){
_hobbys = _hobbys.concat(hobbys);
},
this.getHobby = function(){
return _hobbys;
},
this.setName = function(name){
if(this.checkName(name)){
throw new Error("名字 "+name+" 不能含有数字");
}
_name = name;
},
this.getName = function(){
return _name;
},
this.setAge = function(age){
_age = age || "未设置";
},
this.getAge = function(){
return _age;
}
this.setName(name);
this.setAge(age);
}
Person.prototype = {
checkName:function(name){
re = /\d/;
return re.test(name);
},
sayName:function(){
console.log(this.getName());
},
sayAge:function(){
console.log(this.getAge());
}
}
var person1 = new Person("Helen","20");
person1.addHobby(['sing','drawing']);
function record(person){
Interface.ensureImplements(person,People);
person.sayName();
console.log(person.getHobby().toString());
}
record(person1);
在构造函数中,属性不使用this
,外部也就无法访问到这个属性,而闭包通过作用域链可以访问到这个属性,那么我们就通过闭包设置了为属性赋值的唯一入口,从而起到了严格校验这些属性的作用。
尽管如此,在构造函数中定义方法很多时候是没必要的,因为这样每创建一个实例,就会产生一个方法的副本,这是需要内存支持的,所以在使用的过程中,如果能用上面的基本封装方法,尽量用,除非对于私有属性有非常严格的校验要求才用闭包这种方法。
此文转载;
分享几个Javascript 封装方法的更多相关文章
- Javascript 封装方法
基本封装方法 请看下面的例子: var Person = function(name,age){ this.name = name; this.age = age || "未填写" ...
- JavaScript封装方法,兼容参数类型为Number和String
/** * 依据Kind确定跳转到目标列表页面. * @param kind */ function gobackByKind(kind) { var kindStr = String(kind); ...
- JavaScript封装
js封装就是把使用方式简单化,内部逻辑和使用解耦.使用人员知道参数和返回值就可以了,其他不用使用人员设置. 封装就是将属性,方法,字段等封装成类. JavaScript封装方法 1,函数方式 func ...
- 一些好用的javascript/typescript方法封装分享
1.数字格式化 JS版-直接写到原型链上 /** * @author: silencetea * @name: * @description: 数字格式化,默认每三位用英文逗号分隔 * @param ...
- JavaScript封装一个函数效果类似内置方法concat()
JavaScript封装一个函数效果类似内置方法concat() 首先回忆concat()的作用: concat() 方法用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个 ...
- 在Swift中使用JavaScript的方法和技巧
本文作者Nate Cook是一位独立的Web及移动应用开发者,是继Mattt大神之后NSHipster的主要维护者,也是非常知名活跃的Swift博主,并且还是支持自动生成Swift在线文档的Swift ...
- javaScript封装的各种写法
在javascript的世界里,写法是个神奇的现象,真是百家齐开放啊!每次看到老外写的js组件,思想和写法都怪异,就没看到一个js结构基本相同的代码出来.今天,我就来谈谈js写法,我在开发过程中,也写 ...
- Javascript 封装问题
Javascript 封装问题 为什么会用这样一个题目呢,这是要说封装的什么问题,本文并不讲高深的封装理论,只是解决一个小问题. 问题来源 今天在百度知道上闲逛,遇到一个网友的问题,问题如下,问题的地 ...
- httpclient获取响应实体和信息的封装方法(解耦更新)
转自:https://blog.csdn.net/fhaohaizi/article/details/77850302 2018年07月19日更新,主要是解耦之后方法很多地方发生了变化,httpcli ...
随机推荐
- 在chrome浏览器和在IE浏览器中显示的页面样式不一样的解决办法
在IE浏览器中添加 一行代码即可:<meta http-equiv="X-UA-Compatible" content="IE=edge" /> 位 ...
- Prince2七大原则(3)
Prince2七大原则(3) 我们先来回顾一下,PRINCE2七大原则分别是持续的业务验证,经验学习,角色与责任,按阶段管理,例外管理,关注产品,剪裁. 第三个原则:明确定义的角色和职责. 项目离不开 ...
- 20150625_Andriod_01_ListView1_条目选中
android listview 参考地址: http://www.cnblogs.com/zhengbeibei/archive/2013/05/14/3078805.html http://xy ...
- Linux vim的安装和配置:
1:首先就碰到一个问题 程序 'vim' 已包含在下列软件包中: * vim * vim-gnome * vim-tiny * vim-athena * vim-gtk * vim-nox 请尝试:s ...
- Unity-Animator深入系列---目标匹配Target Matching
回到 Animator深入系列总目录 一开始会理所当然的觉得,匹配是这样的: 但结果却是这样的(右边的Cube是匹配目标): 感觉这个接口应该是专门为攀爬之类的动画准备的,属于被动匹配位置,移动整个对 ...
- 提高 Linux 上 socket 性能
http://www.cnblogs.com/luxf/archive/2010/06/13/1757662.html 基于Linux的Socket网络编程的性能优化 1 引言 随着In ...
- wamp安装完更改关联浏览器
"wampmanager.conf"文件修改的是关于中到官网的链接打开方式. "wampmanager.ini"修改的是左键菜单的打开方式. 修改完无效的话重启 ...
- Robotium中定位Android客户端疑难元素
对于没有id,没有text,只有一个图标的疑难元素(ImageView),应该如何定位呢?拿人人网个人主页的设置按钮举例: 我最终是通过定位页面上可以定位到的其他元素,然后通过其他元素与疑难元素相对坐 ...
- UML中的用例(Use Case)概念分析及StarUML实例
在UML中use case似 乎最簡單的,用例建模的最主要功能就是用来表达系统的功能性需求或行为,依我的理解用例建模可分为用例图和用例描述.用例图由参与者(Actor).用例 (Use Case).系 ...
- Python安装指南
说明:我的安装环境是centos6.4 ,32位系统:(#号之后内容为注释说明内容) 1.准备 centos是自带python的,所以可以在shell下直接执行:python 可以看到相应的打印信息, ...