Effective JavaScript Item 33 让构造函数不再依赖newkeyword
本系列作为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语言的一些约定俗成)。
总结:
- 使用Object.create来保证一个函数确实是被当做一个构造函数进行调用的,不管newkeyword是否被使用了。
- 对于作为构造函数的函数。在文档中指明这一点来保证其它用户可以正确的使用它。
Effective JavaScript Item 33 让构造函数不再依赖newkeyword的更多相关文章
- Effective JavaScript Item 38 调用父类的构造函数在子类的构造函数
作为这一系列Effective JavaScript的读书笔记. 在一个游戏或者图形模拟的应用中.都会有场景(Scene)这一概念.在一个场景中会包括一个对象集合,这些对象被称为角色(Actor). ...
- Effective JavaScript Item 40 避免继承标准类型
本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...
- Effective JavaScript Item 21 使用apply方法调用函数以传入可变參数列表
本系列作为Effective JavaScript的读书笔记. 以下是一个拥有可变參数列表的方法的典型样例: average(1, 2, 3); // 2 average(1); // 1 avera ...
- Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合
本系列作为Effective JavaScript的读书笔记. ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序. 可是在使用for..in循环对Objec ...
- Effective JavaScript Item 37 认识this的隐式指向
本系列作为Effective JavaScript的读书笔记. CSV数据通常都会被某种分隔符进行分隔.所以在实现CSV Reader时,须要支持不同的分隔符.那么,非常自然的一种实现就是将分隔符作为 ...
- Effective JavaScript Item 39 绝不要重用父类型中的属性名
本系列作为Effective JavaScript的读书笔记. 假设须要向Item 38中的Actor对象加入一个ID信息: function Actor(scene, x, y) { this.sc ...
- Effective JavaScript Item 30 理解prototype, getPrototypeOf和__proto__的不同
本系列作为Effective JavaScript的读书笔记. prototype,getPropertyOf和__proto__是三个用来訪问prototype的方法.它们的命名方式非常类似因此非常 ...
- Effective JavaScript Item 10 避免使用with
本系列作为Effective JavaScript的读书笔记. Item 9:避免使用withkeyword 重点: 设计withkeyword本来是为了让代码变简洁,可是却起到了相反的效果.比方: ...
- Effective JavaScript Item 31 优先使用Object.getPrototypeOf,而不是__proto__
本系列作为Effective JavaScript的读书笔记. 在ES5中引入了Object.getPrototypeOf作为获取对象原型对象的标准API.可是在非常多运行环境中.也提供了一个特殊的_ ...
随机推荐
- Python编程-基础知识-条件判断
1. 简单的if/else条件判断 judge_flow.py name = input("Please input name: ") if name == 'master': p ...
- Python面向对象编程 - 一个记事本程序范例(二)
给程序加上控制台菜单 menu.py import sys from notebook import Notebook, Note class Menu: '''Display a menu and ...
- jdbc第三天
事务 什么是事务? 转账: 1. 给张三账户减1000元 2. 给李四账户加1000元 当给张三账户减1000元后,抛出了异常!这会怎么样呢?我相信从此之后,张三再也不敢转账了. 使用事务就可以处理这 ...
- $watch
$watch简单使用 $watch是一个scope函数,用于监听模型变化,当你的模型部分发生变化时它会通知你. $watch(watchExpression, listener, objectEqua ...
- vue Watcher分类 computed watch
1.Watcher构造函数源码部分代码 if (options) { this.deep = !!options.deep this.user = !!options.user this.lazy = ...
- 用户研究Q&A(1)
近来,不少同事开始认同用户研究的价值,希望通过接触,理解和研究用户来获取提升产品的有效信息.这绝对是件好事,因为我一直抱持的理念是,研究并不是藏在实验室或者握在少部分人手中的稀罕货,更重要是一种理念和 ...
- linux(red hat)下安装jenkins
Jenkins的安装能够分为在线安装和下载软件本地安装.我这里用的是另外一种方法,将其下载后是一个应用程序直接点击安装就能够.等安装完后配置一下jdk的路径就ok啦!接下来进行具体的说明: 一.前提 ...
- .net完整的图文验证
摘自:http://blog.csdn.net/durongjian/article/details/4336380 一.创建ValidaeCode类库工程: 1.创建ValidaeCode类库工程, ...
- CYDIA装了个插件,想删除怎么都删除,电脑如何删除插件?
http://bbs.weiphone.com/read-htm-tid-3670917.html 装了个插件,想删除怎么都删除不掉不要跟我说在CYDIA里面删除.,在CYDIA里点击该插件就会闪退C ...
- JS阻止冒泡方法(转)
S事件流其中一种是冒泡事件,当一个元素被触发一个事件时,该目标元素的事件会优先被执行,然后向外传播到每个祖先元素,恰如水里的一个泡泡似的,从产生就一直往上浮,到在水平面时,它才消失.在这个过程中,如果 ...