当前位置: 首页 > 图文教程 > 网络编程 > Javascript > Javascript的构造函数和constructor属性

Javascript
web开发设计师比较费解的JavaScript
jQuery教程:整理的几个常见的初学者问题
免费资源:7个效果非常棒的jQuery 3D效果插件
JavaScript教程:编写匿名函数的几种方法
jQuery教程:jQuery的核心
jQuery教程:jQuery核心方法的使用
webjx收集45个jQuery导航插件和教程
30个气泡悬浮框(Tooltip)的jQuery插件
Jetpack扩展案例:Gmail邮件提醒功能
非常出色的jQuery运动特效可以和Flash媲美
ImagesLazyLoad 图片延迟加载效果
收集国外的14个图片放大编辑的jQuery插件
修改和创建DOM节点两种方式的4种优化方案
jQuery.Switchable整合插件用途介绍
提高Textarea操作性能优秀的jQuery插件
WEBJX收集12个非常有创意的JavaScript小游戏
Javascript教程:关于深入了解JS的几个问题

Javascript的构造函数和constructor属性


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2010-01-10   浏览: 61 ::
收藏到网摘: n/a

我们知道,默认情况下,对一个函数前面使用new,可以构造出一个对象。每一个对象都有一个constructor属性,这个constructor属性指向构造出该对象的函数。 例如,在Chrome下调试如下程序,很清楚的展示了这点:

image

然而事情并不是这么简单。再看下面的代码:

image
很显然,这个时候obj的constructor已经不再是创建它的函数,注意到obj.name也是undefined,因此修改构造函数的prototype的contructor并不会影响构造函数所产生的对象。真正的原因是:一个对象的constructor是它的构造函数的prototype.constructor,而每一个函数都有一个prototype,默认情况下,这个prototype有一个constructor属性,指向的是它自己。 我觉得Javascript的设计本意是让每个对象的constructor都指向自己的构造函数,然而有像上面的例子可以破坏这一点。另外,这样的设计其实也不很完美,一个很大的问题就是在继承的时候必须小心的维护constructor的指向。在最简单的继承中,可以把子类的构造函数的prototype设置为父类的一个实例,而父类的实例的constructor是父类的构造函数,从而子类的prototype的constructor是父类的构造函数,这就造成了子类的每个对象的构造函数都是父类的构造函数。这是很容易引起困惑的。
最后,再回到上一篇遗留下来的问题,上文谈到Extjs官网给出的一个继承Observable的例子:

复制代码 代码如下:

Employee = Ext.extend(Ext.util.Observable, {
constructor: function(config){
this.name = config.name;
this.addEvents({
"fired" : true,
"quit" : true
});
// Copy configured listeners into *this* object so that the base class's
// constructor will add them.
this.listeners = config.listeners;
// Call our superclass constructor to complete construction process.
Employee.superclass.constructor.call(config)
}
});

这个例子给人的错觉就是你可以重写父类的constructor属性,从而达到改变子类的构造函数的行为的效果。这对于Javascript基础却不深的人是一种误导。 我们再仔细看下Ext.extend的源代码:
复制代码 代码如下:

extend : function(){
// inline overrides
var io = function(o){
for(var m in o){
this[m] = o[m];
}
};
var oc = Object.prototype.constructor;
return function(sb, sp, overrides){
if(Ext.isObject(sp)){
overrides = sp;
sp = sb;
sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);}; //注意这里 }
//以下省略………}(), 请注意加注释的那一行。extend如果检测到overrides参数中有constructor属性,也就是说子类试图改写父类的prototype的constructor的时候,就直接将子类设置为这个函数!这样就达到效果了。不过我立刻发现这句检测仅在这个if语句块中,也就是extend的两参数版本中有,那么使用extend的另一个三参数版本这样设置应该是无效的。 写段代码测试下:
<head>
<title></title>
<script type="text/javascript" src="ext-3.1.0/src/core/core/Ext.js"></script>
<script type="text/javascript">
function MyClass() {
this.id = 'class';
}
function SubClass() { }
// SubClass=Ext.extend(SubClass, MyClass, { constructor: function() {
// this.overrideProperty = 'OK';
// }
// });
SubClass = Ext.extend(MyClass, { constructor: function() {
this.overrideProperty = 'OK';
}
});
var obj = new SubClass();
alert(obj.overrideProperty);
</script>
</head>

两种写法,运行的结果果然是第一种是undefined而第二种是OK。呃,名字相同的函数仅仅是参数写法不同,执行的效果却不相同,这个是有点出乎意料的。而且Extjs的官方文档未对此有任何说明。以后大家还是尽量用两参数版本的吧。
最后顺便再看几个表达式,
image
第一个是说函数的prototype的constructor是自己,这个上文已经谈到,没有问题;第二个是说函数也是一个对象,它是Function构造函数的一个对象,也还好理解;第三个是说Function构造函数本身一个对象,它还是Function构造函数的一个对象;最后一个其实是和第三个等价的,是说Function对象的构造函数是它自己…… 我确实有点想不明白Function是怎么自己构造自己的?鸡生蛋,蛋生鸡?要再追究下去就应该涉及到Javascript语言的具体实现了吧,就此打住。
哎,Javascript这个语言本身还是有点复杂啊。要不是有了XMLHttpObject,让它大红大紫了下,否则它还在黑暗的角落里暗自哭泣呢。
作为应用程序开发人员,或许我们自己写程序的并不会用到这些底层的东西,但是,JS框架中却大量的使用了这些高级特性,而且再详尽的文档也不可能把这些方法的作用、影响一一道来,所以开发人员还是需要尽量理解这些东西,以免死了还不知道怎么回事。上面的Ext.extend函数就是一个例子。