虽然用Object构造函数或者字面量创建对象,但是会产生大量重复性代码,而且代码不宜维护。
因为ECMAScript无法创建类,用工厂模式是可以实现创建对象的细节,也可以看成封装对象
function createAnimal(name,age){
var o = new Object();
o.name = name;
o.age = age;
o.bark = function(){
console.info(this.name);
}
return o;
}
var dog1 = createAnimal("Small Yellow",5);
var dog2 = createAnimal("Big Yellow",25);
注意:虽然工厂模式可以创建对象,但是无法解决对象识别问题。
像Object和Array这样原生的构造函数,在运行时(浏览器内核或者Node环境中)出现在执行环境中。此外,可以创建自定义的构造函数,用构造函数的方式重新实现上面的例子
function Animal(name,age){
this.name = name;
this.age = age;
this.bark = function(){
console.info(this.name);
}
}
var dog1 = Animal("Small Yellow",5);
var dog2 = Animal("Big Yellow",25);
这个例子中Animal取代了工厂模式的createAnimal函数,但是这种原生支持的函数会与工厂模式有三种不同之处,如下:
借鉴与OO(面向对象)语言,函数名首字母约定为大写,当然小写不会报错,但不建议这样做。创建对象也是和OO语言保持一致,通过new关键字,那么在使用new来调用构造函数,会有下面四个step:
那么此时,由同个函数生成的对象,他们的类型保持一致。
console.info((dog1.constructor == dog2.constructor) && (dog1.constructor == Animal) && (dog2.constructor == Animal));//true
如果去检测对象类型的话,还是instanceof靠谱些
console.info(dog1 instanceof Object);//true
console.info(dog2 instanceof Object);//true
console.info(dog1 instanceof Animal);//true
console.info(dog2 instanceof Animal);//true
注意:dog1和dog2同时也是Object的子类,这个原理是原型继承,第三章节会详细给出答案
其实构造函数与普通函数没有任何区别,只是调用方式的不同。也就是说任何的函数都可以通过new来调用,但这样做可能会失去业务场景的意义,所以该如何调用,完全取决于您是否想去规划对象的创建和如何组织整个工程的代码。那么具体区别会在下面的例子中一一展现出
//函数通过new来进行调用
var dog = new Animal("Small Yellow",5);
dog.bark();//"Small Yellow"
//当作普通函数调用,就是直接调用
Animal("Small Yellow",5);//添加到window
window.bark(); //"Small Yellow"
//在其它对象的作用域调用
var o = new Object();
Animal.call(o,"Small Yellow",5);//o通过call会持有Animal的运行环境,同时也可以调用apply方法,只是参数不一致
o.sayName(); //"Small Yellow"
讲到这里,不得不提前巩固个知识,所有的函数都是Function的实例。当创建对象时,通过new来调构造函数,每调用一次,Animal内部代码都会执行一次,所以这里的this.bark就不是同一个函数了。因此,不同的实例上同名的函数引用是不同的。
console.info(dog1.bark == dog2.bark);//false
然而遇到这样的问题,我们可以通过把函数写在外部,就解决了这么尴尬的问题,但是不要高兴太早。它任然存在弊端,虽然共享的bark是同一个引用,但是这样在全局作用域上定义方法,这样会造成很多的全局函数,以后很难维护,更别谈封装了。如何解决这种问题,那么下面会讲到原型模式
function Animal(name,age){
this.name = name;
this.age = age;
this.bark = bark;
}
function bark (){//函数声明升级,编译器会先执行声明,所以这里不会报错
console.info(this.name);
}
var dog1 = new Animal("Small Yellow",5);
var dog2 = new Animal("Big Yellow",25);