面向对象是JS的重点与难点,但也是走向“掌握JS”的必经之路,有不少的文章或书籍中都对其进行了详细的描述,本没有必要再写这些,可是对于学习来讲,讲给别人听对本身来讲是一种更好的受益方式。我想经过简洁的语言来描述建立对象的方法以及这种方法的优缺点。javascript
本系列内容:java
基本建立模式segmentfault
对象字面量建立对象函数
工厂模式学习
构造函数模式测试
更新时间this
2015年12月6日:建立code
2017年7月8日:精简内容,修正错误对象
建立对象的方法有许多,各有利弊。知其然,作到会用;知其因此然,作到为何用这种方法。才能是真正的掌握。ip
var person = new Object(); person.name = "张三"; person.job = "学生"; person.viewName = function(){ console.log(this.name); }
这是一种最基础的建立对象的方法,使用新建Object
的方法建立对象,而且为其添加属性和方法。
但这种方式有个很差的地方是重复使用了多个person
变量,并且没有任何的封装性可言,因而就出现了更受开发人员喜好的对象字面量形式。
var person = { name: "张三", job: "学生", viewName: function(){ console.log(this.name); } }
这种方式的好处显而易见,就是解决了以前的缺点。
但在实际需求中,须要建立一批相似的对象就有些力不从心了。好比一个小组有六个成员,我要基于每一个组员进行对象实例化,那么我要写6遍以上的代码,而且为其命名为person1~person6。若是能够像流水线通常建立对象就行了:给其提供原料(名字和职务),让其自动建立出组员,使用函数刚好能作到。
var person = function(name, job){ var o = new Object(); o.name = name; o.job = job; o.viewName = function(){ console.log(this.name); } return o; }; var person1 = person("张三","学生"); var person2 = person("李四","学生");
工厂模式利用"建立对象函数"造成流水线的模式,使其流程化,将建立的过程都封装到函数中,对外只暴露每一个对象的特性(经过参数的形式传入)。
具体的实现流程是:在函数内建立了一个对象,将传入的参数做为对象的属性,在最后将其返回。调用函数,函数就会返回拥有特定属性的对象。
工厂模式流程化了建立对象的方法,使其建立对象变得很是简便,但其中出了一个问题,既然person1和person2都使用person函数建立,那么,有什么方法能够证实person1和person2"师出同门"呢?或者用JS的话说是怎样解决对象识别问题,答案是工厂模式不能证实。因而又出现了构造函数模式,用此模式能够肯定person1和person2的关系。
var Person = function(name, job){ this.name = name; this.job = job; this.viewName = function(){ console.log(this.name); } } var person1 = new Person("张三","学生"); var person2 = new Person("李四","学生");
与以前工厂模式的方法对比:
Person变量名首字母大写了
在函数内没有显式的建立及返回对象而使用了this
建立时使用了new
关键字。
Person变量首字母大写是为了区别普通函数,除此以外,别无它用。既然Person的首字母大写只是为了让本身一眼辨别出他是构造函数,在功能上是相同的。那么写成person固然能够,只是这样不推荐(没法区分普通函数与构造函数)。
使用new操做符必须经历四个步骤
建立一个新的对象
将构造函数的做用域赋值给新对象
执行构造函数的代码:为其添加属性和方法
返回新的对象
使用new操做符建立的对象都有一个constructor
属性,该属性指向构造函数。
person1.constructor == Person; // true person1.constructor === person2.constructor;// true console.log(person1.constructor);// 返回构造函数 //function (name, job){ // this.name = name; // this.job = job; // this.viewName = function(){ // console.log(this.name); // } //}
在测试的时候发现一个问题:不使用new关键字建立Object对象为何constructor有值?
再回到原来的需求,小组有两我的,我要建立两个对象,对象的名字和职位可能不同,可是打印每一个人的名字这个方法是同样的。
对于以上几种模式建立的对象。
person1.viewName === person2.viewName;// false
我每次建立一个对象,都建立一次viewName,可是每次都不相等(person1.viewName == person2.viewName返回false)。且若是有一天咱们想把viewName方法改为return返回name值,我要每一个对象都改吗?咱们只要把这个方法作成对象公用的就行了,咱们能够这样:
var Person = function(name, job){ this.name = name; this.job = job; this.viewName = viewName; } function viewName(){ console.log(this.name); } var person1 = new Person("张三","学生"); var person2 = new Person("李四","学生");
可是这又出现了一个问题,没有封装性可言啊,viewName明明是Person的私有方法,可是放在外面,变成了谁均可以调用,原型函数模式解决了这个问题。