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使用封装的更多相关文章
- 2016/11/17 周四 <javascript的封装简单示例>
这是一个简单的javascript代码封装的示例以及封装后的调用方法: var ticker={ n:0, add:function() { this.n++; }, show:function() ...
- 第一百三十五节,JavaScript,封装库--拖拽
JavaScript,封装库--拖拽 封装库新增1个拖拽方法 /** tuo_zhuai()方法,将一个弹窗元素实现拖拽功能 * 注意:一般需要在css文件将元素里的某一个区块光标设置成提示可以拖拽, ...
- 第一百三十四节,JavaScript,封装库--遮罩锁屏
JavaScript,封装库--遮罩锁屏 封装库新增1个方法 /** zhe_zhao_suo_ping()方法,将一个区块元素设置成遮罩锁屏区块 * 注意:一般需要在css文件将元素设置成隐藏 ** ...
- 第一百三十三节,JavaScript,封装库--弹出登录框
JavaScript,封装库--弹出登录框 封装库,增加了两个方法 yuan_su_ju_zhong()方法,将获取到的区块元素居中到页面,chuang_kou_shi_jian()方法,浏览器窗口事 ...
- 第一百三十二节,JavaScript,封装库--下拉菜单
JavaScript,封装库--下拉菜单 封装库,增加了3个方法 shu_biao_yi_ru_yi_chu()方法,给元素设置鼠标移入移出事件,接收两个参数,参数是移入和移出时的执行函数(包含代码) ...
- 第一百三十一节,JavaScript,封装库--CSS
JavaScript,封装库--CSS 将封装库里的方法,改成了原型添加方法 增加4个方法 tian_jia_class()方法,给获取到的元素添加class属性,参数是class属性值,可以连缀1 ...
- 第一百三十节,JavaScript,封装库--连缀
JavaScript,封装库--连缀 学习要点: 1.连缀介绍 2.改写库对象 本章我们重点来介绍,在调用库的时候,我们需要能够在前台调用的时候可以同时设置多个操作,比如设置CSS,设置innerHT ...
- Openlayer3之C++接口在javaScript的封装使用
0.写在前面: 1)涉及的关键词定义: 传入:JavaScript向CAPI传值 传出:CAPI向JavaScript传值 2)关于类和结构体的封装,需要严格执行内存对齐,以防止读取越界,但是避免不了 ...
- 第一百四十二节,JavaScript,封装库--运动动画和透明度动画
JavaScript,封装库--运动动画和透明度动画 /** yi_dong_tou_ming()方法,说明 * * yi_dong_tou_ming()方法,将一个元素,进行一下动画操作 * 1,x ...
- 第一百四十一节,JavaScript,封装库--DOM加载
JavaScript,封装库--DOM加载 DOM加载,跨浏览器封装DOM加载,当网页文档结构加载完毕后执行函数,不等待图片音频视频等文件加载完毕 /** dom_jia_zai()函数,DOM页面加 ...
随机推荐
- Spring4读书笔记(1)-模块
Srping主要模块 Core Container spring-core,spring-beans: 提供基础功能,包括IoC和DI等特性.对依赖起到解耦作用(BeanFactory). sprin ...
- ubuntu下C++连接mysql数据库
参考了该博客的做法:http://zhmy.michael.blog.163.com/blog/static/861578792012101244715692/ 1.安装mysql: sudo apt ...
- Json.net日期格式化
1. 全局设置,可以在App_Global中配置 JsonSerializerSettings setting = new JsonSerializerSettings(); JsonConvert. ...
- 项目vue2.0仿外卖APP(三)
项目的结构如下: 项目资源准备 准备项目的各种图片资源等等 注意:在webpack可以不用css sprite,直接用单张图片,因为它会帮忙打包. 还有SVG图片, ...
- springmvc+mybatis事务回滚
spring-mybatis.xml中 配置了 <!-- 拦截器方式配置事物 --> <tx:advice id="transactionAdvice" tran ...
- ACM/ICPC 之 中国剩余定理+容斥原理(HDU5768)
二进制枚举+容斥原理+中国剩余定理 #include<iostream> #include<cstring> #include<cstdio> #include&l ...
- 适配各种Windows分辨率,为DPI添加感知,当在高DPI时,禁用WINFORM缩放等。
因为现在高分屏越来越多,很多windows设备必须设置高DPI,这样很容易导致WINFORM整体错位,因此我们需要自己适配.禁止缩放 在程序配置清单 mainfest中添加如下. <assemb ...
- 聊一聊log4j2配置文件log4j2.xml
一.背景 最近由于项目的需要,我们把log4j 1.x的版本全部迁移成log4j 2.x 的版本,那随之而来的slf4j整合log4j的配置(使用Slf4j集成Log4j2构建项目日志系统的完美解决方 ...
- cnetos7.0 安装mysql
CentOS 7的yum源中貌似没有正常安装mysql时的mysql-sever文件,需要去官网上下载 [root@localhost ~]# wget http://dev.mysql.com/ge ...
- AspNetPager分页控件的使用
下面所记得东西仅仅是使用方法,详细知识点请看链接:http://www.webdiyer.com/Controls/AspNetPager/Downloads 首先:从网站上下载并安装控件 下载地址: ...