javascript面向对象三大特征之封装实例详解
作者:Johnny丶me 发布时间:2023-08-23 21:39:04
本文实例讲述了javascript面向对象三大特征之封装。分享给大家供大家参考,具体如下:
封装
封装(Encapsulation):就是把对象内部数据和操作细节进行隐藏。很多面向对象语言都支持封装特性,提供关键字如private来隐藏某些属性和方法。要想访问被封装对象中的数据,只能使用对象专门提供的对外接口,这个接口一般为方法。调用该方法能够获取对象内部数据。
在JavaScript语言中没有提供专门的信息封装关键字,不过可以使用闭包来创建,只允许从对象内部访问的方法和属性。另外,接口也是数据封装的一种工具,接口提供了外界访问方法的约定。在应用开发中,所有类都应定义接口,类只向外提供已实现接口中规定的方法,任何别的方法都是隐藏的。其所有属性都是私有的,外界只能通过接口中定义的存取操作与之打交道。
---引自 《jQuery开发从入门到精通》,不过原书有错误,或者可能是我错买了盗版,不过下面代码都是经过我修改的,没有问题。
被动封装
被动封装:就是对对象内部数据进行适当约定,这种约定具有很强的主观性,没有强制性保证,主要针对公共对象而言。一般来说,JavaScript所包含的数据都是公开的,没有隐私可言,其中的信息可以随意被访问。下面给出一个例子来阐述:
var Person = function (name,gender) {
if(name === undefined) {
throw new Error("name is necessary")
} else {
this.name = name;
}
if(gender === undefined) {
throw new Error("gender is necessary")
} else {
this.gender = gender;
}
}
var p = new Person("Tom",1); // 如果我们实例化的时候,如果传递参数错误了,将会报异常
为了数据安全,代码中适当的增加了一些条件限制,避免非法信息侵入。
var Animal = function (species) {
if(!this.checkSpecies(species)) {
throw new Error('species is illegal');
} else {
this.species = species;
}
}
Animal.prototype = {
checkSpecies:function(species){
// 检测 species , 参数为 species , 合法返回true ,这里可自定义检测逻辑
// 这里先让它直接返回 true
return true;
}
}
var ani = new Animal("dog");
从更安全和扩展的角度来说,凡是类都应该定义接口,这样能够保证数据存取更加安全,同时也方便团队的合作。内部私有方法检测和接口措施可在一定程度上保护对象内部数据,但是他们也存在一个致命漏洞(这些属性和方法可以被公开重置,面对公开覆盖属性和方法值,任何人都无法阻止这种行为。),比如这样的:
var Util = function() {};
Util.prototype = {
_say:function(){
console.log("这里有一个私有的成员 _say方法");
}
}
// 下面我们来修改它
Util.prototype._say = function(){
console.log('哈哈,我已经被修改了');
}
// 开始检测
var util = new Util;
util._say(); // 哈哈,我已经被修改了
同时内部检测和接口可以在一定程度上占用了系统开销,这个问题也是必须认真考虑的。
就像上面的代码那样,一般我们约定了区别公共和私有成员,就是在一些方法和属性名称前或者后加下划线,来表示私有。
下划线命名是一种约定俗称的命名规范,表示一个属性和方法仅供内部使用,直接访问可能会导致意外发生。
以上数据保护方式都是被动性防御,因为他们只是一种约定,只有在遵守的时候才有效果。主要适用于非敏感性的内部方法和属性。
主动封装
在js中,因为函数有作用域,在函数内部声明的变量,在函数外部无法访问。而所以的私有和公有的区别就在于在对象外部是否可以访问。所以实现封装的最佳选择是使用函数的作用域。举例:
function haha() {
var n = 1;
function hehe() {
n++;
}
hehe();
return n;
}
console.log(haha()); // 2
函数haha内部有私有变量n,在此作用域中,hehe能够访问n,而haha外部的任何函数都无法访问haha里的n。
同样的,我们在函数内部返回hehe,就可以在外部来调用haha私有函数hehe。
function haha() {
var n = 1;
function hehe() {
return ++n;
}
return hehe;
}
console.log(haha()()); // 2
函数作用域内部的方法无法被外界访问,但是在函数作用域内部的其他公共方法可以访问到它们,于是利用公共方法为中转站,可以巧妙的把内部私有方法公开化。因此这些公共方法也被称为特权方法,即在方法前面加this关键字。
使用这种方式创建的对象具有真正的封装性如:
function A() {
// 私有方法 _xx
function _xx(){}
// 公有方法
this.xx = function() {
return _xx;
}
}
A.prototype = {
other:function() {
console.log("other方法代表不需要访问私有属性和方法的方法,一般放在原型里");
}
}
但是这种方式也有一些缺点:
① 新生成的每个实例对象都会拷贝构造函数中的属性和方法,而私有的_xx 无疑在每次实例化的时候都会重复拷贝,这样会占用大量内存,所以不适合大量使用,仅在必要时适当使用
② 不利于类的继承,所有派生的子类都不能访问超类中的私有属性和方法。不过可以使用特权方法来访问超类中的私有属性和方法。举个例子:
// B 是超类
function B() {
var _private = 1;
function _checkPrivate() {
return _private;
}
this.checkPrivate = function() {
return _checkPrivate;
}
}
// C 是派生类
function C() {
B.call(this); // 用call 实现继承 ,后面我们会讲到如何继承
// this.private = _private; // 这里尝试访问超类的私有属性,因为无法访问,会报错
}
// 实例化 派生类C
var c = new C();
// console.log(c.private); // 和在C内部的尝试一样,是无法访问的,报错
// 不过可以用下面的方法访问超类中的私有属性
console.log(c.checkPrivate()()); // 1
静态方法
在面向对象编程中,大多数的方法和属性与类的实例产生联系。还有一种情况是,静态属性和方法是与类本身直接联系,可直接从类访问,也就是说,静态成员在类上操作,而不是实例上。在JavaScript中的Math和Global都是静态对象,不需要实例化就可直接访问。
类的静态成员,包括私有和公共两种。他们在系统中只有一份副本,意思就是说他们不会被分成多份传递给不同的实例对象。而是通过函数指针进行引用。书上有个例子非常好,下面举例:
var F = (function(){ // 把闭包函数赋给F,返回一个构造函数
var _a = 1; // 定义一个闭包体内的私有变量
this.a = _a; // 闭包体内的公共属性 a
this.get1 = function(){ // 闭包体内的公共方法get1
return _a;
}
this.set1 = function(x){ // 闭包体内的公共方法set1
_a = x;
};
return function(){ // 返回一个构造函数,构造函数也是函数,更是对象(相当于一个类)
this.get2 = function() { // 类的get2方法
return _a;
};
this.set2 = function(x) { // 类的set2方法
_a = x;
};
}
})();
// 定义类的静态公共方法和属性
F.get3 = function(){ // 定义一个静态方法get3
return get1(); // 这里可以直接使用 F内的公共方法get1
}
F.set3 = function(x) { // 定义一个静态方法set3
return set1(x); // 同get1
}
// 下面开始测试
var f = new F(); // 实例化这个类
console.log(f.get2()); // 1 用实例对象访问公共方法get2
F.set3(3); // 调用静态方法set3
console.log(F.get3()); // 3
F.A = ++a; // 定义一个静态属性A
console.log(F.A); // 2
我们推荐使用这种闭包的封装方式
希望本文所述对大家JavaScript程序设计有所帮助。
来源:https://blog.csdn.net/Tyro_java/article/details/51164915


