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 相关文章推荐
js 对象是否存在判断
Jul 15 Javascript
监控 url fragment变化的js代码
Apr 19 Javascript
jQuery对象[0]是什么含义?
Jul 31 Javascript
JavaScript的作用域和块级作用域概念理解
Sep 21 Javascript
Jquery对象和Dom对象的区别分析
Nov 20 Javascript
Ajax+FormData+javascript实现无刷新表单信息提交
Oct 24 Javascript
两种简单的跨域方法(jsonp、php)
Jan 02 Javascript
Vue+Mock.js模拟登录和表格的增删改查功能
Jul 26 Javascript
微信小程序实现图片滚动效果示例
Dec 05 Javascript
Angular中innerHTML标签的样式不起作用的原因解析
Jun 18 Javascript
Vue v-bind动态绑定class实例方法
Jan 15 Javascript
JS实现横向轮播图(中级版)
Jan 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
索尼SONY SRF-S83/84电路分析和打磨
2021/03/02 无线电
PHP数据库万能引擎类adodb配置使用以及实例集锦
2014/06/12 PHP
php压缩和解压缩字符串的方法
2015/03/14 PHP
浅谈PHP中的错误处理和异常处理
2017/02/04 PHP
浅谈PHP进程管理
2019/03/08 PHP
js带按钮的提示框可供选择示例代码
2013/09/17 Javascript
jquery实现多级下拉菜单的实例代码
2013/10/02 Javascript
正则表达式中特殊符号及正则表达式的几种方法总结(replace,test,search)
2013/11/26 Javascript
JavaScript中判断变量是数组、函数或是对象类型的方法
2015/02/25 Javascript
javascript实现图像循环明暗变化的方法
2015/02/25 Javascript
Javascript 计算字符串在localStorage中所占字节数
2015/10/21 Javascript
浅析jquery与checkbox的checked属性的问题
2016/04/27 Javascript
javascript执行环境及作用域详解
2016/05/05 Javascript
JavaScript中Number对象的toFixed() 方法详解
2016/09/02 Javascript
详解闭包解决jQuery中AJAX的外部变量问题
2017/02/22 Javascript
bootstrap实现动态进度条效果
2017/03/08 Javascript
AngularJS双向绑定和依赖反转实例详解
2017/04/15 Javascript
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
vue2.0中vue-cli实现全选、单选计算总价格的实例代码
2017/07/18 Javascript
js 两数组去除重复数值的实例
2017/12/06 Javascript
javascript深拷贝、浅拷贝和循环引用深入理解
2018/05/27 Javascript
JS模拟浏览器实现全局搜索功能
2019/09/11 Javascript
js判断复选框是否选中的方法示例【基于jQuery】
2019/10/10 jQuery
python中异常捕获方法详解
2017/03/03 Python
python基础教程项目四之新闻聚合
2018/04/02 Python
Python3实现对列表按元组指定列进行排序的方法分析
2018/12/22 Python
Django模板标签中url使用详解(url跳转到指定页面)
2020/03/19 Python
Otticanet美国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/03/10 全球购物
linux面试题参考答案(4)
2013/01/28 面试题
客户代表实习人员自我鉴定
2013/09/27 职场文书
应聘教师自荐信
2013/10/12 职场文书
小学校本培训方案
2014/06/06 职场文书
出纳试用期工作总结2015
2015/05/28 职场文书
离婚民事起诉状
2015/08/03 职场文书
Nginx中break与last的区别详析
2021/03/31 Servers
redis实现排行榜功能
2021/05/24 Redis