JavaScript 模拟类机制及私有变量的方法及思路


Posted in Javascript onJuly 10, 2013

在使用一些 Javascript 框架时,或许会看到类似的代码

var MyClass = new Class({


initialize: function(param, ...) {



this.param = param;



...


},


func1: function(...) {



...


}

});

var myObj = new MyClass(param);

myObj.func1(...);

这是一种典型的面向对象的类机制应用,与原生的 Javascript 类机制相比,显得更为清晰和自然。并且,在此基础上,实现类的继承也较为方便。那么,这是如何实现的呢?
众所周知,在 Javascript 中,将一个函数作为构造器,可以创建出一个对象,上面的代码可以简单的写成:
function MyClass(param) {


this.param = param;


this.func1 = function(..) {



...


};

}

var myObj = new MyClass(param);

myObj.func1();

其实还是蛮简单的,也不难理解。不过如果要构建一套大型的 Javascript 类库,可能就会比较混乱,从一堆代码中,要找出哪些是类,哪些是函数,哪些是类方法,哪些是类属性,是一件痛苦的事。
当然,这里并不是要比较它们的优劣,只是好奇 new Class 的实现方式而已。
在上面的代码中,使用 new MyClass() 这样的语句,意味着 MyClass 必须是一个函数,同时也就意味着 new Class 需要返回一个函数对象,从字面的意思上可以看出,函数 initialize 是当做构造函数来使用的,所以,new Class 返回的函数中,必须使用 initialize 来对对象进行初始化。基于这样的分析,可以得出以下代码:
function Class(argu) {


return function() {



var init = argu['initialize'] || function() {};  //如果没有构造函数 initialize,使用一个空函数作为默认构造函数



for(var p in argu) {




this[p] = argu[p];



}



init.apply(this, arguments); //使用当前函数的 this 来代替函数 initialize 原有的 this


}

}

上面的代码并不够严谨,但用来说明问题已经足够了。需要注意 init.apply(this, arguments) 这一句,这里有几个变量的指代,一个是 this,原本 initialize 中默认的 this,现在已被替代为返回的这个匿名函数的 this,而这个匿名函数,是通过 new Class 新建的自定义类的构造器。另外一个是 arguments,它指代的是匿名函数的参数,也就是上面的 new MyClass(param) 中的 param。
this 的转换有些让人头晕,那么有没有更为简单的方法呢?请看下面的代码:
function Class(argu) {


var obj = argu['initialize'] || function() {};


for(var p in argu) {



obj.prototype[p] = argu[p]; //注意,这里用的是 prototype


}


return obj; // 其??还是返回一??函??BR>
}

呵呵,感觉直白了许多。
这就完成了一个简单的类机制的构建。通过这种机制,可以创建类的构造函数、方法及属性,但这些显然都是公有的,那么,如何实现私有变量及方法呢?
我们知道,Javascript 类的私有变量可以通过闭包的机制来完成。但使用 new Class({...}) 的方式转换后,显然很难形成有效的闭包。如何绕过这个问题呢?
Javascript 提供了两个方法:eval() 及函数对象的 toString() 方法,前者较为常见,而后者,可用于获取函数的具体代码。通过这两个方法,可以简单的模拟类的私有变量:
function Class(argu) {


var _ = argu['private'] || {};


eval('var obj = ' + (argu['initialize'] || function() {}).toString());


for(var p in argu) {



if(p == 'initialize' || p == 'private')




continue;



if(typeof argu[p] == 'function')




eval('obj.prototype[p] = ' + argu[p].toString());



else




obj.prototype[p] = argu[p];


}


return obj;

}

通过函数对象的 toString() 方法提取出函数的代码,并使用 eval 方法执行这些代码,这样就可以构造出一个有效的闭包范围,从而实现私有机制。我们可以如下应用:
var Person = new Class({


private: {



height: 160,



weight: 50


},


initialize: function(name, height, weight) {



this.name = name;



_.height = height || _.height;



_.weight = weight || _.weight;


},


show: function() {



alert('Name:' + this.name + '/nheight:' + _.height + '/nweight:' + _.weight);


}

});

var my = new Person("Zh");

my.show();

看起来不不错,不过在实际应用中,其实并没有太大的用途。主要是效率上,相比通常的实现方式,大概需要多花四倍的时间。在大型类库的构建上,这是不可容忍的,而小型的应用中,实现下面的代码更为简单直接:
function MyClass(param) {


var privateVar = ...;


this.param = param;


this.func = function() {



alert(privateVar);


};

}

