Effective JavaScript Item 54 将undefined视为"没有值"
将undefined视为"没有值"
JavaScript中的undefined是一个特殊的值:当JavaScript没有提供详细的值时。它就会产生undefined。
比方:
- 未被赋值的变量的初始值就是undefined
- 訪问对象中不存在的属性会得到undefined
- 没有返回值的函数。undefined会作为其返回值
- 函数的參数没有提供时。它的值就是undefined
// 情形1
var x;
x; // undefined // 情形2
var obj = {};
obj.x; // undefined // 情形3
function f() {
return;
}
function g() { } f(); // undefined
g(); // undefined // 情形4
function f(x) {
return x;
}
f(); // undefined
将undefined视为不论什么详细值的缺失是JavaScript语言的一种约定。
所以,将它作为其他用途使用就是一种具有风险的行为。比方,一个库中的highlight方法用来改变元素的背景颜色:
element.highlight(); // use the default color
element.highlight("yellow"); // use a custom color
假设我们想让highlight方法具备返回随机颜色的功能,我们或许会尝试使用undefined作为这样的情况下须要传入的參数来和其它情况差别开:
element.highlight(undefined); // use a random color
可是,这样做是有风险的。比方。我们可能会向该方法中传入一个对象的属性。假设该属性没有值时。highlight方法就会返回一个随机的颜色,可是这样的情况下,用户期望的结果应该是为该元素使用默认的颜色。
var config = JSON.parse(preferences);
// ...
element.highlight(config.highlightColor); // may be random
除了使用undefined之外。有些开发者可能会选择相同比較特殊的null作为參数传入来进行区分:
element.highlight(null);
可是。这种代码的可读性比較差。用户第一眼看上去会猜想此方法是要移除element的背景颜色,而不是八竿子打不着的返回随机颜色。
一个更好的API应该是这种,通过传入字符串来表名意图:
element.highlight("random"); // 或者通过配置对象。关于配置对象能够參考Item 55
element.highlight({ random: true });
另外一个须要注意undefined的地方是拥有可选參数的函数。尽管能够通过arguments对象(关于此对象,能够參考Item 51)对实际传入的參数进行推断,可是对參数进行undefined推断能够让API更加健壮。比方。一个Server对象也许会接受host名作为參数:
var s1 = new Server(80, "example.com");
var s2 = new Server(80); // defaults to "localhost" function Server(port, hostname) {
if (arguments.length < 2) {
hostname = "localhost";
}
hostname = String(hostname);
// ...
}
以上代码使用arguments的length值作为推断根据。来给hostname參数一个默认值。可是,假设hostname被传入了undefined,就会导致默认值不会生效:
// config.hostname为undefined时,就跳过了以上的检查
var s3 = new Server(80, config.hostname); // 更好的办法是显式地对undefined进行检查
function Server(port, hostname) {
if (hostname === undefined) {
hostname = "localhost";
}
hostname = String(hostname);
// ...
}
一种替代方案是进行真值推断(參见Item 3):
function Server(port, hostname) {
hostname = String(hostname || "localhost");
// ...
}
根据是undefined在做真值推断时会返回false,因此默认值localhost会生效。
可是须要注意在某些情况下使用真值推断也是不安全的。
当一个函数可以接受空的字符串作为合法參数时。进行真值推断就会将传入的空字符串替换为默认值。类似的,假设一个函数可以接受数字0(或者特殊的NaN)作为合法參数,真值推断也会将它替换成默认值。
比方,以下的API用来通过传入元素的宽度和高度进行创建。
假设没有传入。则使用默认值:
var c1 = new Element(0, 0); // width: 0, height: 0
var c2 = new Element(); // width: 320, height: 240 function Element(width, height) {
this.width = width || 320; // wrong test
this.height = height || 240; // wrong test
// ...
} var c1 = new Element(0, 0); c1.width; // 320
c1.height; // 240
当我们传入0时,真值推断会将它替换成默认值。然而这并非我们想要的行为。更好的方式是显式对undefined进行推断:
function Element(width, height) {
this.width = width === undefined ? 320 : width;
this.height = height === undefined ? 240 : height;
// ...
} var c1 = new Element(0, 0); c1.width; // 0
c1.height; // 0 var c2 = new Element();
c2.width; // 320
c2.height; // 240
总结
- 不要使用undefined来表达除了缺失特定值外的不论什么其它意义。
- 在须要表达特殊情况时。不要使用undefined或者null。
而是使用更具表达性的字符串或者对象。
- 在函数中显式地对參数进行undefined检查,而不要依赖于诸如arguments.length等检查方法。
- 对于可以接受真值推断返回false的特殊值(如0,NaN,null,""),不要使用真值推断。
Effective JavaScript Item 54 将undefined视为"没有值"的更多相关文章
- Effective JavaScript Item 55 接受配置对象作为函数參数
接受配置对象作为函数參数 尽管保持函数接受的參数的顺序非常重要,可是当函数可以接受的參数达到一定数量时.也会让用户非常头疼: var alert = new Alert(100, 75, 300, 2 ...
- Effective JavaScript Item 31 优先使用Object.getPrototypeOf,而不是__proto__
本系列作为Effective JavaScript的读书笔记. 在ES5中引入了Object.getPrototypeOf作为获取对象原型对象的标准API.可是在非常多运行环境中.也提供了一个特殊的_ ...
- 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 10 避免使用with
本系列作为Effective JavaScript的读书笔记. Item 9:避免使用withkeyword 重点: 设计withkeyword本来是为了让代码变简洁,可是却起到了相反的效果.比方: ...
- Effective JavaScript Item 39 绝不要重用父类型中的属性名
本系列作为Effective JavaScript的读书笔记. 假设须要向Item 38中的Actor对象加入一个ID信息: function Actor(scene, x, y) { this.sc ...
- Effective JavaScript Item 22 使用arguments来创建接受可变參数列表的函数
本系列作为Effective JavaScript的读书笔记. 在Item 21中,介绍了结合apply方法实现的可变參数列表函数average,它实际上仅仅声明了一个数组作为參数,可是利用apply ...
- Effective JavaScript Item 40 避免继承标准类型
本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...
随机推荐
- day05_02 IDE介绍及设置
notepad++比较麻烦,使用IDE工具进行程序开发 集成开发环境(IDE,Integrated Development Environment) VIM #经典的linux下的文本编辑器 Emac ...
- [java开发篇][代码规范]
http://www.hawstein.com/posts/google-java-style.html Google Java编程风格指南 January 20, 2014 作者:Hawstein出 ...
- 【mysql 优化 4】嵌套连接优化
原文地址:Nested Join Optimization 与SQL标准相比,table_factor的语法被扩展.后者仅接受table_reference,而不是一对括号内的列表.如果我们将tabl ...
- google chrome & preferences & languages
google chrome & preferences & languages language settings https://www.google.com/preferences ...
- 硅谷和国内的 iOS 开发到底有何不同?
前段时间在国内各大互联网公司转了一圈.与各位 iOS 业界大佬交流了之后,深感国内变化之大,敬佩诸位国内开发者的实力和韧劲.除此之外,我还发现硅谷和国内的 iOS 开发还是差别很大,且听我慢慢道来. ...
- iOS学习笔记40-日志重定向
一.日志重定向 我们在iOS开发过程中,我们时常会使用NSLog打印到控制台的日志信息进行代码调试,但这样调试的前提是连接上Xcode.如果进行真机调试但同时又不能连接Xcode的时候,就不能直接在x ...
- 【bzoj4407】于神之怒加强版 莫比乌斯反演+线性筛
题目描述 给下N,M,K.求 输入 输入有多组数据,输入数据的第一行两个正整数T,K,代表有T组数据,K的意义如上所示,下面第二行到第T+1行,每行为两个正整数N,M,其意义如上式所示. 输出 如题 ...
- P1108 低价购买 (动态规划)
题目链接 Solution 似乎就是个很简单的最长不上升子序列输出方案. 但是有一个很艹蛋的条件: 不同方案选择价格必须不同. 且其股票价格不保证不相同. \(f[i]\) 代表以第 \(i\) 天结 ...
- Dumb Bones(uva 10529)
题意:给定n,表示要放n个骨牌,每次放下骨牌,有可能向左倒的概率为pl,向右倒的概率为pr,如果倒下,会将那一侧的骨牌全部推倒,可以选择位置先后放骨牌,问说一种放骨牌次数最少的期望是多少. /* 设d ...
- 金鹰教程网 FLASH8.0(AS)视频教程(下载地址)自认为最好的一个Flash教程
原文发布时间为:2008-07-29 -- 来源于本人的百度文章 [由搬家工具导入] 可以用迅雷新建批量任务下载,很方便的。 金鹰教程网 FLASH8.0教学视频 到目前(2008年7月29日21:2 ...