JavaScript高级程序设计 扩展--关于动态原型


Posted in Javascript onNovember 09, 2010

但是作者Nicholas C. Zakas在【动态原型】方式创建对象的时候没有深究可能会存在的问题和解决方案。而仅仅在继承的时候对【动态原型】的瓶颈作了说明。即在作子类继承的时候,不能通过动态原型的方式来实现。

原文大致如下:
继承机制不能采用动态化的原因是:prototype对象的唯一性。实例代码:

function A (i) { 
this.a = i; 
if (typeof A._init == 'undefined') { 
A.prototype.func = function () { 
return 0; 
} 
A._init = 1; 
} 
} 
function subA (j) { 
A.call(this, 1); 
this.j = j; 
if (typeof subA._init == 'undefined') { 
subA.prototype = new A(); 
subA.prototype.func_sub = function () { 
return ++j; 
} 
subA._init = 1; 
} 
} 
var sub_a = new subA(1); 
alert(sub_a.func_sub()); //error: sub_a.func_sub is not a function

Nicholas解释说在代码运行前,对象已被实例,并与prototype联系,在当前对prototype对象替换不会对它产生任何影响,即当前的替换是访问不到的,只有未来对象的实例才会反映出这种改变。于是第一个实例对象就会不正确。但第二个及以后的子类实例都没问题。
解决方法就是在构造函数外赋予新的prototype对象:
function A (i) { 
this.a = i; 
if (typeof A._init == 'undefined') { 
A.prototype.func = function () { 
return 0; 
} 
A._init = 1; 
} 
} 
function subA (j) { 
A.call(this, 1); 
this.j = j; 
if (typeof subA._init == 'undefined') { 
subA.prototype.func_sub = function () { 
return ++j; 
} 
subA._init = 1; 
} 
} 
subA.prototype = new A(); 
var sub_a = new subA(1); 
alert(sub_a.func_sub()); //2

可惜这违反了我们为什么使用动态原型的初衷。
使用动态原型的初衷本来就是要让构造函数能“统一江山”,在视觉上让人觉得原型方法是类构造的一部分。

以上是《JavaScript高级程序设计》中对动态原型继承小节的大概内容。
<! -- ========== 分割线 ============ -->

可是Nicholas在先前的章节讲对象构造的【动态原型】方式中,似乎忘了提这个同样的问题。我们看看上文中最后一个例子:

var Obj = function (name) { 
this.name = name; 
this.flag = new Array('A', 'B'); 
if (typeof Obj._init == 'undefined') { 
Obj.prototype = { 
showName : function () { 
alert(this.name); 
} 
}; 
Obj._init = true; 
} 
} 
var obj1 = new Obj('aa'); 
var obj2 = new Obj('bb'); 
obj1.showName(); //error: is not a function 
obj2.showName(); // bb;

是的,这个问题其实和子类继承中出现的问题如出一辙,prototype在当前的替换是不会对该对象有任何影响的,只有在未来的实例中可见。如果按照Nicholas处理动态原型继承的方式中说的一样,那就意味着只能在构造函数外边重新赋予prototype对象。那么这不就成了【构造函数/原型混合】方式了吗?所谓的【动态原型】方式也就不存在了...

其实我们可以想想,为什么在【构造函数/原型混合】这种已经基本没有副作用的构建对象方式后面还要在写一节【动态原型】方式。作者的意图无非就是想让构造函数在视觉上更为统一么。其实仅仅要视觉上的统一可以不用动态原型的。

var Obj = function () { 
function __initialize (name) { 
this.name = name; 
this.flag = new Array('A', 'B'); 
} 
__initialize.prototype = { 
showName : function () { 
alert(this.name); 
}, 
showFlag : function () { 
alert(this.flag); 
} 
} 
return __initialize; 
}(); 
var obj1 = new Obj('aa'); 
var obj2 = new Obj('bb'); 
obj1.showName(); // aa 
obj2.showName(); // bb

其实上面的方式就可以算是视觉的统一了,Obj的构造函数内通过__initialize来初始化属性,通过__initialize.prototype原型初始化方法。只不过稍微有点“小作弊”的感觉,__initialize代理了Obj的初始化...

下面是来自tangoboy的“构造类”的封装,其实思路和上面基本一致,唯一不同的是他把属性也用原型方式创建了,同时把初始化属性和方法都扔到了构造函数参数对象里。方便自定义:

/* == form tangoboy == */ 
window['$Class'] = { 
//创建一个类 混合构造函数/原型方式 
create: function(config) { 
var obj = function(){},config = config||{}; 
//过滤构造方法和原型方法 
obj = obj.prototype.constructor = config["__"]||obj; 
delete config["__"]; 
obj.prototype = config; 
return obj; 
} 
} 
/* -- eg -- */ 
var man = $Class.create({ 
__ : function (name) { 
this.name = name; 
}, 
sex : 'male', 
showName : function () { 
alert(this.name); 
} 
}); 
var me = new man('ru'); 
me.showName(); //ru

