JavaScript里,构造函数通常是认为用来实现实例的,JavaScript没有类的概念,但是有特殊的构造函数。通过new关键字来调用定义的否早函数,你可以告诉JavaScript你要创建一个新对象并且新对象的成员声明都是构造函数里定义的。在构造函数内部,this关键字引用的是新创建的对象。基本用法如下:

  1. function her(name, sex, height){
  2. this.name = name;
  3. this.sex = sex;
  4. this.height = height;
  5. this.say = function(){
  6. return this.name + ' is a ' + this.sex + ' has ' + this.height;
  7. }
  8. }
  9. var she1 = new her('Anna', 'women', '170cm');
  10. console.log(she1.say()); // 'Anna is a Women has 170cm'

  上面的例子是个非常简单的构造函数模式,但是有点小问题。首先是使用继承很麻烦了,其次output()在每次创建对象的时候都重新定义了,最好的方法是让所有Car类型的实例都共享这个output()方法,这样如果有大批量的实例的话,就会节约很多内存(这种情况在之前的文章里提到过了,可以看一下)。

解决这个问题,我们可以使用如下方式:

  1. function her(name, sex, height){
  2. this.name = name;
  3. this.sex = sex;
  4. this.height = height;
  5. this.say = gaoHan;
  6. }
  7. function gaoHan(){
  8. return this.name + ' is a ' + this.sex + ' has ' + this.height;
  9. }

这个方式虽然可用,但是我们有如下更好的方式。

JavaScript里函数有个原型属性叫prototype,当调用构造函数创建对象的时候,所有该构造函数原型的属性在新创建对象上都可用。按照这样,多个her对象实例可以共享同一个原型,我们再扩展一下上例的代码:

  1. function her(name, sex, height){
  2. this.name = name;
  3. this.sex = sex;
  4. this.height = height;
  5. }
  1. /*注意:这里我们使用了Object.prototype.方法名,而不是Object.prototype主要是用来避免重写定义原型prototype对象*/her.prototype.say = function(){ return this.name + ' is a ' + this.sex + ' has ' + this.height;}
  1. var she1 = new her('Anna', 'women', '170cm');
  2. console.log(she1.say()); // 'Anna is a Women has 170cm'

这里,say()单实例可以在所有Car对象实例里共享使用。另外:我们推荐构造函数以大写字母开头,以便区分普通的函数。

只能用new吗?

  1.  
  1. function her(name, sex, height){
  2. this.name = name;
  3. this.sex = sex;
  4. this.height = height;
  5. this.say = function(){
  6. return this.name + ' is a ' + this.sex + ' has ' + this.height;
  7. }
  8. }
  1. //方法1:作为函数调用 her('Anna', 'women', '170cm');
  1. //添加到window对象上 console.log(window.say());
  2.  
  3. //方法2:在另外一个对象的作用域内调用 var o = new Object(); her.call(o, "Anna", "women", "170cm"); console.log(o.say());

该代码的方法1有点特殊,如果不适用new直接调用函数的话,this指向的是全局对象window,我们来验证一下:

  1. // 作为函数调用
  2. var she = her('Anna', 'women', '170cm');
  3. console.log(typeof tom); // 'undefined'
  4. console.log(window.say());

这时候对象tom是undefined,而window.output()会正确输出结果,而如果使用new关键字则没有这个问题,验证如下:

  1. // 作为函数调用
  2. var she = her('Anna', 'women', '170cm');
  3. console.log(typeof tom); // 'undefined'
  4. console.log(tom.say());

强制使用new!

上述的例子展示了不使用new的问题,那么我们有没有办法让构造函数强制使用new关键字呢,答案是肯定的,上代码:

  1. function Her(name, sex, height){
  2. if( !(this instanceof her) ){
  3. return new Car(name, sexr, height);
  4. }
  5. this.name = name;
  6. this.year = year;
  7. this.height= height;
  8. this.say = function(){
  9. return this.name + ' is a ' + women + ' has ' + this.height;
  10. }
  11. }var she1 = new her('Anna', 'women', '170cm');var she2 = her('Lous', 'women', '165cm');console.log(typeof she1); // object;console.log(typeof she2); // object;

通过判断this的instanceof是不是Car来决定返回new Car还是继续执行代码,如果使用的是new关键字,则(this instanceof Car)为真,会继续执行下面的参数赋值,如果没有用new,(this instanceof Car)就为假,就会重新new一个实例返回。

原始包装函数:

  1. // 使用原始包装函数
  2. var s = new String("my javascript");
  3. var n = new Number(520);
  4. var b = new Boolean(true);
  5.  
  6. // 推荐这种
  7. var s = "my javascript";
  8. var n = 520;
  9. var b = true;

推荐,只有在想保留数值状态的时候使用这些包装函数,关于区别可以参考下面的代码:

  1. // 原始string
  2. var greet = "Hello there";
  3. // 使用split()方法分割
  4. greet.split(' ')[0]; // "Hello"
  5. // 给原始类型添加新属性不会报错
  6. greet.smile = true;
  7. // 单没法获取这个值(18章ECMAScript实现里我们讲了为什么)
  8. console.log(typeof greet.smile); // "undefined"
  9.  
  10. // 原始string
  11. var greet = new String("Hello there");
  12. // 使用split()方法分割
  13. greet.split(' ')[0]; // "Hello"
  14. // 给包装函数类型添加新属性不会报错
  15. greet.smile = true;
  16. // 可以正常访问新属性
  17. console.log(typeof greet.smile); // "boolean"

