对象是js编程中使用最广泛的数据类型,在《javascript高级程序设计》中详细讲解了对象的相关知识,以下是一些总结。
一.创建一个对象的基本方法
1.Object构造函数
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer"
person.sayName = function () {
alert(this.name);
}
2.函数字面量
var person = {
name : "Nicholas",
age : 29,
job : "Software Engineer"
sayName = function () {
alert(this.name)
}
}
使用以上两种方法可以创建对象,但是也存在一些缺陷,以上两种方法使用同一个接口创建很多对象,会产生很多重复的代码。
二.其他方法
1.工厂模式
工厂模式抽象了创建具体对象的过程 一种函数 用函数封装以特定接口创建对象的细节,例如:
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;
}
然而工厂模式没有解决对象识别,即确定一个对象的类型问题。
2.构造函数模式
使用构造函数模式重写以上例子:
function Person (name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
alert(this.name)
};
}
var person1 = new Person("Nicholas",29,"Software Engineer");
var person2 = new Person("Greg",27,"Doctor");
过程是:
O创建一个新对象。
O将构造函数的作用于赋给新对象(所以this指向新对象)。
O执行构造函数的代码(为新对象添加属性)。
O返回新对象。
构造函数模式的缺点是每个实例需要重写创建一遍。
3.原型模式
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途就是包含可以由特定类型的所有实例共享的属性和方法。
字面理解就是prototype就是通过调用构造函数而创建的那个对象的原型对象。
使用原型对象的好处就是让所有对象实例共享它所包含的属性和方法,换句话说不必再构造函数中定位对象的实例信息,而是可以将这些信息直接添加到原型对象中,例子:
function Person () {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer"
person.prototype.sayName = function () {
alert(this.name);
}
var person1 = new Person();
person1.sayName()
var person2 = new Person();
person2.sayName()
alert(person1.sayName == person2.sayName)//true
原型对象:无论什么时候创建一个新函数,就会根据一组特定的规则创建一个prototype属性,这个属性指向函数的原型对象(个人注释:obj.prototype就是原型属性)
在这里 person1 person2 与构造函数 Person没什么关系,即这两个属性不包含属性和方法,但是可以调用person1.sayName,这是通过查找对象属性来实现的。
每当代码读取到某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性 搜索首先从对象实例本身开始,如果找到,则返回属性值,如果没找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定属性的名字,如果找到则返回该属性的值。
对于上述例子来说,就是调用person1.sayName()时,先搜索person内是否有sayName属性 没有则继续搜索person1的原型里有没有sayName属性。有则返回。注意:constructor也是属性也是共享的。
虽然可以访问属性,但是不能修改属性,只能进行覆盖。
function Person () {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer"
person.prototype.sayName = function () {
alert(this.name);
}
var person1 = new Persons();
var person2 = new Persons();
person2.name = "Grag"
console.log(person1.name);//Nicholas 来自原型
console.log(person2.name);//Grag 来自实例
//当使用delete的时候
delete person2.name;
console.log(person2.name);//Nicholas 来自原型
使用 hasOwnProperty()方法可以检测一个属性是存在与原型中还是存在于实例中。
原型模式最大的缺点是共享,例如:
function Person () {
}
Person.prototype = {
constructor : "Person",
name : "Nicholas",
age : 29,
job : "Software Engineer",
friends : ["Bob","Mike"],
sayName : function () {
alert(this.name)
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van")
console.log(person2.friends);//"Bob","Mike","Van"
console.log(person1.friends === person2.friends)//true
4组合使用构造函数模式和原型模式。
使用构造模式用于定义实例属性,使用原型模式定义方法和共享属性,这样每个实例都会有自己的一份实例属性副本,但同时又共享着对方法的引用,最大限度地节省了内存。这种模式还支持向构造函数传递参数,重写例子后:
function Person (name,age,job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Bob","Mike"]
}
Person.prototype = {
constructor : Person;
sayName : function () {
alert(this.name)
}
}
var person1 = new Person("Nicholas",29,"Software Engineer");
var person2 = new Person("Greg",27,"Doctor");
person1.friends.push("Van");
console.log(person1.friends);//"Bob","Mike","Van"
console.log(person2.friends);//"Bob","Mike"
console.log(person1.friends === person2.friends)//false
console.log(person1.sayName === person2.sayName)//true
这种模式是ECMAscript中使用最广泛、认同度最高的模式。
当然还有其他模式:动态原型模式、寄生构造函数模式、稳妥构造函数模式等~