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 相关文章推荐
JQuery 绑定事件时传递参数的实现方法
Oct 13 Javascript
jquery下将选择的checkbox的id组成字符串的方法
Nov 28 Javascript
jquery post方式传递多个参数值后台以数组的方式进行接收
Jan 11 Javascript
JavaScript获取/更改文本框的值的实例代码
Aug 02 Javascript
jquery 日期控件datepicker属性详细解析
Nov 08 Javascript
两款JS脚本判断手机浏览器类型跳转WAP手机网站
Oct 16 Javascript
JavaScript和jquery获取父级元素、子级元素、兄弟元素的方法
Jun 05 Javascript
JavaScript实现的微信二维码图片生成器的示例
Oct 26 Javascript
ajax+node+request爬取网络图片的实例(宅男福利)
Aug 28 Javascript
在 vue-cli v3.0 中使用 SCSS/SASS的方法
Jun 14 Javascript
Js 利用正则表达式和replace函数获取string中所有被匹配到的文本(推荐)
Oct 28 Javascript
小程序实现列表点赞功能
Nov 02 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
模拟flock实现文件锁定
2007/02/14 PHP
解析php中heredoc的使用方法
2013/06/17 PHP
合并ThinkPHP配置文件以消除代码冗余的实现方法
2014/07/22 PHP
PHP PDOStatement::errorInfo讲解
2019/01/31 PHP
PHP将整数数字转换为罗马数字实例分享
2019/03/17 PHP
javascript 语法基础 想学习js的朋友可以看看
2009/12/16 Javascript
JS实现标签页效果(配合css)
2013/04/03 Javascript
jquery 动态创建元素的方式介绍及应用
2013/04/21 Javascript
jquery队列queue与原生模仿其实现方法分享
2014/03/25 Javascript
JS使用replace()方法和正则表达式进行字符串的搜索与替换实例
2014/04/10 Javascript
使用jquery组件qrcode生成二维码及应用指南
2015/02/22 Javascript
JS实现的数组全排列输出算法
2015/03/19 Javascript
javascript生成img标签的3种实现方法(对象、方法、html)
2015/12/25 Javascript
一起学写js Calender日历控件
2016/04/14 Javascript
基于MVC5和Bootstrap的jQuery TreeView树形控件(一)之数据支持json字符串、list集合
2016/08/11 Javascript
javascript中this用法实例详解
2017/04/06 Javascript
详谈javascript精度问题与调整
2017/07/08 Javascript
Vue拖拽组件列表实现动态页面配置功能
2019/06/17 Javascript
详解JavaScript执行模型
2020/11/16 Javascript
[42:32]Secret vs Optic 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python里disconnect UDP套接字的方法
2015/04/23 Python
Python使用base64模块进行二进制数据编码详解
2018/01/11 Python
Python3爬虫全国地址信息
2019/01/05 Python
python的依赖管理的实现
2019/05/14 Python
python三大神器之fabric使用教程
2019/06/10 Python
pyinstaller参数介绍以及总结详解
2019/07/12 Python
Hotels.com爱尔兰:全球酒店预订
2017/02/24 全球购物
诺心蛋糕官网:LE CAKE
2018/08/25 全球购物
上海奥佳笔试题面试题
2016/11/16 面试题
国培教师自我鉴定
2014/02/12 职场文书
李开复演讲稿
2014/05/24 职场文书
企业宣传标语
2014/06/09 职场文书
二手手机买卖合同范本(2019年版)
2019/10/28 职场文书
浅谈Python实现opencv之图片色素的数值运算和逻辑运算
2021/06/23 Python
Vue Element-ui表单校验规则实现
2021/07/09 Vue.js
分享一个vue实现的记事本功能案例
2022/04/11 Vue.js