上一章我们谈了构造函数,他的唯一特点就是比较了地址不相同,因为大家知道引用类型是比较的引用。我们来谈谈 原型。
我们每创建一个函数都有一个原型 (prototype) 属性,这个属性是一个对象,他的特点是 共享 。也就是说不用在构造函数中定义对象实例,而是直接将这些添加到原型当中。
- function Create() {} //声明一个构造函数
- Create.prototype.a = 'abc'; //在原型中添加属性
- Create.prototype.b = 10;
- Create.prototype.c = function() { //在原型中添加方法
- return this.a + this.b;
- };
- var create = new Create();
- alert(create.c()); //返回abc10
我们这次再来比较一下原型中方法的地址是否一致:
- var create = new Create();
- var create1 = new Create();
- alert(create.c == create1.c); //true
是不是还没明白?我们用一张图来告诉大家:
这个__proto__就相当于指针,指向了原型对象的 constructor, 而 constructor 就相当于将构造函数对象和原型对象相关联。
那么我们要用构造函数对象去给重写 属性或者方法 会怎么样呢?
- var create = new Create();
- create.a = 'EFD';
- alert(create.a); //返回EFD
真的将原型对象里面的 a 给覆盖了么?并没有:
- var create1 = new Create();
- alert(create.a); //返回abc
原型模式的执行过程:
1. 先去查找构造函数里面的属性和方法 ,如果有就立即返回。
2. 如果构造函数实例里面没有,就去原型里面查找,如果有就立即返回。
因为我们在构造函数添加了属性,所以它会自动去查找,构造函数里面的属性也就立即返回了!
原型的字面量
在原型中,我们也可以使用字面量的方式去创建,可以让属性和方法体现出更好的封装效果。
- function Create(a, b) {}; //声明一个构造函数
- Create.prototype = { //字面量方式
- a: 'abc',
- b: 10,
- c: function() {
- return this.a + this.b;
- }
- };
不知道大家有没有发现,我们用字面量的方式是这样的:Create.prototype ={};
大家都知道,用一个 {} 就等同于 new Create(); 这样,我们就相当于新声明的一个对象,我们原型对象里面的 constructor 还会指向 Create 么?
- var create = new Create();
- alert(create.constructor == Create); //false
- alert(create.constructor == Object); //true
(我们来解释一下为什么用 create.constructor, 因为我们打印 constructor 就会将整个构造函数打印出来,因为上面讲过它是将构造函数对象和原型对象相关联的属性。)
通过上面的例子可以看出,它已经指向了新的实例对象。
constructor 的巧妙用法:
我们可以使用 constructor 来强制指回原来的实例对象:
- function Create(a, b) {};
- Create.prototype = {
- constructor: Create,
- a: 'abc',
- b: 10,
- c: function() {
- return this.a + this.b;
- }
- };
原型对象的重写问题:
大家都知道,构造函数的属性和方法重写是无伤大雅的,但是原型对象中可以重写么?
- function Create(a, b) {};
- Create.prototype = {
- constructor: Create,
- a: 'abc',
- b: 10,
- c: function() {
- return this.a + this.b;
- }
- };
- Create.prototype = {
- a: 'EFD',
- };
- var create = new Create();
- alert(create.c()); //create.c is not a function
不难看出,我们重写了原型会将之前的原型指向切断!!!
原型模式的缺点:
其实它的缺点也是它优点: 共享 。
我们在字面量里面给原型对象添加一个数组就很容易的看出来了:
- function Create(a, b) {};
- Create.prototype = {
- constructor: Create,
- a: 'abc',
- b: 10,
- c: [第一个, 第二个, 第三个],
- d: function() {
- return this.a + this.b + this.c;
- }
- };
- var create = new Create();
- create.c.push('第四个');
- alert(create.run()); //返回abc10第一个第二个第三个第四个
我们看得出这时候 push 添加已经生效了,在数组的末尾添加了 "第四个"
我们再来实例一个对象就能看得出他的共享问题了:
- var create1 = new Create();
- alert(create1.run()); //返回abc10第一个第二个第三个第四个
这就是共享问题。下面新实例化一个对象也会将上面添加的字符串给共享到这里来。
这一章就到这里。
Brian Lee
来源: http://www.open-open.com/lib/view/open1480382998564.html