猜你喜欢
- 例一:使用httplib访问某个url然后获取返回的内容:import httplibconn=httplib.HTTPConne
- 这个周忙的就像打仗一样,感觉有点被别人牵着鼻子走了,每天都是早出晚归,干不完的活儿,有时候感觉DBA这碗饭真的不好
- 本文实例讲述了golang image图片处理方法。分享给大家供大家参考,具体如下:golang处理图片挺简单的,我是过功能挺简单的,没有过
- 在最开始的时候所有的斐波那契代码都是使用递归的方式来写的,递归有很多的缺点,执行效率低下,浪费资源,还有可能会造成栈溢出,而递归的程序的优点
- 1、工厂模式在面向对象编程中,工厂模式是开发过程中最常用的设计模式之一,属于创建型模式,就是通过一个接口函数或对象来创建其他对象并返回,该模
- 在金融领域中,我们的y值和预测得到的违约概率刚好是两个分布未知的两个分布。好的信用风控模型一般从准确性、稳定性和可解释性来评估模型。一般来说
- 我们在开发过程中,有时候需要把float,int型等数字作为金额类型数字显示会出现很多问题,比如float会显示成 965868.45999
- 大家都知道,在ASP中可以使用Request.ServerVariables("REMOTE_ADDR")来取得客户端的
- ConfigParser模块在Python3修改为configparser,这个模块定义了一个ConfigeParser类,该类的作用是让配
- 什么是序列化与反序列化这里引入微软对序列化的解释:序列化是指将对象转换成字节流,从而存储对象或将对象传输到内存、数据库或文件的过程。 它的主
- 本文主要给大家介绍了关于CentOS 6.5 安装Python 3.5.2并与Python2并存的相关内容,分享出来供大家参考学习,下面来看
- Python下载Python最新源码,二进制文档,新闻资讯等可以在Python的官网查看到:Python官网:http://www.pyth
- js部分setInterval("time_controller()",1000);function time_cont
- 网上async with和async for的中文资料比较少,我把PEP 492中的官方陈述翻译一下。异步上下文管理器”async with
- 本文实例为大家分享了python绘制雪花的具体代码,供大家参考,具体内容如下代码非常容易理解,画着玩玩还是可以的。直接上代码# -*- co
- 一、运行vue项目1、下载node.js安装完成后分别在cmd中执行node -v查看是否安装成功,出现版本号就安装成功了2、安装 webp
- 宝塔更新Python版本因为在宝塔中的Python版本为2.6.8,使用宝塔Python项目管理的话需要把Python升级到3.x,不然的话
- 最近需要做一个围棋识别的项目,首先要将棋盘位置定位出来,效果图如下:效果图原图中间处理效果最终结果思路分析我们利用python opencv
- 一、事务:事务是逻辑上的一组操作,要么都成功,要么都失败!——————————————————————————————————1、SQL执行
- var obj=document.getElementById("txtUserID") var range=obj.c