其实如果硬要追求视觉的统一也可以不用动态原型的方式。说到底看看上面的思路,已经回溯到了我们最常用的“类构造”方式:
var Class = { 
create : function () { 
return function () { 
this.initialize.apply(this, arguments); 
} 
} 
}

相信上面这段代码大家或许都不会陌生,如果细究下去,会发现其实和上面的代码都一致,用initialize函数作了初始化的代理,从而完成了视觉的统一。
Javascript 相关文章推荐
DOMAssitant最新版 DOMAssistant 2.5发布
Dec 25 Javascript
javascript Object与Function使用
Jan 11 Javascript
js保留两位小数使用toFixed实现
Jul 29 Javascript
js中substr,substring,indexOf,lastIndexOf,split,replace的用法详解
Nov 09 Javascript
使用Script元素发送JSONP请求的方法
Jun 12 Javascript
bootstrap基本配置_动力节点Java学院整理
Jul 14 Javascript
Angular2使用SVG自定义图表(条形图、折线图)组件示例
May 10 Javascript
IE11下CKEditor在Bootstrap Modal中下拉问题的解决
Sep 25 Javascript
JS window对象简单操作完整示例
Jan 14 Javascript
node创建Vue项目步骤详解
Mar 06 Javascript
微信小程序报错: thirdScriptError的错误问题
Jun 19 Javascript
Ajax 的初步实现(使用vscode+node.js+express框架)
Jun 18 Javascript
关于JavaScript定义类和对象的几种方式
Nov 09 #Javascript
JS图片浏览组件PhotoLook的公开属性方法介绍和进阶实例代码
Nov 09 #Javascript
一个javascript图片阅览组件
Nov 09 #Javascript
js中格式化日期时间型数据函数代码
Nov 08 #Javascript
window.location.hash 使用说明
Nov 08 #Javascript
JavaScript游戏之是男人就下100层代码打包
Nov 08 #Javascript
JavaScript游戏之优化篇
Nov 08 #Javascript
You might like
PHP __autoload()方法真的影响性能吗?
2012/03/30 PHP
php数组去重实例及分析
2013/11/26 PHP
php查询操作实现投票功能
2016/05/09 PHP
Yii2 assets清除缓存的方法
2016/05/16 PHP
js去除重复字符串两种实现方法
2013/01/09 Javascript
Javascript 遮罩层和加载效果代码
2013/08/01 Javascript
对frameset、frame、iframe的js操作示例代码
2013/08/16 Javascript
Knockout text绑定DOM的使用方法
2013/11/15 Javascript
javascript判断office版本示例
2014/04/11 Javascript
jquery+javascript编写国籍控件
2015/02/12 Javascript
微信小程序 教程之条件渲染
2016/10/18 Javascript
JS实现用户注册时获取短信验证码和倒计时功能
2016/10/27 Javascript
BootStrap Table对前台页面表格的支持实例讲解
2016/12/22 Javascript
javascript获取指定区间范围随机数的方法
2017/09/08 Javascript
详解Vue.js自定义tipOnce指令用法实例
2018/12/19 Javascript
jQuery表单校验插件validator使用方法详解
2020/02/18 jQuery
JavaScript oncopy事件用法实例解析
2020/05/13 Javascript
在Django框架中运行Python应用全攻略
2015/07/17 Python
详解Python的Django框架中的Cookie相关处理
2015/07/22 Python
Python序列操作之进阶篇
2016/12/08 Python
利用python获取某年中每个月的第一天和最后一天
2016/12/15 Python
Python2.7.10以上pip更新及其他包的安装教程
2018/06/12 Python
python读取几个G的csv文件方法
2019/01/07 Python
python归并排序算法过程实例讲解
2020/11/04 Python
python实现在列表中查找某个元素的下标示例
2020/11/16 Python
Python修改DBF文件指定列
2020/12/19 Python
Wilson体育用品官网:美国著名运动器材品牌
2019/05/12 全球购物
销售冠军获奖感言
2014/02/03 职场文书
《谁的本领大》教后反思
2014/04/25 职场文书
公司法人授权委托书范本
2014/09/12 职场文书
学校党委副书记个人对照检查材料思想汇报
2014/09/28 职场文书
贫困证明怎么写
2015/06/16 职场文书
React列表栏及购物车组件使用详解
2021/06/28 Javascript
一篇文章带你复习java知识点
2021/06/28 Java/Android
quickjs 封装 JavaScript 沙箱详情
2021/11/02 Javascript
前端与RabbitMQ实时消息推送未读消息小红点实现示例
2022/07/23 Java/Android