Javascript的构造函数和constructor属性_javascript技巧

例如,在Chrome下调试如下程序,很清楚的展示了这点:

 

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


很显然,这个时候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的官方文档未对此有任何说明。以后大家还是尽量用两参数版本的吧。
最后顺便再看几个表达式,
 
第一个是说函数的prototype的constructor是自己,这个上文已经谈到,没有问题;第二个是说函数也是一个对象,它是Function构造函数的一个对象,也还好理解;第三个是说Function构造函数本身一个对象,它还是Function构造函数的一个对象;最后一个其实是和第三个等价的,是说Function对象的构造函数是它自己…… 我确实有点想不明白Function是怎么自己构造自己的?鸡生蛋,蛋生鸡?要再追究下去就应该涉及到Javascript语言的具体实现了吧,就此打住。

哎,Javascript这个语言本身还是有点复杂啊。要不是有了XMLHttpObject,让它大红大紫了下,否则它还在黑暗的角落里暗自哭泣呢。

作为应用程序开发人员,或许我们自己写程序的并不会用到这些底层的东西,但是,JS框架中却大量的使用了这些高级特性,而且再详尽的文档也不可能把这些方法的作用、影响一一道来,所以开发人员还是需要尽量理解这些东西,以免死了还不知道怎么回事。上面的Ext.extend函数就是一个例子。

时间: 2024-10-14 20:08:23

Javascript的构造函数和constructor属性_javascript技巧的相关文章

浅谈JavaScript 数据属性和访问器属性_javascript技巧

在JavaScript中对象被定义为"无序属性的集合,其属性可以包含基本值.对象或函数."通俗点讲,我们可以把对象理解为一组一组的名值对,其中值可以是数据或函数. 创建自定义对象通常有两种方法,第一种就是创建一个Object的实例,然后再为其添加属性和方法,例如: var person = new Object(); person.name = "Scott"; person.age = 24; person.sayName = function(){ alert(

浅谈Javascript数据属性与访问器属性_javascript技巧

ES5中对象的属性可以分为'数据属性'和'访问器属性'两种. 数据属性一般用于存储数据数值,访问器属性对应的是set/get操作,不能直接存储数据值. 数据属性特性:value.writable.enumerable.configurable. 解释:configurable:true/false,是否可以通过delete删除属性,能否修改属性的特性,能否把属性修改为访问器属性,默认false: enumerable:true/false,是否可以通过for in循环返回,默认false: wr

详解JavaScript中的构造器Constructor模式_javascript技巧

构造器模式简单描述(看图): 构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading.构造器用于创建特定类型对象--准备好对象以备使用,同时接收构造器可以使用的参数,以在第一次创建对象时,设置成员属性和方法的值 1.创建对象 新对象创建的两种方法 var newObject={}; var newObject=new object();//object 构造器的简洁记法 2.基本Constructor Javascript不支持类的情况下对象

实例学习Javascript之构建方法、属性_javascript技巧

我爱你中国 爱你中国 中国爱你 很爱你中国 我爱你中国 爱你中国 中国爱你 很爱你中国

《JavaScript启示录》——1.18 构造函数实例都拥有指向其构造函数的Constructor属性

1.18 构造函数实例都拥有指向其构造函数的Constructor属性 任何对象实例化时,都是在幕后将constructor属性创建为对象/实例的属性.这是指创建对象的构造函数.下面创建一个Object()对象,保存在变量foo中,然后验证constructor属性在创建的对象中是否可用. <!DOCTYPE html><html lang="en"><body><script> var foo = {}; console.log(foo

深入理解javascript构造函数和原型对象_javascript技巧

常用的几种对象创建模式 使用new关键字创建 最基础的对象创建方式,无非就是和其他多数语言一样说的一样:没对象,你new一个呀! var gf = new Object(); gf.name = "tangwei"; gf.bar = "c++"; gf.sayWhat = function() { console.log(this.name + "said:love you forever"); } 使用字面量创建 这样似乎妥妥的了,但是宅寂的

JavaScript笔记之数据属性和存储器属性_javascript技巧

在javascript中,对象的属性分为数据属性和存储器属性两种: 两种属性的区别 我们使用Object.defineProperty()先来直观的感受一下这两者的不同. 使用Object.defineProperty()对数据属性进行设置的方法如下 var obj = {}; Object.defineProperty(obj, "prop", { value: 1, writable: true, //可写性 enumerable: true, //可枚举性 configurabl

javascript实现复选框选中属性_javascript技巧

熟悉web前端开发的人都知道,判断复选框是否选中是经常做的事情,判断的方法很多,但是开发过程中常常忽略了这些方法的兼容性,而是实现效果就好了.博主之前用户不少方法,经常Google到一些这个不好那个不好的文章,到后面自己都混乱了.今天偶然看到一篇外国的博客,觉得讲解的很不错,打算翻译成中文,并加上了一些自己的见解. 如果你从事web开发并且在你开发的网页中有复选框,你可能需要判断当前该复选框是否选中,进而执行一些条件语句.有很多种方法来判断一个复选框是否选中. 让我们先来看看原生的javascr

JavaScript 拾碎[三] 使用className属性_javascript技巧

A 三位一体的页面 网页的结构层(Structure )由HTML 或XHTML 创建: 网页的表现层(Presentation )由CSS 来创建: 网页的行为层(Behavior )由Javascript 和DOM 所完成: 其实,网页的表现层和行为层总是存在的,即使用户没有去定义.因为Web 浏览器会把自身默认的样式和事件加载到网页的结构层上. B 使用className 属性 Javascript 还可以通过className 属性灵活的更改一个标签元素的CSS 类选择器来实现样式的变化