JavaScript创建新类(或对象)的方法主要有以下几种:工厂方式、构造函数式、原型方式、混合的构造函数/原型方式、动态原型方法、混合工厂方式。

1.工厂方式:

function say() {
    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((tom.constructor == new Object().constructor)+"<br/>"); //output "true"
//But constructor property doesn`t belong to tom.
document.write((tom.hasOwnProperty("constructor")) + "<br/>"); //output "false"
// prototype also does not belong to tom.
document.write((tom.hasOwnProperty("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((people.prototype == Function.prototype) + "<br/>"); //output "false"
document.write((marry.prototype == Function.prototype) + "<br/>"); //output "false"

工厂方式的缺点是:

1. 没有类的概念,在创建一个新的类型时,需要新创建一个新的工厂方法,不具有OO的特征;

 

2.构造函数式

function Person(name, age, sex) {
   
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

function Person() {
    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"
//普通对象没有prototype对象,对对普通对象的prototype进行比较,也说明不了任何东西
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 == Function.prototype) + "<br/>"); //output "false"
document.write((Person.prototype == Object.prototype) + "<br/>"); //output "false"

 

从以上输出的结果看,原型方式定义的属性,如果属性指向的是对象,而不是函数的时候,对象的共享问题就会显现出来,多个实例的属性共享一个对象,示例中lessons属性是指向Array对象的指针,如果其中一个实例更改了属性,其它的实例也会跟着一起被更改,确切的来说就是所有的实例的该属性共用了一个内存地址。


4.构造函数/原型混合方式(推荐方式)

function Person(name, age, sex) {
   
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.动态原型方法(推荐方式)

构造函数/原型混合方式创建虽然是可以的,有不少优点,但相对于标准的面向对象语言,构造函数/原型混合式的写法显然不那么美观,结果上也不是很合理,于是就有了动态原型方法。

function Person(name, age, sex) {
   
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.混合工厂方式(不推荐使用)

function Person(){
  
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的变量。