构造器也叫构造函数,它就是一个普通的函数,只不过它的主要目的是用于和 new
操做符配合来建立特定类型的对象。(关于 new
操做符,个人理解 JavaScript(一)里有进一步描述)javascript
举例:java
var me = new Person('Albert', 'Yu', 32); // Person 便是构造函数
在本例中,me
对象具备特定的类型,可称之为:一个 Person
对象。而 Person
就是它的类型名字。程序员
那么构造函数内部又是如何工做的?segmentfault
function Person(firstName, lastName, age) { this.firstName = firstName; this.lastName = lastName; this.age = age; };
和普通的函数相比,有两个明显的区别,解释以下:浏览器
this
捆绑局部变量:通常性的函数都是直接建立本地变量来保存值,而构造函数使用 this
捆绑局部变量是为了配合 new
操做符。由于 new
操做符会建立一个新对象,而且把新对象绑定在构造函数内部的 this
上,因而被捆绑在 this
上的局部变量事实上就成为新对象的属性了所以,这样的构造函数所建立的对象大体等价于:函数
var me = { firstName: 'Albert', lastName: 'Yu', age: 32 };
那么既然如此,咱们为啥还要写构造函数?this
若是只须要建立少许对象(好比一个),编写构造函数的确没太大意义。可是遇到须要重复建立对象的场合,构造函数显然是 DRY(Don't Repeat Youself)的上佳选择。编码
不只仅是为了减小重复编码的工做量,并且常常会有对于输入参数进行验证并抛出错误的功能设计,也能够借助构造函数来完成。prototype
使用构造函数建立的对象能够很方便的检查它们的类型,好比:设计
var me = new Person('Albert', 'Yu', 32); var you = { firstName: 'Super', lastName: 'Man', age: 18 }; console.log(me instanceof Person); // true console.log(you instanceof Person); // false
这多是使用构造函数最重要的理由了。基于原型继承的 JavaScript 能够很方便的为对象扩充成员属性:
var me = new Person('Albert', 'Yu', 32); me.firstName; // "Albert" me.lastName; // "Yu" me.age; // 32 // 我想要标记全部的 Person 对象都是活着的…… Person.prototype.isAlive = true; me.isAlive; // true // 我还想要输出用户的全名…… me.firstName + ' ' + me.lastName; // "Albert Yu" // 这样太二了吧? Person.prototype.fullName = function() { return [this.firstName, this.lastName].join(' '); }; me.fullName(); // "Albert Yu" // 嗯,文艺多了……
有一点特别须要注意的!
使用构造函数建立对象必定要使用
new
操做符
这是由于(再次强调):真正建立新对象的不是构造函数,而是 new
操做符。构造函数只是充当新对象的模板,它接收 new
建立的对象而后用模板填充这个对象的属性设置。
鉴于此,忘记使用 new
的话是比较危险的。由于没有 new
建立新对象的时候,构造函数内的 this
会被捆绑给全局对象,一般是 window
(浏览器)或者 global
(Node.js),让咱们看看会发生啥事儿吧……
var me = new Person('Albert', 'Yu', 32); me.firstName; // "Albert" var you = Person('Super', 'Man', 18); you.firstName; // undefined... WTF?! this.firstName; // "Super"...Shiiiit! // 上面的 this 是全局对象
那么如何改进构造函数呢?简单。
function Person(firstName, lastName, age) { if (this instanceof Person) { // 想想还有没有其余的判断方式? this.firstName = firstName; this.lastName = lastName; this.age = age; } else { throw new Error('不用 `new` 是不能够的哟~~~'); } }
这个思路就是先判断构造函数接收到的 this
是否是本身的实例,如果则一切好说,若不是则抛出错误强制用户使用 new
操做符。
固然,这个改进虽然可靠了,但仍是不够“聪明”,要是能让构造函数本身判断来自动使用 new
该多好呀!没错,这是更好地方式,不过在这里我就不演示了,仍是由您本身来动手实践一下吧?(提示:考虑一下构造函数的原型对象。若是想不出来的话没关系,咱们之后接着聊)