本系列作为EffectiveJavaScript的读书笔记。

在将function当做构造函数使用时,须要确保该函数是通过newkeyword进行调用的。

function User(name, passwordHash) {
this.name = name;
this.passwordHash = passwordHash;
}

假设在调用上述构造函数时。忘记了使用newkeyword。那么:

var u = User("baravelli", "d8b74df393528d51cd19980ae0aa028e");
u; // undefined
this.name; // "baravelli"
this.passwordHash; // "d8b74df393528d51cd19980ae0aa028e"

能够发现得到的u是undefined。而this.name以及this.passwordHash则被赋了值。可是这里的this指向的则是全局对象。

假设将构造函数声明为依赖于strict模式:

function User(name, passwordHash) {
"use strict";
this.name = name;
this.passwordHash = passwordHash;
}
var u = User("baravelli", "d8b74df393528d51cd19980ae0aa028e");
// error: this is undefined

那么在忘记使用newkeyword的时候,在调用this.name= name的时候会抛出TypeError错误。这是由于在strict模式下。this的默认指向会被设置为undefined而不是全局对象。

那么,是否有种方法可以保证在调用一个函数时,不管使用了newkeyword与否,该函数都可以被当做构造函数呢?以下的代码是一种实现方式。使用了instanceof操作:

function User(name, passwordHash) {
if (!(this instanceof User)) {
return new User(name, passwordHash);
}
this.name = name;
this.passwordHash = passwordHash;
} var x = User("baravelli", "d8b74df393528d51cd19980ae0aa028e");
var y = new User("baravelli", "d8b74df393528d51cd19980ae0aa028e");
x instanceof User; // true
y instanceof User; // true

以上的if代码块就是用来处理没有使用new进行调用的情况的。当没有使用new时。this的指向并非一个User的实例。而在使用了newkeyword时,this的指向是一个User类型的实例。

还有一个更加适合在ES5环境中使用的实现方式例如以下:

function User(name, passwordHash) {
var self = this instanceof User ? this : Object.create(User.prototype);
self.name = name;
self.passwordHash = passwordHash;
return self;
}

Object.create方法是ES5提供的方法。它可以接受一个对象作为新创建对象的prototype。

那么在非ES5环境中,就须要首先实现一个Object.create方法:

if (typeof Object.create === "undefined") {
Object.create = function(prototype) {
function C() { }
C.prototype = prototype;
return new C();
};
}

实际上,Object.create方法还有接受第二个參数的版本号,第二个參数表示的是在新创建对象上赋予的一系列属性。

当上述的函数确实使用了new进行调用时。也可以正确地得到返回的新建对象。这得益于构造器覆盖模式(Constructor Override Pattern)。该模式的含义是:使用了newkeyword的表达式的返回值可以被一个显式的return覆盖。

正如以上代码中使用了returnself来显式定义了返回值。

当然。以上的工作在某些情况下也不是必要的。可是,当一个函数是须要被当做构造函数进行调用时,必须对它进行说明,使用文档是一种方式。将函数的命名使用首字母大写的方式也是一种方式(基于JavaScript语言的一些约定俗成)。

总结:

  1. 使用Object.create来保证一个函数确实是被当做一个构造函数进行调用的,不管newkeyword是否被使用了。

  2. 对于作为构造函数的函数。在文档中指明这一点来保证其它用户可以正确的使用它。

Effective JavaScript Item 33 让构造函数不再依赖newkeyword的更多相关文章

  1. Effective JavaScript Item 38 调用父类的构造函数在子类的构造函数

    作为这一系列Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中.都会有场景(Scene)这一概念.在一个场景中会包括一个对象集合,这些对象被称为角色(Actor). ...

  2. Effective JavaScript Item 40 避免继承标准类型

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...

  3. Effective JavaScript Item 21 使用apply方法调用函数以传入可变參数列表

    本系列作为Effective JavaScript的读书笔记. 以下是一个拥有可变參数列表的方法的典型样例: average(1, 2, 3); // 2 average(1); // 1 avera ...

  4. Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序. 可是在使用for..in循环对Objec ...

  5. Effective JavaScript Item 37 认识this的隐式指向

    本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔.所以在实现CSV Reader时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...

  6. Effective JavaScript Item 39 绝不要重用父类型中的属性名

    本系列作为Effective JavaScript的读书笔记. 假设须要向Item 38中的Actor对象加入一个ID信息: function Actor(scene, x, y) { this.sc ...

  7. Effective JavaScript Item 30 理解prototype, getPrototypeOf和__proto__的不同

    本系列作为Effective JavaScript的读书笔记. prototype,getPropertyOf和__proto__是三个用来訪问prototype的方法.它们的命名方式非常类似因此非常 ...

  8. Effective JavaScript Item 10 避免使用with

    本系列作为Effective JavaScript的读书笔记. Item 9:避免使用withkeyword 重点: 设计withkeyword本来是为了让代码变简洁,可是却起到了相反的效果.比方: ...

  9. Effective JavaScript Item 31 优先使用Object.getPrototypeOf,而不是__proto__

    本系列作为Effective JavaScript的读书笔记. 在ES5中引入了Object.getPrototypeOf作为获取对象原型对象的标准API.可是在非常多运行环境中.也提供了一个特殊的_ ...

随机推荐

  1. iOS 获取流量

    #include <arpa/inet.h> #include <net/if.h> #include <ifaddrs.h> #include <net/i ...

  2. [置顶] macbook 深度休眠和待机

    开发用了macbook pro, 10.8.3, 因为用windows的习惯,一直比较习惯不关机,直接休眠,不是待机standby,今天找到了一个工具,可以实现,亲测通过. 下载:https://gi ...

  3. GraphQL返回分页对象

    private GraphQLOutputType testUserOutputType; private GraphQLOutputType pageType; private void initO ...

  4. asp.net 使用JS获得串口数据

    使用JS获得串口数据 JavaScript语言通常是一种网页编程语言,比较适合前台的一些应用设计.对于本地设备和数据的操作有比较大的限制.由于项目的需要,我需要获得本机的串口数据并显示在web端.我们 ...

  5. Linux虚拟机下使用USB转串口线——配置minicom、以及screen的使用

    转自:http://bbs.ednchina.com/BLOG_ARTICLE_637212.HTM 环境:Windows XP + (VMware Workstation - Linux) 1.确保 ...

  6. info.plist

    更新了Xcode8 以及 iOS10,App访问用户的相机.相册.麦克风.通讯录的权限都需要重新进行相关的配置,不然在Xcode8中打开编译的话会直接crash. 需要在info.plist中添加Ap ...

  7. 安装 Flex2packagebeta_1.994

    下载文件 解压到/var/root/Media/Cydia/AutoInstall/这个路径重启手机,Cydia会自动安装好DEB文件的 patch路径 下载 /private/var/mobile/ ...

  8. Linux see 网卡当前流量

    linux see网卡的当前流量 sar –n DEV  1 2  命令后面1 2 意思是:每一秒钟取1次值,取2次. DEV显示网络接口信息 -n参数很有用,他有6个不同的开关:DEV | EDEV ...

  9. OpenERP Client Error

    SyntaxError: JSON.parse: unexpected end of data http/mydomain:8069/web/webclient/js:23114 Solutions: ...

  10. SpringBoot自定义HttpMessageConverter

    Spring就是一个大大的插线板,上面插着各种各样的Bean. SpringBoot大大简化了Spring的配置,将原来放在XML中的配置大量的在代码中使用注解实现.这么做有利有弊,总体上利大于弊. ...