[Effective JavaScript 笔记]第59条:避免过度的强制转换
js是弱类型语言。许多标准的操作符和代码库会把输入参数强制转换为期望的类型而不是抛出错误。如果未提供额外的逻辑,使用内置操作符的程序会继承这样的强制转换行为。
functin square(x){
return x*x;
}
square("3");//9
强制转换
强制转换可以带来方便性,但也会带来相关的麻烦,一些错误无法显露出来,导致程序行为的不稳定和难以调试。
当强制转换与重载的函数一起工作的时候,结果会更难理解。上一节讲的位向量类的enable方法。该方法使用其参数的类型来决定其行为。如果enable方法尝试将其参数强制转换为一个期望的类型,那么方法签名可能会变更难理解。将方法的参数强制转换为一个数字完全破坏了重载。
BitVector.prototype.enable=function(x){
x=Number(x);//转化为数字
if(typeof x=== 'number'){//一直是正确的
this.enableBit(x);
}else{//这里永远不会执行
for(var i=0,n=x.length;i < n;i++){
this.enableBit(x[i]);
}
}
};
一般规则,在那些使用参数类型来决定重载函数行为的函数中避免强制转换参数。强制转换使用很难识别出参数的变量。
bits.enable('100');//数字还是位数组值
调用者可以合理地认为参数可以是一个数字或一个位数组值,然而我们的构造函数并不是为字符串设计的,因此无法识别它。
防御性编程
可能是调用者没有用对,但如果设计API时,强制只接收数字和对象,则可以避免出现上面的错误。
BitVector.prototype.enable=function(x){
if(typeof x=== 'number'){
this.enableBit(x);
}else if(typeof x==='object' && object){
for(var i=0,n=x.length;i < n;i++){
this.enableBit(x[i]);
}
}else{
throw new TypeError('请输入一个数或类数组对象');
}
};
enable方法的最终版本是一种风格更加谨慎的示例,被称为防御性编程。防御性编程试图以额外的检查来抵御潜在的错误。抵御所有可能的错误是不可能的。如,我们可能使用检查来确保如果x具有length属性,那么它应该是一个对象,然而这并不是安全的,比如,一个意外使用的String对象。
监视函数
js除了提供实现检查的基本工具外,比如typeof操作符,还可以编写简洁的工具函数来监视函数签名。如,可以使用一个预先检查来监视BitVector的构造函数。
function BitVector(x){
uint32.or(arrayLike).guard(x);
//...
}
借助于共享原型对象来实现guard方法以构建一个监视对象的工具库。
var guard={
guard:function(x){
if(!this.test(x)){
throw new TypeError('expected '+this);
}
}
};
每个监视对象实现自己的test方法和错误消息的字符串描述。
uint32监视对象
var uint32=Object.create(guard);
uint32.test=function(x){
return typeof x === 'number' && x === (x >>> 0);
};
uint32.toString=function(){
return 'uint32';
};
uint32的监视对象使用js位操作符的一个诀窍来实现32位无符号整数的转换。无符号右移位运算符在执行移位运算前会将其第一个参数转换为一个32位的无符号整数。移入零位对整数值没有影响。实际上uint32.test是把一个数字与该数字转换为32位无符号整数的结果做比较。
arrayLike监视对象
下面实现arrayLike的监视对象。
var arrayLike=Object.create(guard);
arrayLike.test=function(x){
return typeof x==='object' && x && uint32.test(x.length);
};
arrayLike.toString=function(){
return 'array-like object';
};
这里又进一步地采取了防御性编程来确保一个类数组对象应该具有一个无符号整数的length属性。
“链”方法
最后,实现一些原型方法的“链”方法,比如or方法。
guard.or=function(other){
var res=Object.create(guard);
var self=this;
res.test=function(x){
return self.test(x)||other.test(x);
};
var description=this+' or '+other;
res.toString=function(){
return description;
};
return res;
}
该方法合并接受者监视对象和另一个监视对象,产生一个新的监视对象。新监视对象的test和toString方法合并了这两个输入对象的方法。这里用局部的self来保存this的引用,以确保能在合成的监视对象的test方法中引用。
当遇到错误时,这些测试能帮助我们更早地捕获错误,使得它们更容易诊断。但,这也可能扰乱代码库并潜在地影响应用程序的性能。是否使用防御性编程是一个成本和收益的问题。
提示
避免强制转换和重载的混用
考虑防御性地监视非预期的输入
[Effective JavaScript 笔记]第59条:避免过度的强制转换的更多相关文章
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- [Effective JavaScript 笔记]第54条:将undefined看做“没有值”
undefined值很特殊,每当js无法提供具体的值时,就会产生undefined. undefined值场景 未赋值的变量的初始值即为undefined. var x; x;//undefined ...
- [Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑
构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...
- [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合
对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...
- [Effective JavaScript 笔记]第45条:使用hasOwnProperty方法以避免原型污染
之前的43条,44条讨论了属性的枚举,但都没有彻底地解决属性查找中原型污染的问题.看下面关于字典的一些操作 'zhangsan' in dict; dict.zhangsan; dict.zhangs ...
- [Effective JavaScript 笔记]第67条:绝不要同步地调用异步的回调函数
设想有downloadAsync函数的一种变种,它持有一个缓存(实现为一个Dict)来避免多次下载同一个文件.在文件已经被缓存的情况下,立即调用回调函数是最优选择. var cache=new Dic ...
随机推荐
- storm如何保证at least once语义?
背景 前期收到的问题: 1.在Topology中我们可以指定spout.bolt的并行度,在提交Topology时Storm如何将spout.bolt自动发布到每个服务器并且控制服务的CPU.磁盘等资 ...
- 有四中方法可以实现PHP的伪静态,你造吗?
说起伪静态的实现方案,你是不是很爽快的回答"简单,配置下apache的重写规则就行了嘛" 但是你有没有发现这种情况,你最近弄了很多新功能,每天上几个新功能,每天都有好多伪静态配置, ...
- [USACO2004][poj2373]Dividing the Path(DP+单调队列)
http://poj.org/problem?id=2373 题意:一条直线分割成N(<=25000)块田,有一群奶牛会在其固定区域吃草,每1把雨伞可以遮住向左右延伸各A到B的区域,一只奶牛吃草 ...
- shell中的正则表达式
1.正则与通配符 linux中的通配符是用来匹配文件名的,其匹配是完全匹配.只支持通配符则命令有ls find cp等命令 正则是用来匹配字符串的,是包含匹配.只要搜索的内容在某个字符串中,那么改字符 ...
- 年终福利:调试.NET Framework源代码
前言 要问JAVA语言最大的优势之一,那就是开源.开源的JAVA框架让JAVA程序员可以不断的通过看源代码来学习.成长.解决问题.并随着时间增长能力越来越强,自然薪水就越来越高.而DONET程序员要看 ...
- c#中的protected和internal
protected限制子类访问,可以跨程序集 internal 限制此程序集访问,可以跨类 protected internal 限制此程序集的子类中访问
- ASP.NET Web API实现POST报文的构造与推送
毕设和OAuth协议相关,而要理解OAuth协议就必须理解HTTP GET/POST方法.因此研究了一下如何使用Web API或MVC构造POST报文并实现客户端与服务器端的交互. 我使用的工具是Vi ...
- 20.(转)Android的样式(Style)和主题(Theme)
Android上的Style分为了两个方面: 1,Theme是针对窗体级别的,改变窗体样式: 2,Style是针对窗体元素级别的,改变指定控件或者Layout的样式. Android系统的themes ...
- BZOJ-2929 洞穴攀岩 最大流Dinic(傻逼题)
竟然没有1A真羞耻...1分钟不到读完题,10分钟不到打完....MD没仔细看...WA了一遍,贱! 2929: [Poi1999]洞穴攀行 Time Limit: 1 Sec Memory Limi ...
- jQuery返回顶部代码组件
非原创,拿来修改,样式可自定义,div,img都可以,效果如下: 下载地址:http://files.cnblogs.com/files/EasonJim/jquery.topback.rar 项目相 ...