08 创建对象

创建对象
 一.工厂模式
 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("Nicho",29,"farmer");
 var person2 = createPerson("Mike",19,"farmer");
 person1.sayName();
 person2.sayName();

二.构造函数模式
 function Person(name,age,work){
 	this.name = name;
 	this.age = age;
 	this.work = work;
 	this.sayName = function(){
 		alert(this.name);
 	};
 }
 var person1 = new Person("Nicho",29,"farmer");
 var person2 = new Person("Mike",19,"farmer");
 person1.sayName();
 person2.sayName();
 new Person("Nicho",29,"farmer")的执行步骤
	 1>创建一个新的对象
	 2>将构造函数的作用域赋给新对象
	 3>执行构造函数中的代码
	 4>返回新对象
1.将构造函数当作函数
	任何函数只要通过new操作符来调用,那它就可以作为构造函数,而任何函数,如果不通过new操作符来调用,那它跟普通函数也不会有什么两样。
    //当构造函数使用
    var person =new Person("Nich",26,"worker");
    person.sayName();

    //作为普通函数调用
    Person("Nich",26,"worker");
    windown.sayName();
    //在另一个对象的作用域调用
    var o = new Object();
    Person.call(o,"Nich",26,"worker");
    o.sayName();
 2.构造函数的问题
 使用构造函数的主要问题是:每个方法都要在每个实例上重新创建一次,person1,person2都有sayName方法,但是不是同一个Function实例, 
 alert(person1.sayName == person2.sayName);//false
可以通过下面的方法来解决这个问题
fuction Person(name,age,job){
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = sayName;
} 

funciton sayName(){
	alert(this.name);
}
这样person1和person2对象就共享了在全局作用域中定义的同一个sayName()方法,但是这就导致了两个新的问题,第一,在全局作用域定义的函数实际上只被某个特定的对象使用,这样全局作用域名不副实,第二,如果对象需要很多方法,那么就需要定义很多全局作用域的方法,于是我们的自定义引用类型就没有了封装性。


三,原型模式
每个函数都有一个prototype属性,该属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法,使用原型的好处是可以让所有对象实例共享它所包含的属性和方法,不必在构造函数里定义对象信息,可以将这些信息直接添加到原型对象中。
function Person(){
	
}

Person.prototype.name = "Nicho";
Person.prototype.age = 26;
Person.prototype.job = "farmer";
Person.prototype.sayName = function(){
	alert(this.name);
}

var perons1 = new Person();
alert(person1.name);//"Nicho"

var perons2 = new Person();
alert(person2.name);//"Nicho"

alert(person1.sayName == person2.sayName);//true

  

1.原型
每当代码读取某个对象的属性时,都会执行一次搜索,目标是具有给定名字的属性,搜索首次从对象实例开始,如果在实例中找到了具有给定名字的属性,则返回该属性的值,如果没有找到,则继续搜索指针指向原型对象,在原型对象中查找具有给定名字的属性,如果在原型对象中找到这个属性就返回这个属性的值。

原型最初只包含constructor属性,而这个属性也是共享的,因此可以通过对象实例访问。

虽然可以通过对象实例访问保存在原型中的值,但是不能通过实例去设置原型中的值。

2.原型与in操作
alert("name" in person1);//true;

in操作符会在通过对象能够访问到给定属性时返回true,无论属性存在于实例中还是在原型中。hasOwnProperty()方法仅仅在实例中存在属性时返回true。
同时使用这两个方法可以确定属性是存在于实例中还是存在于原型中。

在使用for-in循环时,返回的是所有能够通过对象访问的可枚举的属性,其中既包括存在于实例中的属性也包括存在于原型中的属性

3.更简单的原型语法
function Person(){
	
}

Person.prototyep ={
	name:"Nicho",
	age :29,
	job:"worker",
	sayName: function(){
		alert(this.name);
	}	
};

注意:这种形式会导致constructor属性不再指向Person了,没创建一个函数,就会同时创建它的prototype对象,这个对象也会自动获得constructor属性,而这种语法,完全重写了prototype对象,因此constructor属性也变成了新的对象的constructor属性,指向Object,

注:可以设置回来 
function Person(){
	
}

Person.prototyep ={
    constructor:Person,
	name:"Nicho",
	age :29,
	job:"worker",
	sayName: function(){
		alert(this.name);
	}	
};

4.原型的动态性
由于在原型中查找值是一个搜索,因此对原型的任何修改都能够立即从实例上反映出来,即使先创建了实例后修改原型也是如此。之所以这样是因为实例与原型之间的松散耦合关系,实例与原型之间连接的仅仅是一个指针,而非一个副本。
但是如果重写整个原型对象那情况就不一样了。调用构造函数时会为实例添加一个指向最初原型的_proto_指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。(实例中的指针仅仅指向原型,而不指向构造函数)
 


5.原生对象的原型
所有原生的引用类型都是采用原型模式来创建的,通过原生对象的原型,不仅可以取得所有默认方法的引用,而且可以定义新的方法,可以像修改自定义原型一样修改原生对象的原型,因此可以随时添加方法。
Strig.prototype.startsWith = function (test){
	return this.indexOf(text) == 0;
}
var msg ="Hello world";
alert(msg.startsWith("Hello"));//true;
这里就为String添加了一个startsWith方法


6.原型模式的问题
首先,省略了构造函数初始化的环节
其次,最大的问题是由其共享的本性所导致的。这种共享对函数和基本类型可以,但是对于引用类型,问题就比较明显。
function Person(){
	
}

Person.prototype ={
	constructor : Person,
	name:"Nicho",
	age:29,
	job:"worker",
	friends:["Mike","Jam"],
	sayName : function(){
		alert(this.name);
	}
};

var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);//Mike Jam Van
alert(person2.friends);//Mike Jam Van

四.组合使用构造函数模式和原型模式
构造函数:定义实例属性
原型模式:定义方法和共享的属性

function Person(name,age ,job){
	this.name = name;
	this.age = age;
	this.job = job;
	this.friends =["Shelby","Court"];
}

Person.prototype ={
	constructor:Person,
	sayName: function(){
		alert(this.name);
	}
}


五.动态原型模式

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);
		};
	}
}


六.稳妥构造函数模式
稳妥对象指的是没有公共属性,而且其方法也不引用this的对象,稳妥对象最适合在一些安全环境(禁止使用new和this)或者在防止数据被其他应用程序改动时使用
function Person(name,age,job){
	var o = new Object();
	o.sayName = function(){
		alert(name);
	};
	return o;
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章