什么是构造函数?

构造函数 是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 特别的一个类可以有多个构造函数 可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载 ---引自百度百科

在JavaScript中是没有类的,但是我们有构造函数(是不是很怪),很深的东西我也说不来,直接上代码:

```javascript
//工厂模式
function createCat(name){
var o = {};
o.name = name;
o.cry = function(){
console.log(this.name + " : " + "喵喵喵!");
};
return o;
}
var tom = createCat("tom");
tom.cry();
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
}
var jerry = new Mouse("jerry",5);
jerry.cry();
```

以上实例代码分别是工厂模式和构造函数模式,构造函数模式相比于工厂模式,存在一下几个不同之处:

  • 没有显式的创建对象
  • 直接将属性和方法赋给了this对象
  • 没有return语句

实际上,调用构造函数会经历以下几个步骤:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(因此this就指向了新对象)
  • 执行构造函数中的代码(给这个新对象添加方法和属性)
  • 返回这个新对象

我们要注意以上是JS隐式执行的,我们也可以显式的来,上代码:

```javascript
function Mouse(name){
var o = {};
var that = o;
that.name = name;
that.cry = function(){
console.log(that.name);
}
return that;
}
var jerry = new Mouse("jerry",5);
jerry.cry();
```

在隐式的构造函数中,我们要注意一个问题,return是隐式返回this的,但是我们可以手动return ,可是这有可能会return我们意料之外的结果:

```javascript
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
return "WeiRan"
}
Mouse.prototype.a = {};
var jerry = new Mouse("jerry",5);
jerry.cry(); // jerry : 吱吱吱!
```

以上代码,虽然我们手动返回的是字符串但是真正返回的还是this,其实JS会判断我们返回的是不是对象,数组,function 如果不是这还是会返回this(即便是undefined,null,空)

对象识别

虽然工厂模式解决了多个相似对象的问题,却没有解决对象识别的问题,但是构造函数模式却解决了这个问题,在构造函数模式中,每一个实例都有一个属性constructor,该属性指向他么的构造函数,可以这样来检测对象的类型

```javascript
console.log(jerry.constructor == Mouse); //true
```

但是这样做其实是不严谨的,可能会出现以下的问题:

```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
return;
}
var jerry = new Mouse("jerry",5);
Mouse.prototype.constructor = {};
console.log(jerry.constructor);//Object {}
```

这段代码说明,jerry的constructor其实指向的是Mouse的prototype的constructor,这样很不严谨,故我们可以采用instanceof来检测对象类型

```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
return;
}
var jerry = new Mouse("jerry",5);
Mouse.prototype.constructor = {};
console.log(jerry.constructor == Mouse);//false
console.log(jerry instanceof Mouse); //true
```

将构造函数当作函数

构造函数与其他函数的唯一不同,就在于调用他们的方式不同。但是构造函数也是函数,故我们可以以普通函数的方式执行构造函数,任何函数也可以通过new来调用(慎用),下面我列举了几个调用方式:

```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
}
//当作构造函数使用
var m1 = new Mouse("m1");
m1.cry(); //m1 : 吱吱吱!
//当作普通函数使用
Mouse("m2");
window.cry(); //m2 : 吱吱吱!
//在其他作用域调用
var obj = {};
Mouse.call(obj,"m3");
obj.cry(); //m3 : 吱吱吱!
```

第一种是用最常见的调用构造函数的方式,第二种,所有的属性和方法都被添加到Global对象上去了(在浏览器中就是window),第三种,我们制定了作用域,所以obj就有了所有的属性和方法

构造函数的问题

构造函数虽然好用,但是他也有缺点,使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍,即每个实例的方法都是不同的(虽然代码一样),上代码:

```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
}
var m1 = new Mouse();
var m2 = new Mouse();
console.log(m1.cry == m2.cry); //false
```

然而,创建两个完成相同功能的Function实例的确没有必要,而且有this对象在,根本没有必要在执行代码前就把函数绑定到特定的对象上去,以此我们可以用下面的代码来解决这个问题:

```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = cry;
}
function cry(){
alert(this.name);
}
```

在上面的例子中我们把cry方法定义在了构造函数外部,这样大大避免了资源的浪费,我们创建的实例调用的都是同一个cry方法,但是新问题又来了,如果这种方法很多,我们就不得不在全局定义很多函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了,好在这些我们可以用原型模式来解决(下一篇,呵呵)

后记 :

关于这篇,我开始是想写的非常全,但是奈何经验不足,大体框架也是按照书上的逻辑,最大的收获就是真的用心去看书了。如果在文中发现错误,请指正,共同进步

