创建单个对象的方法:
直接量
var blog = { author: "MirrorAvatar", year: 2015 };
关键字new
var blog = new Object(); blog.author = "MirrorAvatar"; blog.year = 2015;
以上方法的缺点:使用同一个接口创建很多对象,会产生大量的重复代码。为了可复用性,才有了下面七种用于批量创建对象的七种模式。
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
};
return o;
}
var person1 = createPerson("MirrorAvatar", "3", "coder");
var person2 = createPerson("Cindy", "4", "master");
console.log(person1); //Object {name: "MirrorAvatar", age: "3", job: "coder", sayName: function}
console.log(person2); //Object {name: "Cindy", age: "4", job: "master", sayName: function}
?代码特点:
缺点:无法识别一个对象的类型。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
}
}
var person1 = new Person("MirrorAvatar", "3", "coder");
var person2 = new Person("Cindy", "4", "MLer");
console.log(person1); //Person {name: "MirrorAvatar", age: "3", job: "coder", sayName: function}
console.log(person2); //Person {name: "Cindy", age: "4", job: "MLer", sayName: function}
?
person1和person2都有一个constructor属性,都指向了Person。
person1.constructor === Person; //true
person2.constructor === Person; //true
person1.constructor === person2.constructor; //true
?
对象的constructor属性最初是用来标识对象类型的,但是用instanceof操作符更可靠。
person1.instanceof Object; //true
person1.instanceof Person; //true
person2.instanceof Object; //true
person2.instanceof Person; //true
?
优点:创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型;而这正是构造函数模式胜过工厂模式的地方。
缺点:构造函数里的每个方法都要在实例上重新创造一遍,不可复用。如果像下面的代码那样讲方法抽象出来,那么如果对象需要定义很多方法,那么就要定义很多全局函数,毫无封装性。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName() {
alert(this.name);
}
?
构造函数和其他函数的区别,在于调用它们的方式不同。
任何函数,只要通过new操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过new操作符来调用,那它跟普通函数也不会有什么两样。
//当做构造函数用
var person = new Person("Michael282694", 5, "MLer");
person.sayName(); //Michael282694
//当做普通函数用,添加到宿主对象window,this指向Global对象
Person("Michael", 6, "MLer");
window.age; //6
window.sayName(); //Michael
//在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Cindy282694", 7, "MLer");
o.sayName(); // Cindy282694
?
//原型模式一
function Person() {
}
Person.prototype.name = "MirrorAvatar";
Person.prototype.age = 4;
Person.prototype.job = "coder";
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person();
person1.sayName(); //MirrorAvatar
var person2 = new Person();
person2.sayName(); //MirrorAvatar
?
//原型模式二,减少模式一不必要的输入
function Person() {
}
Person.prototype = {
name: "MirrorAvatar",
age: 4,
job: "coder",
sayName: function() {
alert(this.name);
}
};
Person.prototype.constructor === Person; //false
Person.prototype.constructor === Object; //true
person1 instanceof Person; //true
person2 instanceof Object; //true
?
//原型模式三,针对上述3的缺陷
function Person() {
}
Person.prototype = {
constructor: Person,
name: "MirrorAvatar",
age: 3,
job: "coder",
sayName: function() {
alert(this.name);
}
};
//以上重设了constructor指向,导致constructor的[[Enumerable]]特性设置成true,默认是false的。
//重设构造函数,只适用于ECMAScript 5兼容的浏览器
Object.defineProperty(Person.prototype, "constructor",{
enumerable: false,
value: Person
});
?
重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系;它们引用的仍然是最初的原型。
function Person() {
}
var friend = new Person();
Person.prototype = {
constructor: Person,
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName: function() {
alert(this.name);
}
};
friend.sayName(); //Error
?
重写原型对象前:
重写原型对象后:
function Person() {
}
Person.prototype = {
constructor: Person,
name: "MirrorAvatar",
age: 2,
job: "coder",
friends: ["Cindy","Cindy282694"],
sayName: function() {
alert(this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Michael");
console.log(person1.friends); //"Cindy,Cindy282694,Michael"
console.log(person2.friends); //"Cindy,Cindy282694,Michael"
person1.friends === person2.friends; //true
?
创建自定义类型的最常见方式。既复用方法,又共享共同属性。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Cindy", "Michael"];
}
Person.prototype = {
constructor: Person,
sayName: function() {
alert(this.name);
}
}
var person1 = new Person("Cindy282694", 4, "coder");
var person2 = new Person("MirrorAvatar", 3, "coder");
person1.friends.push("Michael282694");
console.log(person1.friends); //"Cindy,Michael,Michael282694"
console.log(person2.friends); //"Cindy,Michael"
person1.friends === person2.friends; //false
person1.sayName === person2.sayName; //true
?
这种构造函数与原型混成的模式,是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。
封装性比较好
function Person(name, age, job) {
//属性
this.name = name;
this.age = age;
this.job = job;
//方法
if(typeof this.sayName != "function") {
Person.prototype.sayName = function() {
alert(this.name);
}
}
}
var friend = new Person("MirrorAvatar", 3, "coder");
friend.sayName(); //MirrorAvatar
?
这个模式其实和第一个模式“工厂模式”一样,不信你看。
通常,在前述的几种模式都不适用的情况下,可以使用寄生(parasitic)构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。
function Person(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
}
return o;
}
var friend = new Person("MirrorAvatar", 2, "coder");
friend.sayName();
?
特点:
首先,返回的对象与构造函数或者与构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。
所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象。稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用this和new),或者在防止数据被其他应用程序(如Mashup程序)改动时使用。
稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的实例方法不引用this;二是不使用new操作符调用构造函数。
function Person(name, age, job) {
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function() {
alert(name);
}
//返回对象
return o;
}
var friend = Person("MirrorAvatar", 3, "coder");
friend.sayName(); //"MirrorAvatar"
?
特点: 1. 没有new操作符 2. 没有this
原文:http://mirroravatar.iteye.com/blog/2190842