工厂模式
由于在ECMAScript无法创建类,所以用函数的封装以特定接口创建对象
function creatPerson(name,age){
var o = new Object();
o.name = name;
o.age = age;
o.sayname = function(){
alert(this.name);
}
return o;
}
//创建实例
var person = creatPerson("ice",22 );
问题:解决了创建多个相似对象的问题,但是不知道对象的类型
构造函数模式
function Person(naem,age){
this.name = name;
this.age = age;
this.sayname = function(){
alert(this.name);
}
}
//创建实例
var person = Person("ice",22 );
与工厂模式相比较
- 没有显示创建对象 ;
- 将属性和方法赋予给this对象;
- 没有return语句;
经历的步骤
1.创建一个对象;
2.构造函数的作用域赋给新对象;
3.执行构造函数的代码;
4.返回新对象;
alert(person instanceof Object); //ture 继承自Object
alert(person instanceof Person); //ture
//作为普通函数调用
Person("ice",21);//添加到window对象
alert(window.name);//ice
//在另一个对象作用域中调用
var o = new Object();
Person.call(o,"ice",27);
alert(o.name);//ice
问题:不同实例,同名函数不相等,一个实例重新创建一遍函数
原型模式
创建一个函数,就会创建一个prototype属性(一个指向对象的指针)指向函数的原型对象;默认原型对象会获得一个constructor(构造函数)属性(共享的可以通过对象实例访问),包含一个指向prototype所在函数的指针;通过这个构造函数我们可以继续向原型对象添加其他属性和方法。创建自定义构造函数默认只会取到constructor属性,其余方法继承自Object
alrt(Person.prototype.isPrototypeOf(person1));//true
alrt(Object.getPrototypeOf(person1) == Person.prototype);//true
通过isPrototypeOf确定对象之间是否存在这种关系
alrt(Object.getPrototypeOf(person1) == Person.prototype);//true
alrt(Object.getPrototypeOf(person1。name);//"Nicholas"
通过getPrototypeOf返回对象的原型
代码读取对象属性的时候会执行搜索,首先从实例本身开始,如果找到给定的属性,则返回属性的值;没有找到继续搜索指针指向的原型对象找到,返回属性的值。
对象间关系function Person(){
}
Person.prototype.name = "Nicholas";
Person.age = 29;
Person.protype.job = "Software Enginner0"
Person.prototype.sayName = function(){
alert(this.name);
};
var Person1 = new Person();
var Person2 = new Person();
Person1 .name = "ice";
alert(Person1 .name);//ice 来自实例
alert(Person2 .name);//NIcholas 来自原型
alert(Person1.sayname == Person2.sayname);//true
我们为实例添加同名属性会屏蔽原型对象的同名属性,但不会修改。我们可以用delete删除实例属性重新访问原型的属性
alert(Person1.hasOwnProperty("name"));//true
用hasOwnProperty()(Object中继承)方法检测属性在实例中还是在原型中,当在实例中返回true
示例
示例
单独实用"in"操作符无论在实例还是原型,可访问就返回true
function hasprototyProperty(object,name){
return !object.hasOwnProperty(name) && (name in object);
}
hasOwnProperty()方法和in操作符可以同时使用确定属性的位置
for-in所有可以通过对象可访问可枚举的属性,以及屏蔽了原型中不可枚举的属性(有Enumerable标记的属性)都可以返回
IE8之前屏蔽了原型中不可枚举的属性不会出现包括(hasOwnProperty()、propertyIsEnumerable()、toLocalString()、toString()、valueOf())
Object.keys(Person.prototype);//获取 可枚举 属性字符串数组
Object.keys(person);//获取 可枚举 的实例属性
Object.getOwnPropertyNames(Person.prototype);获取 属性 字符串数组
简单的原型语法
function Person(){
}
Person.prototype = {
name : "Nicholas",
age : 29,
job:"Software Engineer",
sayName : function(){
alert(this.name);
}
}
将Person.prototype 设置为等于一个一对象字面量形式创建的新对象,结果相同,但是constructor不在指向Person
重写原型对象之后
此时instanceof还能返回正确结果,constructor已经无法确定对象类型了
var newperson = new Person();
alert(newperson instanceof Object);//true
alert(newperson instanceof Person);//true
alert(newperson.constructor == Object);//true
alert(newperson.constructor == Person);//faluse
必要时可以设置constructor 属性指向适当的值而此时constructor 的Enumerable被设置为true;
function Person(){
}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job:"Software Engineer",
sayName : function(){
alert(this.name);
}
}
//实用与ECMAScript5兼容的浏览器
Object.defineProperty(Person.prototype,"constructor",{
enumerable : false,
value : Preson
})
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
虽然可以随时为原型添加属性和方法并且在实例中反映出来,但是重写原型时,由于调用构造函数时添加的是指向最初原型的prototype指针,而把原型修改为另一个对象,切断了构造函数与最初原型的联系。
实例中指针指向原型,不指向构造函数
重写对象之后
原生引用(Object、Array、String等等)都在构造函数原型上定义了方法
alert(typeof Array.prototype.sort);//function
alert(typeof String.prototype.substring);//function
通过对象的原型不仅可以引用,也可以定义新方法
但是这样容易命名冲突,但是这样容易意外重写原生方法
如果原型中包含引用会出现问题
例如:
function Person(){
}
Person.prototype = {
constructor : Person,
name : "ice",
friend : ["fire","purple"]
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("blue");
alert(person1.friends);//"fire,purple,blue"
alert(person2.friends);//"fire,purple,blue"
alert(person1.friends == person2.friends);//true
组合使用构造函数模式和原型模式(创建自定义类型最常用的方法)
函数构造模式用于定义实例属性,原型模式用于定义方法和共享属性
function Person(name,age){
this.name = name;
this.age = age;
this.friends = ["fire","red"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("ice","21");
var person1 = new Person("blue","22");
person1.friends.push("purple");
alert(person1.friends);//"fire","red","purple"
alert(person2.friends);//"fire","red"
alert(person2.friends == person2.friends);//false
alert(person2.sayName== person2.sayName);//true
动态原型模式
把所有信息都封装在构造函数中,通过在构造函数初始化原型,又保持同时使用构造函数和原型的优点。
(通过检查某个应该存在的方法是否有效决定是否初始化原型)
function Person(name,age){
this.name = name;
this.age = age;
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
var friend = new Person("ice",21);
friend.sayName();
只有在sayName()不存在的情况下(初次调用构造函数)才会添加到原型中,其中只需要检查一个待添加的属性或方法,而且可以通过instanceof操作符确定类型
寄生构造函数模式
创建一个函数,该函数的作用仅仅封装创建对象的代码,然后返回新创的对象
例如创建一个具有额外方法的特殊数组,不能直接修改Array构造函数
function SpecialArray(){
var values = new Array();
values.push.apply(values,arguments);
values.toPipedString = function(){
return this.ioni("|");
}
return values;
}
var colors = new SpecialArray("red","blue","green");
alert(colors.toPipedString());//"red|blue|green"
返回的对象与构造函数或构造函数的原型属性之间没有关系,因此不能依赖instanceof确定对象的类型。
稳妥构造函数模式
适用于安全环境,没有公共属性,禁止使用this和new,防止数据被其他应用程序改动时使用
function Person(name,age){
var o = new Object();
//定义私有
o.sayName = function(){
alert(name);
}
return o;
}
除了调用sayName()方法之外,没有别的可以访问数据成员的方式。也不能向构造函数的原始数据传入新数据适合安全环境,也不能使用instanceof操作符。
网友评论