初涉JavaScript模式 (4) : 构造函数的更多相关文章

  1. 初涉JavaScript模式系列 阶段总结及规划

    总结 不知不觉写初涉JavaScript模式系列已经半个月了,没想到把一个个小点进行放大,竟然可以发现这么多东西. 期间生怕对JS的理解不到位而误导各位,读了很多书(个人感觉JS是最难的oo语言),也 ...

  2. 初涉JavaScript模式 (7) : 原型模式 【三】

    组合使用构造函数模式和原型模式 上篇,我们提到了原型模式的缺点,就是每个实例不能拥有自己的属性,因为纯原型模式所有的属性都是公开给每个实例的,故我们可以组合使用构造函数模式和原型模式.构造函数用来定义 ...

  3. 初涉JavaScript模式 (6) : 原型模式 【二】

    原型与in操作符 有两种方式使用in操作符:单独使用和在for-in循环中使用. 在单独使用时,in操作符会遍历实例公开(可枚举)的属性,如果找到该指定属性则返回true,无论该指定属性是存在与实例中 ...

  4. 初涉JavaScript模式 (12) : 沙箱模式

    引子 上一篇说了模块模式,而对于其中的命名空间模式其实也是有着一些问题,比如每添加一个模块或则深入叠加都会导致长命名,并且对于多个库的不同版本同时运行,一不小心就会污染全局标识,而这两天也发现了JSe ...

  5. 初涉JavaScript模式 (11) : 模块模式

    引子 这篇算是对第9篇中内容的发散和补充,当时我只是把模块模式中的一些内容简单的归为函数篇中去,在北川的提醒下,我才发觉这是非常不严谨的,于是我把这些内容拎出来,这就是这篇的由来. 什么是模块模式 在 ...

  6. 初涉JavaScript模式 (5) : 原型模式 【一】

    什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...

  7. 初涉JavaScript模式 (2) : 基本技巧

    尽量少用全局变量 大量使用全局变量会导致的后果 全局变量创建以后会在整个JavaScript应用和Web页面中共享.所有的全局变量都存在于一个全局命名空间内,很容易发生冲突 不知不觉创建了全局变量 其 ...

  8. 初涉JavaScript模式 (3) : 字面量

    什么是字面量? 在编程语言中,字面量是一种表示值的记法.例如,"Hello, World!" 在许多语言中都表示一个字符串字面量(string literal ),JavaScri ...

  9. 初涉JavaScript模式 (13) : 代码复用 【上】

    引子 博客断了一段时间,不是不写,一是没时间,二是觉得自己沉淀不够,经过一段时间的学习和实战,今天来总结下一个老生常谈的东西: 代码复用. 为何复用 JS门槛低,故很多人以为写几个特效就会JS,其实真 ...

随机推荐

  1. 组合数学(Pólya计数原理):UvaOJ 10601 Cubes

    Cubes You are given 12 rods of equal length. Each of them is colored in certain color. Your task is ...

  2. 数据结构(主席树):COGS 2213. K个串

    2213. K个串 ★★★★   输入文件:bzoj_4504.in   输出文件:bzoj_4504.out   简单对比时间限制:20 s   内存限制:512 MB [题目描述] 兔子们在玩k个 ...

  3. 动态规划(模型转换):uvaoj 1625 Color Length

    [PDF Link]题目点这里 这道题一眼就是动态规划,然而貌似并不好做. 如果不转换模型,状态是难以处理的. 巧妙地转化:不直接求一种字母头尾距离,而是拆开放到状态中. #include <i ...

  4. 动态规划(方案还原):SGU 104 Little shop of flowers

    花店橱窗布置问题 时间限制:3000 ms 问题描述(Problem)    假设你想以最美观的方式布置花店的橱窗,你有F束花,每束花的品种都不一样,同时,你至少有同样数量的花瓶,被按顺序摆成一行.花 ...

  5. 调用系统api修改系统时间

    一:截图 二:代码 using System; using System.Collections.Generic; using System.ComponentModel; using System. ...

  6. Insertion Sort List —— LeetCode

    Sort a linked list using insertion sort. 题目大意:将一个单链表使用插入排序的方式排序. 解题思路:先新建一个头指针,然后重新构建一下这个单链表,每次从头找到第 ...

  7. Happy Number——LeetCode

    Write an algorithm to determine if a number is "happy". A happy number is a number defined ...

  8. CTE Recursion Performance

    CTE全名是Common Table Expression,语法基础请参考MSDN文档:https://msdn.microsoft.com/zh-cn/library/ms175972.aspx. ...

  9. 进了ACM之后,我才清楚了自己的方向!!!

    2015年8月29日,从郴州比完赛后,状况并没有想象中的乐观,我被卡在了一个数学题上,本来以为这个题目真的是很容易,天真的以为打表就可以敲的出来,可是并没有,横在了一个结束条件上面,比完赛后真想抽自己 ...

  10. 使用国内镜像通过pip安装python的一些包 Cannot fetch index base URL http://pypi.python.org/simple/

    原文地址:http://www.xuebuyuan.com/1157602.html 学习flask,安装virtualenv环境,这些带都ok,但是一安装包总是出错无法安装, 比如这样超时的问题: ...