每次当觉得自己对原型这里有点了解的时候就会出来一道题打脸,,,so决定再重新看一遍,
关于面向对象的几种模式及其优缺点
原始情况
var box = new Object(); //创建一个Object对象
box.name = 'Lee'; //创建属性
box.run = function () { //创建一个run()方法
return this.name + this.age;
};
缺点:创建类似的对象的话就要再写一遍代码,复用率不好
工厂模式
用来解决声明多个类似对象问题,提高代码复用率,大概就是写一个模板,用的时候传入具体值就可以了,以实现上面的功能为例
function createObject(name, age) {
var obj = new Object();
obj.name = name;
obj.age=age;
obj.run = function () {
return this.name + this.age;
};
return obj;
}
// 调用
var box1 = createObject('rose', 100);//第一个实例
var box2 = createObject('Jack', 200);//第二个实例
alert(box1.run());
alert(box2.run()); //保持独立
缺点:这样写是不用重复的写好多代码,但是有一个问题。先假设还有一个createObject2,这个函数也返回一个对象,用他实例化一个box3,这时你完全搞不清楚box1、2、3到底谁是谁的对象,
所以就有构造函数这个模式
构造函数模式
function Box(name, age) { //构造函数模式
this.name = name;
this.age=age;
this.run = function () {
return this.name + this.age;
};
}
var box1 = new Box('Lee', 100);
//很清晰的看到他是Box实例化来的
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box);
优点:解决了重写重复代码的问题,解决了找自己对象的问题。可以看到他与前面所说的创建对象的方法的不同之处:
- 他没有创建对象(new Object());
- 直接将属性和方法赋值给当前对象(this);
- 也没有返回一个对象。
没有上面这些他是怎么创建一个对象的呢: - new 构造函数(),后台自动执行new Object();
- 实例化后构造函数的作用域给了实例,即this指向了实例;
- 执行构造函数内的代码;
- 后台自动返回新对象。
构造函数的规范:
1. 为了区分普通函数,首字母要大写,但是不强制,函数名和new的时候名字要相同
2. 通过new操作符实例化一个对象
上面的代码,虽然box1、box2都是同一个构造函数创建的,但是他们的方法是不相等的,每次实例化的时候相当于创建一个Function(new Function()),这样其实是没有必要的,有一个解决方法是把通用的方法写成全局的,这样每次实例化完属性后,再直接全局调用需要的方法,但是这样就没有封装性可言了,下面说的原型模式可以解决这个问题。
原型模式
原型 实现所有对象的实例共享对象的属性和方法,创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,简单粗暴的来说就是它包含对象的所有实例需要共享的属性和方法。
function Box() {} //声明一个构造函数
Box.prototype.name = 'Lee'; //在原型里添加属性
Box.prototype.run = function () {//在原型里添加方法
return this.name + this.age;
};
// 实例化
var box1 = new Box();
var box2 = new Box();
alert(box1.run == box2.run);//true,每个实例对对象原型的方法的调用其实是引用,不会每实例化一次就创建一次
感觉原型里面比较混乱的就是下面这些内容了,先说一下有哪些然后再分别记录
- prototype:函数属性,指向函数的原型对象;
- 原型对象的constructor:包含一个指向prototype属性所在函数的指针,拿前面的例子来说Box.prototype.constructor = Box;
- 内部属性[[Prototype]]__proto___:这是新实例包含的一个指针,指向构造函数的原型对象。挺纠结的,这两个叫法不是很兼容,所以只要记住有这么一个指针存在就好了;
- isPrototypeOf:可以通过isPrototypeOf方法确定实例与原型对象是否存在上面说的那种关系Box.prototype.isPrototypeOf(box1),返回true;
- Object.getPrototypeOf()[ES5] : 取得一个对象的原型对象。这个方法返回[[Prototype]]的值Object.getPrototypeOf(box1) == Box.prototype;
- ;
- ;