JavaScript实现类的private、protected、public、static以及继承
基础知识
JavaScript中的类
JavaScript实际上是一种弱类型语言,与C++和Java等语言不同。因此,在JavaScript中,没有强调类(class)这一概念,但实际运用中,类还是很重要的,比如写一款游戏,如果我们不停地调用函数来完成创建角色,移动角色的话,那会是什么样的呢?可能会出现非常多的重复代码,因此我们需要一个类来统一这些代码。所谓的类,就是把程序中的代码分类,比如说游戏中的关于角色的代码算作一类,游戏背景算作一类,游戏特效又是一类。这样一来,我们对类进行操作,就不会使代码显得很凌乱,冗杂。虽然Js是弱类型语言,但是也提供了类这一概率。
定义Js中的类,实际上用的是function
,总所周知,这个语法其实是用来定义函数的。不同于定义函数的是,我们可以在function
中通过this.xxx
的方式来定义属性和方法。比如说:
function People () {this.name = "Yorhom";this.getName = function () {return this.name};
}
使用的时候使用new
:
var yorhom = new People();
// "Yorhom"
alert(yorhom.getName());
可以看到,这样就可以使用到我们定义的类和类中的方法了。
也许你会问this.xxx
只能定义公有属性和方法,那私有属性和方法怎么办呢?这个可以用到js闭包的知识来解决:
function People () {this.name = "Yorhom";var age = 16;this.getName = function () {return this.name};this.getAge = function () {return age;};
}var yorhom = new People();
// undefined
alert(yorhom.age);
// 16
alert(yorhom.getAge());
可以看到,这里的age就是一个私有属性了。
JavaScript中的prototype
上面的代码美中不足的地方就是,如果一个类有很多方法,同时用到这个类的地方又有很多(也就是new
出来的对象有很多),那么用上面的代码就会出现内存占用过剩的问题。问题的根本原因在于,每次实例化一个对象,这个类就会执行构造器里的代码(以People类为例就是function People () {…}执行的代码),因此每当这个类被实例化的时候,这些方法和属性就会被拷贝到实例化出来的对象中。这样一来,就会造成“吃”内存的现象。
于是js中的prototype
就诞生了。prototype
的作用通常是给一个类添加一系列常量或者方法。 每当一个类被实例化之后,实例化出来的对象会自动获取类的prototype
中定义的方法和属性。只不过这里的获取类似于C++里面的引用,不会在内存里对这些方法和属性进行复制,而是指向这些方法和属性。示例:
function People () {this.name = "Yorhom";
}People.prototype.getName = function () {return this.name;
};var yorhom = new People();
// "Yorhom"
alert(yorhom.getName());
这种方法虽然可以节约内存,但是,美中不足的是,无法定义私有属性。
类的继承
Javascript没有提供继承的函数,所以只有自己写了。这里借用lufylegend.js中的继承方法向大家展示如何实现继承:
function base (d, b, a) {var p = null, o = d.constructor.prototype, h = {};for (p in o) {h[p] = 1;}for (p in b.prototype) {if (!h[p]) {o[p] = b.prototype[p];}}b.apply(d, a);
}
这里的base就是继承函数了。继承函数的原理莫过于复制类的方法和属性。因此,只要做到这点,就可以实现类的继承了。可以在上面的代码中看见,我们通过遍历prototype
来获取原型链中定义的方法和属性。通过apply
调用父类的构造器进行构造器中属性和方法的复制。使用示例:
function People () {this.name = "Yorhom";
}People.prototype.getName = function () {return this.name;
};function Student () {base(this, People, []);
}var yorhom = new Student();
// "Yorhom"
alert(yorhom.getName());
静态属性和方法的定义
静态属性和方法以及静态类在js中的定义非常简单,先来看静态类:
var StaticClass = {};
这么写不是在定义一个Object
吗?是的,不错,不过js中的静态类也是可以这样定义的。如果要添加静态类中的方法和属性,就可以这么写:
var StaticClass = {id : 5,sayHello : function () {alert("Hello"); }
};
如果是要向类中添加静态属性或者方法,可以采用这种写法:
function People () {this.name = "Yorhom";
}People.prototype.getName = function () {return this.name;
};People.TYPE = "people";
People.sayHello = function () {alert("Hello");
};
实现一个功能丰富的类
我们在上文中提到了,节省内存和定义私有属性两者无法兼得,是啊,和“鱼和熊掌不可兼得”是一个道理,在通常的使用过程中,我们需要对这两项进行取舍。但是现在这个年代,哪有不可兼得的呢?鱼和熊掌不能同时吃?当然不行……因为吃熊掌是违法的(有待考证)?不过至少鸡和鱼是可以同时吃的吧。
由于js没有实现私有属性的定义,所以这其实是一个没有头绪的工作,因为在标准的做法中,我们除了闭包可以阻止外部访问,没有别的办法了。所以这里我们要用点歪门邪道的方法了。
JavaScript Set/Get访问器
什么是set/get访问器呢?如果你熟悉python,那么你可以理解为@property
和@xxx.setter
,但是简陋的js里也有?当然有,只不过是ES5的标准,可以采用这种写法:
Object.defineProperty(this, "name", {get : funtion () {return name;},set : function (v) {name = v;}
});
具体有什么用呢?大致就是this.name
属性在被获取的时候调用get
访问器,在被更改值的时候调用set
。
你可以从上面的代码了解大致的写法,不过如果你想深究,可以参考这篇文章:http://blog.csdn.net/teajs/article/details/22738851
注意以上的这种用法会有兼容性问题,浏览器支持情况如下:
PC端
Firefox | Google Chrome | Internet Explorer | Opera | Safari |
---|---|---|---|---|
4.0 | 5 | 9 | 11.6 | 5.1 |
移动端
Firefox Mobile | Android | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|
4.0 | Yes | 9 | 11.5 | Yes |
来自: https://developer.mozilla.org/…/defineProperty#Browser_compatibility
如何“歪门邪道”地做到禁止访问私有和保护属性?
这是个比较头疼的问题,正如本节开篇所说,我们在常规开发下,只能通过闭包来阻止某变量的访问。可是如果你使用了prototype
,那么闭包这条路就走不通了。在这种情况下,我们的Object.defineProperty
就出场了。我们知道,通过这个函数可以设定获取属性时返回的值,也可以设定更改属性时设置的值。有了这个函数,我们可以随时跟踪到某个属性是不是在被获取,或者是不是在被更改。我们还需要一个开关,我们在类内部的方法调用时,把这个开关打开,表明是在内部运行,方法调用结束后将开关关闭,表明回到外部运行状态。有了这两个状态,我们就可以跟踪private
和protected
属性和方法了,一旦他们在开关关闭的时候被使用,就终止这个属性或方法的获取或设置。
于是乎,大难题就快解决了。
开源库件jpp.js
秉着这个歪门邪道的思想,我把这个功能封装到jpp.js这个库件中,库件的github地址如下:
https://github.com/yuehaowang/jpp.js
当然这个库件不限于创建一个类,还可以实现函数的重载等。目前库件还处于开发阶段,欢迎各位提交建议。
使用jpp.js创建一个类
var People = jpp.class({extends : null,private : {id : null,hobby : null},protected : {money : null,phoneNumber : null},public : {firstName : null,lastName : null,age : null,birthday : null,occupation : null,constructor : function (name, id) {if (name) {var nameArray = name.split(" ");this.firstName = nameArray[0];this.lastName = nameArray[1];}if (id) {this.id = id;}},setBirthday : function (date) {if (date) {this.birthday = date;}},getBirthday : function () {return this.birthday;},askForId : function () {return this.id;},findHobby : function () {return this.hobby;}},static : {OCCUPATION_PROGRAMMER : "programmer",OCCUPATION_ARTIST : "artist",OCCUPATION_MUSICIAN : "musician",OCCUPATION_STUDENT : "student"}
});var peter = new People("Peter Wong", 543232123565);
peter.occupation = People.OCCUPATION_PROGRAMMER;peter.setBirthday("19980727");// result: Peter
alert(peter.firstName);
// result: 19990727
alert(peter.getBirthday());
// result: 51092028
alert(peter.askForId());
// result: null
alert(peter.findHobby());
// result: programmer
alert(peter.occupation);
// error
alert(peter.id);
对上面的代码进行分析:
使用jpp.class
函数创建一个类,函数的参数是一个Object,这个Object可添加的属性如下:
- extends 继承时的父类
- private 装载私有属性,里面定义的成员外部不可使用且不能继承给子类
- protected 装载保护属性,里面定义的成员外部不可使用但可以继承给子类
- public 装载公有属性
- static 装载静态方法和属性
在创建类的过程中,在public
中添加constructor
方法初始化构造器,this.super
可访问父类构造器。
运行代码,可以看到浏览器正常运行前5个alert
,而最后一个运行的时候浏览器报错:
具体的实现过程有点复杂,不过原理在上文已经详细讲述了。代码可以在github里参看,欢迎各位研究。
欢迎大家继续关注我的博客
转载请注明出处:Yorhom’s Game Box
http://blog.csdn.net/yorhomwang
JavaScript实现类的private、protected、public、static以及继承相关推荐
- 山科java实验3-2 在安排教师监考时,需要从一组教师中随机选取n个教师参加监考。要求实现一个类RandomTeacher的静态方法public static String[] getRandomT
在安排教师监考时,需要从一组教师中随机选取n个教师参加监考.要求实现一个类RandomTeacher的静态方法public static String[] getRandomTeachers(Stri ...
- C++中的private protected public区别
标签: c++ 2012-07-10 10:06 5805人阅读 评论(0) 收藏 举报 分类: C++ Primer笔记(4) 当private,public,protected单纯的作为一个类中的 ...
- 简述private protected public internal修饰的访问权限
private : 私有成员, 在类的内部才可以访问. protected : 保护成员,该类内部和继承类中可以访问. public : 公共成员,完全公开,没有访问限制. internal: 当 ...
- php中public放什么,PHP中常用关键字public, private, protected, static...
PHP中常用的关键字:public, private, protected, static, interface, implements, final 1.public.protected.priva ...
- Java中的主类概念以及public static void main方法的分析
1. 首先一定要有main()函数,不然你说从哪个函数开始执行呢 2. 包含main函数的类名不需要和文件名一致 因为字节码文件名只和类名有关,执行java程序时,也只是"java 类名&q ...
- 我的学习笔记001--private protected public internal mxx
1.简述 private protected public internal修饰符的访问权限 private: 私有成员, 在类的内部才可以访问. protected: 保护成员,该类内部和继承类中 ...
- public static
static:静态. 可以设置:静态类.静态变量.静态方法. 没有使用static修饰的成员为实例成员. 静态成员的使用:通过类名. 1.不加static修饰的成员是对象成员,归每个对象所有. 2.加 ...
- 解析Visual C# 7.2中的private protected访问修饰符
去年12月份,随着Visual Studio 2017 Update 15.5的发布,Visual C#迎来了它的最新版本:7.2. 在这个版本中,有个让人难以理解的新特性,就是private pro ...
- @synthesize@dynamic@private,@protected,@publicassign、weak、strong、retain、copy、nonatomic、atomic
iOS属性修饰关键字 1. @private,@protected,@public,@package详解及使用 @privite:私有的,只有本类(不包括子类)自己拥有 @protected:受保护的 ...
最新文章
- 【面试题视频讲解】求一个数的所有质因子
- 使用工具类实现通用分页处理
- vmstat命令列出的属性详解
- oracle系统实验,实验1 启动Oracle系统
- Java基础-异常处理机制
- 怎样设置才能允许外网访问MySQL
- 屏幕画线软件ZOOMIT
- 为mandriva 2010 spring打包(geany-0.19.2)
- 安卓Toast显示流程分析
- linux上centos镜像磁盘,VirtualBox中配置linuxCentOS的本地磁盘镜像iso作为其软件源
- 仅有爱情是不够的(转载)
- rrpp协议如何修改_RRPP(快速环网保护协议)
- EditPlus格式化xml文档
- Nature破解癌王生长关键:真菌由肠道入侵胰腺,定植增加3000倍,富集Malassezia菌...
- 教你如何在centos7服务器中屏蔽掉那些高流量ip
- 组态软件的开发(C#)
- 深入解析AAVE智能合约:计算和利率
- ICPC 2020 亚洲区域赛济南站 赛后总结
- 大型电商平台设计实例:电商平台项目工程、数据库选型、代码库
- 如果后端API一次返回10万条数据,前端应该如何处理?
热门文章
- 饥荒联机自建服务器有什么用,联机版饥荒使用专用服务器的好处 | 手游网游页游攻略大全...
- elasticsearch搜索过程分析
- GBase8s jdbc连接超时参数说明
- 酷比魔方iplay20_主打性价比的全网通平板酷比魔方iPlay 20体验评测
- 【OpenCV】OpenCV的VideoCapture读取网络地址视频慢的问题
- 各种乘法的区别 “点积、外积、数乘...等
- 使用本机ip和端口号不能访问tomcat服务问题解决方案
- 即使采用不同网络协议的计算机也能进行通信,11春-11秋真题汇编(含答案)
- CNN入门详解及TensorFlow源码实现--深度学习笔记
- 集五福华为机试python_2020 春节集五福最详细收集攻略