javascript的设计模式(三)———— 原型模式

原型模式在js中经常用来创建对象的一种模式,它并不是通过创建类来创建对象,而是通过克隆一个对象来创建对象。在js中没有类的概念,所以js中的面向对象编程方式基本都是使用原型模式实现的。

正文

1.原型对象

function Person(){};

Person.prototype.name = 'Marys';

以上代码声明了一个新函数Preson,每一个新函数里都包含一个prototype属性(这是一个指针),这个属性指向一个对象,这就是 "原型对象",这个对象包含构建该函数的一切属性和方法,其中包含一个constructor属性,该属性指向函数本身。如下图所示
![](http://images2017.cnblogs.com/blog/1105247/201711/1105247-20171129173627565-867232908.png)
var person1 = new Person();

上面的代码中,person1声明为Person的实例,在类语言中就可以说,person1是Person类型,就像数字 1 是Number类型一样。但是js中没有类的概念,那么js是怎么实例化一个对象的呢?
首先,当一个实例对象被声明,该实例便会包含一个[[prototype]]属性(这是也一个指针),在一些浏览器中,他可以用 __proto__ 属性名读取到;然后,这个[[prototype]]属性会指向他的父级的原型对象————prototype,换句话说prototype也是person1的原型对象。关系如下图所示。
![](http://images2017.cnblogs.com/blog/1105247/201711/1105247-20171129173734815-987900628.png)

1.1 原型链

如上图,便是在chrome中打印person1的结果。可以看到,在person1下的 ``__proto__`` 属性展开后是Person的原型,其中也包含一个 ``__proto__`` 属性,这个原型便是指向最根部的Object原型。像这样一层包一层的结构就像是一条链子,把原型一个个连接起来,这就是原型链。当要调用一个对象或一个方法的时候,在创建的实例中找不到的话,js便会沿着这条原型链一直向下找,如果原型链中都找不到,就是undefined了。如下面的代码,打印出来的是Person中定义的``Marys`` ```javascript function Person(){}; Person.prototype.name = 'Marys';

var person1 = new Person();

console.log(person1.name);

</section>

#### 1.2 关于this
<section>this的指向是根据**执行上下文(作用域)**决定的,是一个由构造函数constructor创建的对象,所以this中的属性方法并不存在原型对象中。具体this的变化过程如下:
<ul>
  <li>创建实例对象</li>
  <li>将作用域赋予对象(因此this就指向了新对象)</li>
  <li>执行构造函数中的代码,为实例对象添加属性和方法</li>
</ul>
</section>

### 小结
<section>js中的原型模式实际上就是用来实现继承的一种方式,但是使用原型模式继承的属性和方法都有一个缺点:对于引用类型值得属性是会共用的。也就是说继承的属性如果是引用类型值不是独立的,当改变其中一个实例的属性值时,其他同父级的实例的该属性也是会改变。如下代码,当person1的numbers属性推入一个值,person2中的numbers值也会受影响。但是如果代码是``person1.numbers = [1,2,3]``,person2的numbers属性是不会受到影响的,因为这样相当于person1声明了一个新的属性numbers,这是属于person1自己的属性,用this关键字是能读取到的,当声明属性与``__proto__``中的属性重名的时候,会遮挡原型对象中的属性。
```javascript
function Person(){};
Person.prototype.numbers = [1,2,3,4];

var person1 = new Person();
var person2 = new Person();

person1.numbers.push(5);
console.log(person2.numbers);//[1,2,3,4,5]

person1.numbers = [1,2,3];
console.log(person2.numbers);//[1,2,3,4,5]
console.log(person1);
/*
Person {numbers: Array(3)}
  numbers:(3) [1, 2, 3]
  __proto__:
    numbers:(5) [1, 2, 3, 4, 5]
    constructor:ƒ Person()
    __proto__:Object

*/

posted @ 2017-11-29 17:33  Marys  阅读(155)  评论(0)    收藏  举报