javascript 原型模式的工作原理 到 对象模式的探寻(上)
2015-04-20 16:44 coder_w 阅读(308) 评论(0) 编辑 收藏 举报谈到Javascript面向对象,有几个非常重要的知识点:
- 创建对象的模式
- 原型与原型链
- 继承方式
在Javascript中创建单个对象可以通过很简单的如下两种方式
//Object 实例化
var person = new Object();
person.name = "Nick";
person.sayName = function(){
alert(this.name);
};
//对象字面量
var persion = {
name: "Nick",
sayName: function(){
alert(this.name);
}
};
但是这样的缺点就是
- 创建多个相似对象时,产生大量重复代码
- 对象识别问题,无法知道一个对象的类型
为了解决这些问题,在javascript的发展过程中,各位前辈大牛使用了以下模式:
- 工厂模式
- 构造函数模式
- 原型模式
- 组合模式(构造函数+原型模式)
- 其他模式
/**工厂模式**/
//通过函数工厂来创建
//缺点:没有解决对象识别的问题。
function createPerson(name){
var o = new Object();
o.name = name;
o.sayName = function(){
alert(this.name);
};
return o;
}
var personInstance = createPerson("Nick");
/**构造函数模式**/
//ECMAScript 中的构造函数可以用来创建特殊类型的对象。
//缺点:对象中的方法无法共享,每个方法在每个实例中都重新创建了一遍。
funtion Person(name){
this.name = name;
this.sayName = function(){
alert(this.name);
};
}
var personInstance = new Person("Nick");
/****
在这里js引擎会执行以下步骤:
1. 创建一个对象 O
2. 将构造函数的作用域赋给 O ,即this指向了 O
3. 执行构造函数的代码,即为 O 添加了属性
4. return 新对象
通过构造函数创建的对象,可以通过 constructor属性 或者 instanceof 操作符来识别对象类型。
****/
原型模式
每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象即原型对象,里面包含了该类型所有instance共享的属性和方法。
function Person(){
}
//在这里我们对prototype完全重写了,所以它的constructor默认不会指向Person函数,需要我们重新加上。
Person.prototype = {
constructor: Person,
name : "Nick",
sayName : function(){
alert(this.name);
}
};
var personInstance = new Person();
//这里创建的实例 personInstance 并没有对prototype对象中的任何属性进行copy,而是在自己这边添加了一个指针[prototype]访问prototype对象。
需要注意的是 原型的重写一定要在 对象实例化之前,否则会出错。因为实例的指针指向的原型已经被重写了,所有自定义属性都为空。
原型模式的问题
原型模式在实现创建多个相似对象和识别对象的基础上,还提供了共享的功能,节省了大量内存。但是正是共享导致了一些问题,前面有说过所有实例共享prototype对象中的属性。那么当实例化的 instance 需要独享的属性呢? 当然,我们可以通过在实例中重写来覆盖prototype中的属性来实现。但是对于引用类型来说就有一定的问题了。
function Person(){
}
Person.prototype = {
constructor: Person,
friends: ["s","f"]
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("gg");
console.log(person1.friends);
console.log(person2.friends);
person1.friends = ["1","2"];
console.log(person1.friends);
console.log(person2.friends);
/**
[s,f,gg]
[s,f,gg]
[1,2]
[s,f,gg]
**/
从上面的代码我们可以得知,如果对引用类型的属性进行操作的时候,也必须进行完全重写才能实现各自有各自的属性。否则将直接修改到prototype上的属性。
最终我们通过组合构造函数模式和原型模式得到的模式,是目前使用最广泛的一种自定义类型的方式。
function Person(name,friends){
this.name = "Nick";
this.friends = ["s","f"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
console.log(this.name);
}
}
其他还有 如 动态原型模式、寄生构造函数模式、稳妥构造函数模式等,这里不做一一介绍。
下篇将总结原型链和Javascript继承等。
本文为笔者原创, 转载请标明来源!THX
学无止境~沉下心来!