JavaScript创建新类(或对象)的方法主要有以下几种:工厂方式、构造函数式、原型方式、混合的构造函数/原型方式、动态原型方法、混合工厂方式。
1.工厂方式:
document.write(this.name+"<br/>");
}
function people(name, age, sex) {
var pTemp = new Object;
pTemp.name = name;
pTemp.age = age;
pTemp.sex = sex;
pTemp.say = say;
return pTemp;
}
var tom = people("Tom", 6, "male");
var marry = people("Marry", 16, "female");
tom.say(); //outputs "Tom"
marry.say(); //outputs "Marry"
//tom inherits the constructor property from Object.prototype;
document.write((marry.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((people.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((marry.prototype == Function.prototype) + "<br/>"); //output "false"
工厂方式的缺点是:
1. 没有类的概念,在创建一个新的类型时,需要新创建一个新的工厂方法,不具有OO的特征;
2.构造函数式
this.name = name;
this.age = age;
this.sex = sex;
this.say = function () {
document.write(this.name + "<br/>");
}
}
var tom = new Person("Tom", 6, "male");
var marry = new Person("Marry", 16, "female");
tom.say(); //outputs "Tom"
marry.say(); //outputs "Marry"
document.write((tom.constructor == Person) + "<br/>"); //output "true"
document.write((tom.prototype == Person.prototype) + "<br/>"); //output "false"
document.write((tom.prototype == marry.prototype) + "<br/>"); //output "true"
//普通对象没有prototype对象,对对普通对象的prototype进行比较,也说明不了任何东西
document.write((marry.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((marry.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((Person.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((Person.prototype == Object.prototype) + "<br/>"); //output "false"
构造函数式的缺点是say这个方法定义在函数类中,这样每个对象都有这么一个函数,是一种资源浪费。
3.原型方式
使用prototype属性可以很好的扩这类的方法和属性。使用方法为: object.prototype.name=value
Person.prototype.name = "smith";
Person.prototype.age = 3;
Person.prototype.sex = "male";
Person.prototype.lessons = new Array("mathematics", "physics", "geography");
Person.prototype.say = function () {
document.write(this.name + "<br/>");
}
}
var tom = new Person();
var marry = new Person();
tom.lessons.push("biology");
document.write(tom.lessons + "<br/>"); //outputs "mathematics,physics,geography,biology"
document.write(marry.lessons + "<br/>"); //outputs "mathematics,physics,geography,biology"
document.write((Person.prototype == Function.prototype)+ "<br/>");// output "false"
document.write((tom.constructor == Person) + "<br/>"); //output "true"
document.write((tom.constructor == new Object().constructor) + "<br/>"); //output "false"
document.write((Person.prototype == tom.prototype) + "<br/>"); //output "false"
document.write((tom.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((marry.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((marry.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((Person.prototype == Object.prototype) + "<br/>"); //output "false"
从以上输出的结果看,原型方式定义的属性,如果属性指向的是对象,而不是函数的时候,对象的共享问题就会显现出来,多个实例的属性共享一个对象,示例中lessons属性是指向Array对象的指针,如果其中一个实例更改了属性,其它的实例也会跟着一起被更改,确切的来说就是所有的实例的该属性共用了一个内存地址。
4.构造函数/原型混合方式(推荐方式)
this.name = name;
this.age = age;
this.sex = sex;
this.lessons = new Array("mathematics", "physics", "geography");
}
Person.prototype.say = function () {
document.write(this.name);
}
var tom = new Person("Tom", 6, "male");
var marry = new Person("Marry", 16, "female");
tom.lessons.push("biology");
document.write(tom.lessons + "<br/>"); //outputs "mathematics,physics,geography,biology"
document.write(marry.lessons + "<br/>"); //outputs "mathematics,physics,geography"
document.write((Person.prototype == Function.prototype)+ "<br/>");// output "false"
document.write((tom.constructor == Person) + "<br/>"); //output "true"
document.write((tom.constructor == new Object().constructor) + "<br/>"); //output "false"
document.write((Person.prototype == tom.prototype) + "<br/>"); //output "false"
document.write((tom.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((marry.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((Person.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((Person.prototype == Object.prototype) + "<br/>"); //output "false"
document.write((marry.prototype == Function.prototype) + "<br/>"); //output "false"
采用构造函数/原型混合创建的方式,避免了属性为对象(非函数)时候的共享问题。
5.动态原型方法(推荐方式)
构造函数/原型混合方式创建虽然是可以的,有不少优点,但相对于标准的面向对象语言,构造函数/原型混合式的写法显然不那么美观,结果上也不是很合理,于是就有了动态原型方法。
this.name = name;
this.age = age;
this.sex = sex;
this.lessons = new Array("mathematics", "physics", "geography");
//以下的Person不可以改成this,原因很简单,自己体会。
if (typeof Person._initialized == "undefined") {
Person.prototype.say = function () {
alert(this.name);
}
Person._initialized = true;
}
}
var tom = new Person("Tom", 6, "male");
var marry = new Person("Marry", 16, "female");
tom.lessons.push("biology");
document.write(tom.lessons + "<br/>"); //outputs "mathematics,physics,geography,biology"
document.write(marry.lessons + "<br/>"); //outputs "mathematics,physics,geography"
document.write((Person.prototype == Function.prototype)+ "<br/>");// output "false"
document.write((tom.constructor == Person) + "<br/>"); //output "true"
document.write((tom.constructor == new Object().constructor) + "<br/>"); //output "false"
document.write((Person.prototype == tom.prototype) + "<br/>"); //output "false"
document.write((tom.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((marry.prototype == new Object().prototype) + "<br/>"); //output "true"
document.write((Person.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((Person.prototype == Object.prototype) + "<br/>"); //output "false"
document.write((marry.prototype == Function.prototype) + "<br/>"); //output "false"
动态原型方法使用一个flag来判断这个函数是否已经被定义,如果被定义了,那么就不用重复定义了,这样看起来就更像Java/C#中类的定义了。
6.混合工厂方式(不推荐使用)
var pTemp=new Object;
pTemp.name="smith";
pTemp.age=2;
pTemp.sex="male";
pTemp.say=function(){
alert(this.name);
}
return pTemp;
}
var tom=new Person();
var marry=new Person();
tom.say(); //smith
marry.say(); //smith
混合工厂式通常是在不能应用动态原型方式时的变通方法。它的目的是创建构造函数,只返回另一种对象的新实例。代码与工厂函数非常相似,区别主要在实例的创建上,工厂方式不需要用new关键字,混合工厂方式使用
new关键字来创建实例,这又让它看起来像是构造函数。由于在Person内部调用了new运算符,程序将忽略第二个new运算符(new Person()),而是直接返回pTemp给var的变量。