1、创建一个Object实例
var person = new Object(); person.name = "Nicholas"; person.age = 29; person.sayName = function(){ alert(this.name); }
2、对象字面量
var person = { name: "Nicholas", age: 29, sayName: function(){ alert(this.name); } };
Object构造函数或对象字面量的缺点是,使用同一个接口创建很多对象,会产生大量重复代码。
3、工厂模式
function createPerson(name, age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function(){ alert(this.name); } return o; }; var person1 = createPerson("Nicholas", 29); var person2 = createPerson("Greg", 27);
缺点:没有解决对象识别的问题,即怎样知道一个对象的类型。
4、构造函数模式
function Person(name, age){ this.name = name; this.age = age; this.sayName = function(){ alert(this.name); } }; var person1 = new Person("Nicholas", 29); var person2 = new Person("Greg", 27);
构造函数模式和工厂模式的区别:
(1)没有显式的创建对象;
(2)直接将属性和方法赋给了this对象;
(3)没有return语句;
另外,按照惯例,构造函数的函数名以大写字母开头。
构造函数模式的缺点:每个方法在每个实例上重新创建一遍,不同实例的同名函数是不相等的。
alert(person1.sayName == person2.sayName); //false
创建两个完成同样任务的Function实例没有必要;
一个不太好的解决方法是把sayName()函数转移到构造函数外部。
function Person(name, age){ this.name = name; this.age = age; this.sayName = sayName; }; function sayName(){ alert(this.name); } var person1 = new Person("Nicholas", 29); var person2 = new Person("Greg", 27);
新问题:在全局作用域中定义的函数只能被某个对象调用;如果对象需要定义很多方法,就要定义多个全局函数。
5、原型模式
每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person();
当为对象实例添加一个属性时,这个属性会屏蔽原型对象中保存的同名属性,但不会修改那个属性;
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "Greg" alert(person1.name); //Grey ---来自实例 alert(person2.name); //Nicholas --来自原型
更简单的原型语法
function Person(){ } Person.prototype = { name : "Nicholas", age :29, sayName : function(){ alert(this.name); } };
原型模式的缺点:
省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下有相同的属性值;
所有属性被所有实例共享,通过在实例上添加一个同名属性,可以隐藏原型中的对应属性,但对于包含引用类型的属性,修改也会导致原型中同名属性跟着变。
function Person(){ } Person.prototype = { name : "Nicholas", age :29, friends : ["Shelby","court"], sayName : function(){ alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court,Van" alert(person1.friends === person2.friends); //true
6、组合使用构造函数模式和原型模式
这是最常见方式,构造函数用于定义实例属性,原型模式用于定义方法和共享的属性。
结果,每个实例有自己的一份实例属性的副本,同时又共享对方法的引用,节省内存。
function Person(name, age){ this.name = name; this.age = age; this.friends = ["Shelby","court"]; } Person.prototype = { constructor : Person, sayName : function(){ alert(this.name); } }; var person1 = new Person("Nicholas", 29); var person2 = new Person("Greg", 27); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court" alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName);//true
7、动态原型模式
把所有信息都封装在构造函数中,通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。
function Person(name, age){ //属性 this.name = name; this.age = age; //方法 if(typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; } } var person1 = new Person("Nicholas", 29); person1.sayName();