怎样创建一个对象呢???
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;//返回新对象
}
var person1=createPerson("Nicholas", 29, "Sofrware Engineer");
var person2=createPerson("Grey", 27, "Doctor");
存在问题:虽然解决了创建多个对象的问题,但是我们怎么知道这个对象的类型呢???
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("nike",29,"software engineer");
var person2=new Person("grey",34,"doctor");
alert(person1 instanceof Object);
必须使用new操作符,经历四个步骤:
(1)创建一个新对象
(2)将构造函数的作用域赋给新对象(故this就指向这个对象)
(3)执行构造函数中的代码,为这个新对象添加属性
(4)返回新对象
//person1和person2分别保存着Person的一个不同实例,这两个对象都有一个constructor(构造函数)属性,该属性指向Person
//检测对象类型
alert(person1.constructor==Object);//true
alert(person1.constructor==Person);//true
//但还是推荐使用instanceof
alert(person1 instanceof Person);//true
alert(person1 instanceof Object);//true
注意:person1和person2之所以是Object的实例,是因为所有的对象均继承自Object
存在的问题:其中的每个方法都要在每个实例上重新创建一遍。完成同样的事却干了两遍,有必要吗
function Person(name,age,job) {
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);
};
}
alert(person1.sayName==person2.sayName);//false!!!
虽然能这样解决:
function Person(name,age,job) {
this.name=name;
this.age=age;
this.job=job;
this.sayName=sayName;//共享全局作用域中的sayName()
}
function() sayName{
alert(this.name);
}
var person1=new Person("nike",29,"software engineer");
var person2=new Person("grey",34,"doctor");
alert(person1 instanceof Object);
一个全局函数却只被某个对象调用,这算什么全局。
3.原型模式
(1)每个函数有一个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
(2)当代码读取某个属性时,都会执行一次搜索。首先在对象实例本身开始搜索,如果没有找到,则到原型对象继续搜索。
虽然可以通过对象实例访问保存在原型中的值,但不能通过对象实例重写原型中的值 。如果在实例中添加的属性和原型对象中的同名,那么该属性将会屏蔽在原型中的那个属性。
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();
var person2=new Person();
person1.name="Curry";
alert(person1.name);//Curry--来自实例
alert(person2.name);//Nicholas--来自原型
delete (person1.name);//删除之后就能回复对原型name的连接,因此再调用就返回原型的值
alert(person1,name);//Nicholas--来自原型
//使用hasOwnProperty()方法可以检测一个属性存在于实例中还是存在于对象中
alert(person1.hasOwnProperty("name"));//false
person1.name="Curry";
alert(person1.hasOwnProperty("name"));//true
(3)同时使用hasOwnProperty()和in操作符,就能确定某个属性是存在于原型中还是对象实例中,如下:
alert(person2.hasOwnProperty("name"));//false
alert("name" in person2);//true
//存在于原型
(4)更简单的原型语法
前边有点蛋疼,每添加一个属性和方法就敲一遍Person.prototype。不妨像下面这样:
function Person(){
}
Person.prototype={
name:"Nicholas",
age:29,
job:"Software Engineer",
sayName:function () {
alert(this.name);
}
};
但是此时constructor不再指向Person,如下
var friend=new Person();
alert( friend instanceof Person);//true
alert( friend.constructor == Person);//false
alert( friend.constructor == Object);//true
那么怎样解决呢,如下:
function Person(){
}
Person.prototype={
constructor:Person;//注意这里
name:"Nicholas",
age:29,
job:"Software Engineer",
sayName:function () {
alert(this.name);
}
};
但是这将导致constructor的属性[[Enumerable]]变为true,也就是可枚举,那怎么办呢,如下:
enumerable:false,//修改回来
value:Person
});
(5)
原型对象存在的问题:就是它的共享属性。
原型中的属性被很多实例共享,这种共享对于函数而言是非常合适的。对于那些包含基本值的属性倒也说得过去,毕竟只要在原型中添加同名属性就能将其屏蔽。但是对于引用类型的属性来说呢?
看看下面,你还行单独使用原型模式吗?
function Person(){
}
Person.prototype={
constructor:Person;//注意这里
name:"Nicholas",
age:29,
job:"Software Engineer",
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