Javascript 相关文章推荐
详解Angular2中的编程对象Observable
Sep 17 Javascript
浅谈jQuery绑定事件会叠加的解决方法和心得总结
Oct 26 Javascript
用Vue.js实现监听属性的变化
Nov 17 Javascript
jQuery回调方法使用示例
Jun 26 jQuery
Bootstrap 模态框自定义点击和关闭事件详解
Aug 10 Javascript
jQuery实现表格隔行换色
Sep 01 jQuery
微信小程序中遇到的iOS兼容性问题小结
Nov 14 Javascript
vue 表单之通过v-model绑定单选按钮radio
May 13 Javascript
浅谈layui 绑定form submit提交表单的注意事项
Oct 25 Javascript
vue props 单项数据流实例分享
Feb 16 Javascript
vue使用map代替Aarry数组循环遍历的方法
Apr 30 Javascript
简单聊聊TypeScript只读修饰符
Apr 06 Javascript
js固定DIV高度,超出部分自动添加滚动条的简单方法
Jul 10 #Javascript
javascript 手动给表增加数据的小例子
Jul 10 #Javascript
基于javascript 闭包基础分享
Jul 10 #Javascript
关于include标签导致js路径找不到的问题分析及解决
Jul 09 #Javascript
等待指定时间后自动跳转或关闭当前页面的js代码
Jul 09 #Javascript
浅析js封装和作用域
Jul 09 #Javascript
js正则表达式的使用详解
Jul 09 #Javascript
You might like
PHP获取和操作配置文件php.ini的几个函数介绍
2013/06/24 PHP
php使用正则验证中文
2016/04/06 PHP
PHP生成静态HTML文档实现代码
2016/06/23 PHP
JSON 学习之JSON in JavaScript详细使用说明
2010/02/23 Javascript
jQuery的链式调用浅析
2010/12/03 Javascript
JavaScript Title、alt提示(Tips)实现源码解读
2010/12/12 Javascript
基于jquery的web页面日期格式化插件
2011/11/15 Javascript
详细分析使用AngularJS编程中提交表单的方式
2015/06/19 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
javascript动态生成树形菜单的方法
2015/11/14 Javascript
原生JavaScript实现滚动条效果
2020/03/24 Javascript
利用Angular.js限制textarea输入的字数
2016/10/20 Javascript
nodeJS(express4.x)+vue(vue-cli)构建前后端分离实例(带跨域)
2017/07/05 NodeJs
详解JS中的this、apply、call、bind(经典面试题)
2017/09/19 Javascript
详解使用vscode+es6写nodejs服务端调试配置
2017/09/21 NodeJs
微信小程序使用input组件实现密码框功能【附源码下载】
2017/12/11 Javascript
React中常见的动画实现的几种方式
2018/01/10 Javascript
基于Vue实现拖拽效果
2018/04/27 Javascript
React Native日期时间选择组件的示例代码
2018/04/27 Javascript
JS实现的文件拖拽上传功能示例
2018/05/21 Javascript
JavaScript解析及序列化JSON的方法实例分析
2019/01/04 Javascript
图解javascript作用域链
2019/05/27 Javascript
详解Vue-cli3.X使用px2rem遇到的问题
2019/08/09 Javascript
JS数组方法concat()用法实例分析
2020/01/18 Javascript
[02:03]DOTA2亚洲邀请赛 HGT战队出场宣传片
2015/02/07 DOTA
解决pycharm运行出错,代码正确结果不显示的问题
2018/11/30 Python
Python 中 sorted 如何自定义比较逻辑
2021/02/02 Python
中外合拍动画首获奥斯卡提名,“上海出品”《飞奔去月球》能否拿下最终大奖?
2021/03/16 国漫
css3中单位px,em,rem,vh,vw,vmin,vmax的区别及浏览器支持情况
2016/12/06 HTML / CSS
cosme官方海外旗舰店:日本最大化妆品和美容产品的综合口碑网站
2017/01/18 全球购物
正宗的日本零食和糖果订阅盒:Bokksu
2019/11/21 全球购物
5.1手机促销活动
2014/01/17 职场文书
小小的船教学反思
2014/02/21 职场文书
2014基建处领导班子“四风”对照检查材料思想汇报
2014/10/04 职场文书
毕业生爱心捐书倡议书
2015/04/27 职场文书
暖春观后感
2015/06/08 职场文书