文档章节

JavaScript创建对象(二)——构造函数模式

Bob2100
 Bob2100
发布于 2018/09/15 13:35
字数 1174
阅读 69
收藏 0

JavaScript创建对象(一)—— 工厂模式留下了一个问题,就是创建一个对象怎么判断一个对象的类型。换句话说使用下面这种方式:

function createPerson(name, age, job){
var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        console.log(this.name);
    }
    return o;
}

只是函数的名字叫createPerson,其实返回的对象的本质还是一个Object。现在只能你说他是人他就是人,你说他是狗他就是狗,有没有一种方法比如类似下面这样:

var p1 = createPerson('zhangsan', 18, 'JavaScript');
if(p1 == Person){
    alert('p1是人');
}
if(p1 == Dog){
    alert('p1是狗');
}

在程序上有一种判断逻辑可以区分对象的类型呢?答案是有的,这就是本篇文章要讨论的构造函数模式。

现在使用构造函数模式改写上面的工厂模式:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}
var p1 = new Person('zhangsan', 18, 'JavaScript');
var p2 = new Person('lisi', 20, 'Java');

我们比较构造函数模式和工厂模式发现构造函数模式有以下不同:

  1. 没有显式的创建对象,如工厂模式 var o = new Object();
  2. 直接将属性和方法赋给了this,而不是o
  3. 没有return语句
  4. 创建对象使用new关键字,而不是直接调用函数

现在我们可以来讨论如何解决判断对象类型的问题了,很简单,可以使用如下代码:

alert(p1.constructor == Person); //true
alert(p2.constructor == Person); //true

同理,判断一个对象是否是狗,也可以这样:

function Dog(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }
}
var d1 = new Dog('xiaohei', 2, 'kanjia');
var d2 = new Dog('xiaohua', 3, 'huyuan');
alert(d1.constructor == Dog); //true
alert(d2.constructor == Dog); //true

这样就可以用代码在逻辑上判断一个对象的类型了。

检测对象的类型除了可以使用对象的constructor属性还可以使用instanceof关键字。JavaScript和Java一样,所有对象均继承自Object,使用instanceof可以检测到继承链,但是constructor不行,所以从这个角度来说instanceof更可靠一些,因为一个对象是子类型,当然也是父类型。看下面代码:

alert(p1.constructor == Object); //false
alert(p1.constructor == Person); //true
alert(p1 instanceof Object); //true
alert(p1 instanceof Person); //true

至此构造函数函数不止具有了工厂模式的优点,还解决了工厂模式的缺点,那么构造函数模式有没有缺点呢?当然也是有的。 以上述p1p2为例,这两个对象都具有sayName函数,而且功能也一样。在构造函数中sayName是一个指针, function(){alert(this.name)}是一个匿名函数,我们知道js中函数也是对象,每次创建对象都要执行构造函数,那么也就会创建一个匿名函数对象,若是创建若干个对象,那么就要创建若干个匿名函数对象,功能都相同,没必要不说,还占用内存。

通过以下代码可以说明p1sayNamep2sayName确实是两个实例。

alert(p1.sayName == p2.sayName); //false

那么我们可以尝试像下面这样解决这个问题,把函数定义到构造函数之外:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName(){
    alert(this.name);
}
var p1 = new Person('zhangsan', 18, 'JavaScript');
var p2 = new Person('lisi', 20, 'Java');
alert(p1.sayName == p2.sayName); //true

这样虽然解决了多个函数做同一件事的问题,但是又带来了新的问题:定义在全局作用域中的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。比如这里的sayName(),实际上是为Person准备的,但因为是定义在全局作用域所以可以直接调用sayName(),也就是window.sayName(), 那么此时的this.name就是window.name了,违背了定义的初衷。另一个问题是:如果Person上需要定义很多方法,那么就要定义很多个全局函数,若再加上Dog等等其他对象的方法,这些方法全都定义为全局函数,相互揉杂在一起,那么我们自定义的引用类型就丝毫没有封装性可言了。

那么,构造函数模式多个函数做同一件事的问题到底怎么解决呢?请看下一篇——原型模式

文章参考:《JavaScript高级程序设计》第3版

© 著作权归作者所有

共有 人打赏支持
Bob2100
粉丝 23
博文 85
码字总数 46053
作品 0
浦东
高级程序员
私信 提问
JavaScript继承(五)——寄生式继承

首先回顾一下原型式继承: 寄生式继承是与原型式继承紧密相关的一种思路,并且同样也是由克罗克福德推而广之的。 说到寄生式继承不得不说工厂模式和寄生构造函数模式创建对象。下面来回顾一下...

Bob2100
02/13
0
0
JavaScript创建对象(四)——组合使用构造函数和原型模式

在JavaScript创建对象(三)——原型模式中,我们阐述了原型模式存在的两个问题:一是没办法通过构造函数初始化对象属性,二是共享引用类型的数据导致数据错乱。于是我们提出组合使用两种模式...

Bob2100
2018/10/13
0
0
JavaScript继承(二)——借用构造函数

JavaScript继承(一)——原型链中提出原型链继承的两个问题:一是原型的数据共享问题,二是创建子类型的实例时,不能向父类型的构造函数中传递参数。这两个问题的根源还是在于使用原型模式创...

Bob2100
01/20
0
0
JavaScript创建对象(七)——稳妥构造函数模式

道格拉斯-克罗克福德发明了JavaScript中的稳妥对象这个概念。所谓稳妥对象,指的是没有公共属性,而且其方法也不引用的对象。稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用和),...

Bob2100
01/01
0
0
JavaScript继承(六)——寄生组合式继承

JavaScript继承(三)——组合继承中讲到,组合继承是JavaScript中最常用的继承模式,但是它也有自己的不足之处,现在我们就来剖析它的不足,如下示例: 使用组合继承让继承实际上分为两步:...

Bob2100
02/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何开发一款以太坊(安卓)钱包系列2 - 导入账号及账号管理

这是如何开发一款以太坊(安卓)钱包系列第2篇,如何导入账号。有时用户可能已经有一个账号,这篇文章接来介绍下,如何实现导入用户已经存在的账号。 导入账号预备知识 从用户需求上来讲,导...

Tiny熊
今天
2
0
intellJ IDEA搭建java+selenium自动化环境(maven,selenium,testng)

1.安装jdk1.8; 2.安装intellJ; 3.安装maven; 3.1 如果是单前用户,配置用户环境变量即可,如果是多用户,则需配置系统环境变量,变量名为MAVEN_HOME,赋值D:\Application\maven,往path中...

不最醉不龟归
今天
4
0
聊聊ShenandoahGC的Brooks Pointers

序 本文主要研究一下ShenandoahGC的Brooks Pointers Shenandoah Shenandoah面向low-pause-time的垃圾收集器,它的GC cycle主要有 Snapshot-at-the-beginning concurrent mark包括Init Mark(P......

go4it
昨天
4
0
Makefile通用编写规则

#简单实用的Makefile模板: objs := a.o b.o test:$(objs) gcc -o test $^ # .a.o.d .b.o.d dep_files := $(foreach f,$(objs),.$(f).d) dep_files := $(wildcard $(dep_files)) ifneq ($(d......

shzwork
昨天
3
0
《万历十五年》的读后感作文4000字

《万历十五年》的读后感作文4000字: 万历十五年,即1587年,距今已过去432年。在明朝276的历史中,这一年很平淡,并没有什么特别之处。黄仁宇的《万历十五年》一书,有别于其他的历史叙述方...

原创小博客
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部