那么,我为什么说是自定义构造函数模式呢?这是因为,第一部分中,我们使用的Object构造函数是原生构造函数,显然它是���决不了问题的。只有通过创建自定义的构造函数,从而定义自定义对象类型的属性和方法。代码如下:
1 2 3 4 5 6 7 8 9 10
function Person(name,age,school){ this.name=name; this.age=age; this.school=school; this.sayName=function(){ console.log(this.name); }; } var person1=new Person("zzw","21","xjtu"); var person2=new Person("ht","18","tjut");
首先我们验证这种自定义的构造模式是否解决了第一个问题。在上述代码之后追加下面的代码:
1 2
console.log(person1 <strong>instanceof</strong> Person);//true console.log(person1 <strong>instanceof</strong> Object);//true
结构都得到了true,对于Object当然没有问题,因为一切对象都是继承自Object的,而对于Person,我们在创建对象的时候用的是Person构造函数,那么得到person1是Person类型的也就没问题了。
对于第二个问题,答案是显而易见的。很明显,创建大量的对象不会造成代码的重复。于是,自定义构造函数成功解决所有问题。
A 下面我们对比以下自定义构造函数与工厂模式的不同之处:
B 对于构造函数,我们还应当注意:
构造函数的函数名需要大写,用以区分与普通函数。
构造函数也是函数,只是它的作用之一是创建对象。
构造函数在创建新对象时,必须使用new操作符。
创建的两个对象person1和person2的constructor(构造函数)属性都指向用于创建它们的Person构造函数。
C 如何理解构造函数也是函数?
只要证明构造函数也可以像普通函数一样的调用,那么就可以理解构造函数也是函数了。
1 2 3 4 5 6 7 8 9 10
function Person(name,age,school){ this.name=name; this.age=age; this.school=school; this.sayName=function(){ console.log(this.name); }; } <strong>Person("zzw","21","xjtu");</strong> sayName();//zzw
可以看出,我直接使用了Person("zzw","21","xjtu");来像普通函数一样的调用这个构造函数,因为我们把它当作了普通函数,那么函数中的this就不会指向之前所说的对象(这里亦没有对象),而是指向了window。于是,函数一经调用,内部的变量便会放到全局环境中去,同样,对于其中的函数也会在调用之后到全局环境,只是这个内部的函数是函数表达式并未被调用。只有调用即sayName();才能正确输出。
由此,我们证明了构造函数也是函数。
D 那么这种自定义构造函数就没有任何问题吗?
构造函数的问题是在每次创建一个实例时,构造函数的方法都需要再实例上创建一遍。由于在JavaScript中,我们认为所有的函数(方法)都是对象,所以每当创建一个实例对象,都会同时在对象的内部创建一个新的对象(这部分内容同样可以在我的博文《JavaScript函数之美~》中找到)。即我们之前创建的自定义构造函数模式相当于下列代码:
1 2 3 4 5 6
function Person(name,age,school){ this.name=name; this.age=age; this.school=school; this.sayName=new Function("console.log(this.name)"); }
?
1
2
var person1=new Person("zzw","21","xjtu");
var person2=new Person("ht","18","tjut");
即我们在创建person1和person2的时候,同时创建了两个sayName为对象指针的对象,我们可以通过下面这个语句做出判断:
1
console.log(person1.sayName==person2.sayName);//false