本章主要讲解了构造函数模式的使用方法、调用方法以及new关键字的区别,希望大家在使用的时候有所注意。

javascript --- 设计模式之构造函数模式的更多相关文章

  1. JavaScript设计模式之构造函数模式

    一.构造函数模式概念 构造函数用于创建特定类型的对象——不仅声明了使用过的对象,构造函数还可以接受参数以便第一次创建对象的时候设置对象的成员值.你可以自定义自己的构造函数,然后在里面声明自定义类型对象 ...

  2. [JS设计模式]:构造函数模式(2)

    基本用法 function Car(model, year, miles) { this.model = model; this.year = year; this.miles = miles; th ...

  3. JavaScript设计模式之----组合模式

    javascript设计模式之组合模式 介绍 组合模式是一种专门为创建Web上的动态用户界面而量身制定的模式.使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为.这可以简化粘合性代码,使其更 ...

  4. 从ES6重新认识JavaScript设计模式(三): 建造者模式

    1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示. 建造者模式的特点是分步构建一个复杂的对象,可以用不同组合或顺序建造出不 ...

  5. 深入理解JavaScript系列(26):设计模式之构造函数模式

    介绍 构造函数大家都很熟悉了,不过如果你是新手,还是有必要来了解一下什么叫构造函数的.构造函数用于创建特定类型的对象——不仅声明了使用的对象,构造函数还可以接受参数以便第一次创建对象的时候设置对象的成 ...

  6. JavaScript设计模式之建造者模式

    一.建造者模式模式概念 建造者模式可以将一个复杂的对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示.也就是说如果我们用了建造者模式,那么用户就需要指定需要建造的类型就可以得到它们,而具体 ...

  7. JavaScript设计模式之工厂模式

    一.工厂模式概念 工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类.该模式使一个类的实例化延迟到了子类.而子类可以重写接口方法以便创建的时候指定自己的对象类型(抽象工厂). 这个模 ...

  8. JavaScript设计模式之代理模式

    一.代理模式概念 代理,顾名思义就是帮助别人做事,GoF对代理模式的定义如下: 代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问.代理模式使得代理对象控制具体对象的引用.代理几乎可 ...

  9. JavaScript设计模式之命令模式

    一.命令模式概念 命令模式(Command)的定义是:用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行.也就是说该模式旨在将函数的调用.请求和操作封装成一个单一的对 ...

随机推荐

  1. 序列sequence中的cache问题

    Oracle中序列Sequence的创建语法如下: CREATE SEQUENCE [ schema. ] sequence [ { INCREMENT BY | START WITH } integ ...

  2. Cocos2d-x 3.2 学习笔记(二)创建自定义项目

    一.通过命令创建项目 前面搭建好环境后,怎样创建自己的cocos2d-x项目呢? 先来看看cocos2dx 3.2的目录吧(涉及到3.1.1版本的,请自动对应3.2版本,3.x版本的环境搭建都是一样的 ...

  3. Express框架使用以及数据库公共操作类整理(Win7下的NodeJs)

    具体步骤: 1.安装开发工具WebStorm: 2.安装node/npm(下载地址:https://nodejs.org/download/)选择适合你的xxx.mis安装: 3.安装express框 ...

  4. C#中的new修饰符

    MSDN:在用作声明修饰符时,new 关键字可以显式隐藏从基类继承的成员. 隐藏继承的成员时,该成员的派生版本将替换基类版本. 虽然可以不使用 new 修饰符来隐藏成员,但将收到编译器警告. 如果使用 ...

  5. ssh git免密码提交代码

    使用ssh协议通过密钥验证的方式提交代码,不用再每次提交时输入账户密码. 1.打开bash 输入一下命令, ssh-keygen -t rsa -C youremail@example.com(把邮件 ...

  6. 实例演示Android异步加载图片

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

  7. CentOS7 PostgreSQL安装

    CentOS7 PostgreSQL安装 CentOS7 PostgreSQL安装 Install 安装 使用yum安装 yum install http://yum.postgresql.org/9 ...

  8. WinForm(VB.NET)获取当前登录的用户名

    运行Windows Task Manager,查看Users标签,可以看到所有登录电脑的用户,现在Insus.NET想命名用VB.NET的WinForm程序去获取当前的用户名. 获取程序简单,可以参考 ...

  9. 基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作

    我们在使用EasyUI的时候,很多情况下需要使用到表格控件datagrid,这个控件控件非常强大,使用起来很简洁,但是我在使用中,发现对于一个表里面的外键字段进行转义,并显示引用表的一些名称的操作,却 ...

  10. C#DateTimePicker控件问题

    DateTimPicker控件在遇到29这样特殊的日期,选择时可能会出现 解决方案:在属性中把Value值设置为除29日外的其他日期或者在代码中直接设置Value值:DateTimePicker1 = ...