1、前言javascript
上一篇介绍了对象的基本简单的概念和对象的数据属性和访问器属性,以及对这两种属性类型的一些操做,接来讲一下与建立对象的模式。html
2、建立对象的方式java
(1)工厂模式编程
这种模式就是经过建立一个Object对象,并将属性和方法保存在Object对象中,将Object对象返回。函数
function createPerson(name, age, job){ var obj = new Object();//经过建立Object来保存传递进来的属性 obj.name = name; obj.age = age; obj.job = job; obj.sayName = function(){ console.log(this.name); } return obj;//返回建立对象 } var person1 = createPerson('jiang', 12, 'software'); person1.sayName();
在上面的例子中,声明一个createPerson()的函数,这个函数接受三个参数,而在函数体中实例化一个Object对象,来接收传递进来的参数,最后将建立的对象返回,这样子就能得到一个person对象。这种模式是一种广为人知的设计者模式,抽象了建立具体对象的过程。这种模式虽然解决了建立多个类似对象的问题,可是并无结局对象识别的问题。而接下来的构造函数就解决了这样的问题this
(二)构造函数模式spa
在大多数的面向对象编程,构造函数主要用来在建立对象时初始化对象, 即为对象成员变量赋初始值,总与new一块儿使用在建立对象的语句中。特别的一个类能够有多个构造函数 ,可根据其参数个数的不一样或参数类型的不一样来区分它们,即构造函数的重载(在javascript中并无重载这个概念)。构造函数模式解决了对象识别的问题,它能够用来建立特定类型的对象。prototype
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ console.log(this.name); } }
这种方式与工厂模式相比设计
1.没有显示的建立对象
2.直接将属性和方法赋给了this对象
3.没有return语句指针
var person = new Person('jiang', 13, 'sfs'); person.sayName();
经过new操做符建立实例,须要经历一下的步骤
-> 建立一个新对象
-> 将构造函数的做用域赋给了新对象,(所以this也就指向了新对象)
-> 执行构造函数中的代码(为该新对象添加属性)
-> 返回新对象
在两个不一样的实例,虽然是两个不一样的实例,但这两个对象都有一个constructor属性指向Person,因此也能够看出,构造函数模式对于工厂模式在于对象识别的区别
var person2 = new Person('zhen', 13, 'sfs'); person2.sayName(); console.log(person.constructor == Person);//true console.log(person2.constructor == Person);//true
所谓构造函数模式,其实也是函数。跟其余函数的区别就在于调用的方式,任何函数经过new操做符来调用的,就是构造函数,若是不是经过new操做符调用的就是普通的函数。
固然构造函数并非完美的,其问题就在于,每一个方法都要在实例上从新建立一次,也就是说两个实例的方法是不相等的。这样使得有些多余。占用内存。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ console.log(this.name); }
将对象内的方法提取到构造函数外面,能够减小同一方法的重复定义。可是这种方式也很差,因而出现了一下的原型模式
(三)原型模式
prototype 每一个函数都有的属性,是指向一个对象的指针,包含了能够有特定类型的全部实例共享的属性和方法,换句话说,prototype就是经过调用函数而建立的对象实例的原型对象,其好处就是可让全部对象实例共享包含的属性和方法。
function Person(){} Person.prototype.name = 'jiang'; Person.prototype.age = 15; Person.prototype.job = 'sf'; Person.prototype.sayName = function(){ console.log(this.name); }; var person = new Person(); person.sayName();
首先声明一个空的函数。将对象的方法和属性都放到prototype属性上。这样使用构造函数的方式建立新对象,新对象也会拥有相同的属性和方法。那么有人就会问了,Person函数中分明是空的,那么为什么建立出来的新对象会有这些属性和方法呢?那么首先就要了解一下什么是原型对象。
(a)原型对象
当咱们建立一个新的函数的同时,与之同时prototype会做为新函数的属性被建立出来,而这个属性呢就是一个指针,会指向新函数的原型对象。而在默认状况下原型对象就会得到一个constructor(构造函数)属性,这个属性又指向了咱们建立的新函数。上面的例子Person.prototype.constructor,就是咱们的Person上面例子用一张图片来讲明一下
Person函数中的prototype属性指向了Person.prototype,同时Person.prototype.constructor又指向了Person函数,当咱们实例化person1对象时,这个对象内部也含有一个prototype指针指向了Person.prototype对象。
在上面的例子中。Person对象的全部属性和方法都赋值给了原型对象,也就是在Person对象并无这些属性,因此实例出来的person1对象中也没有这些属性,只有一个指向原型对象的指针,那么实例化出来的对象不是至关与没有东西。可是若是person1.name又是有数据的。这就涉及到了原型模式的搜索机制
(b)原型模式的搜索机制
原型对象的遍历方式,先从实例自己开始,搜索给定的属性的名称,全部实例中是否有这个属性的值,若是有就返回,若是没有就全部原型中是否存在,存在就返回这个属性的值
原型中会存在屏蔽原理,当咱们为实例添加一个属性是,这个属性就会屏蔽原型中同名的属性,也就是当咱们访问实例中的某个属性时,若是该属性存在,就会返回该属性不会在搜索原型中的同名属性属性,若是使用delete操做符删除实例中的属性时,就会回复对原型中同名属性的链接。
(c)原型模式的简写方式
Person.prototype = { name: 'jiang', age: 14, job: 'sf', sayName: function(){ console.log(this.name); } }
以上重写后,起原型的constructor再也不指向Person,而是指向了Object,由于这样设置的话就至关与一个以字面量形式建立的新对象,在本质上已经彻底重写了默认的prototype对象,所以prototype的constructor再也不指向原来的Person。除非本身指定constructor:Person。
//或者重设构造函数 Object.defineProperty(Person.prototype, 'constructor', { enumerable:false, value: Person });
这样的写法,就能够将原型对象中的构造函数属性从新指向了Person。
原型模式虽然解决了工厂模式和构造函数模式的缺点,当仍然不是完美的模式。此次先吹水吹到这了