盘点JavaScript中Function三大用途(1)(3)
JavaScript是通过构造函数来模拟面向对象语言中的类的。例如:
- functionAnimal(sort,character){
- this.sort=sort;
- this.character=character;
- }
以Animal作为构造函数,就可以像下面这样创建一个新对象:
- vardog=newAnimal(”mammal”,”fourlegs”);
创建dog的对象的过程如下:首先,new运算符创建一个空对象({}),然后以这个空对象为调用对象调用函数Animal,为这个空对象添加两个属性sort和character,接着,再将这个空对象的默认constructor属性修改为构造函数的名称(即Animal;空对象创建时默认的constructor属性值是Object),并且将空对象的__proto__属性设置为指向Animal.prototype——这就是所谓的对象初始化。最后,返回初始化完毕的对象。这里将返回的新对象赋值给了变量dog。
- dog.sort;//mammal
- dog.character;//fourlegs
- dog.constructor;//Animal
聪明的读者结合前面介绍的内容,可能会认为使用new运算符调用构造函数创建对象的过程也可以像下面这样来实现:
- vardog={};
- Animal.call(dog,“mammal”,”fourlegs”);
表面上看,这两行代码与vardog=newAnimal(”mammal”,”fourlegs”);是等价的,其实却不是。虽然通过指定函数的执行环境能够部分达到初始化对象的目的,例如空对象dog确实获得了sort和character这两个属性:
- dog.sort;//mammal
- dog.character;//fourlegs
- dog.constructor;//Object——注意,没有修改dog对象默认的constructor属性
但是,最关键的是新创建的dog对象失去了通过Animal.prototype属性继承其他对象的能力。只要与前面采用new运算符调用构造函数创建对象的过程对比一下,就会发现,new运算符在初始化新对象期间,除了为新对象添加显式声明的属性外,还会对新对象进行了一番“暗箱操作”——即将新对象的constructor属性重写为Animal,将新对象的__proto__属性设置为指向Animal.prototype。虽然手工“初始化对象”也可以将dog.constructor重写为Animal,但根据ECMA262规范,对象的__proto__属性对开发人员是只读的,对它的设置只能在通过new运算符创建对象时由JavaScript解释引擎替我们完成。
JavaScript是基于原型继承的,如果不能正确设置对象的__proto__属性,那么就意味着默认的继承机制会失效:
- Animal.prototype.greet=“Hi,goodlucky!”;
- dog.greet;//undefined
事实上,在Firefox中,__proto__属性也是可写的:
- Animal.prototype.greet=“Hi,goodlucky!”;
- dog.__proto__=Animal.prototype;
- dog.greet;//Hi,goodlucky!
但这样做只能在Firefox中行得通。考虑到在兼容多浏览器,必须依赖于new运算符,才能实现基于原型的继承。






