3.当心隐式的强制转换

JavaScript对类型错误出奇宽容

在JavaScript中有一些极少数的情况,提供错误的类型会产生一个及时错误;但是在大多数情况下,JavaScript不会抛出错误,而是按照多种多样的自动转换协议将值强制转换为期望的类型。

2 + 3; // 5
"hello" + "world"; // "hello world"
"2" + 3; // "23"
2 + "3"; // "23"
1 + 2 + "3"; // "33" === (1 + 2) + "3"; // "33"
1 + "2" + 3; // "123" === (1 + "2") + 3; // "123"

位运算符不仅会将操作数转换为数字,而且还会将操作数转换为32位整数。

"17" * 3; // 51
"8" | "1"; // 9

强制转换也会隐藏错误。结果为null的变量在算术运算中不会导致失败,而是被隐式地转换为0;一个未定义的变量将被转换为特殊的浮点数值NaN(not a number)。

NaN

  • NaN不等于其本身,测试一个值是否等于NaN根本行不通。
var x = NaN;
x === NaN; // false
  • 标准的库函数isNaN只有在你已经知道一个值是数字时才能检测它是否是NaN。
isNaN(NaN); // true
isNaN("foo"); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN({ valueOf: "foo"  }); // true
  • NaN是JavaScript中唯一一个不等于其本身的值,可以随时通过检查一个值是否等于其自身的方式来测试该值是否是NaN。
var a = NaN;
a !== a; // true

var b = "foo";
b !== b; // false

var c = undefined;
c !== c; // false

var d = {};
d !== d; // false

var e ={ valueOf: "foo"  };
e !== e; // false

//抽象函数工具
function isReallyNaN(x) {
  return x !== x;
}

对象也可以被强制转换为原始值。

  • 通过toString方法转换为字符串。
"J" + { toString: function() { return "S"; } }; // "JS"
  • 通过valueOf方法转换为数字。
2 * { valueOf: function() { return 3; } }; // 6

当一个对象同时包含toStringvalueOf方法时,运算符+应该调用哪个方法并不明显——做字符串连接还是加法应该根据参数的类型,但是存在隐式的强制转换,因此类型并不是显而易见,JavaScript通过盲目地选择valueOf方法而不是toString方法来解决这种含糊的情况。

var obj = {
  toString: function() {
    return "[object MyObject]";
  },
  valueOf: function() {
    return 17;
   }
};
"object: " + obj; // "object: 17"
// valueOf方法才真正是为那些代表数值的对象而设计的,对于这些对象,toString和valueOf方法应该返回一致的结果,最好避免使用valueOf方法,除非对象的确是一个数字的抽象。

真值运算
if||&&等运算符逻辑上需要布尔值作为操作参数,但实际上可以接受任何值,JavaScript按照简单的隐式强制转换规则将值解释为布尔值,JavaScript中有7个假值:false0-0NaNnull""undefined,除此以外所有的值都为真值。使用真值运算检查函数参数或者对象属性是否已定义不是绝对安全的。

function point(x, y){
  if (!x){
    x = 320;
  }
  if (!y){
    y = 240;
  }
  return { x: x, y: y };
}
point(0, 0); // { x: 320, y: 240 }

检查参数是否为undefined更为严格的方法是使用typeof

function point(x, y) {
  if (typeof x === "undefined") {
    x = 320;
  }
  if (typeof y === "undefined") {
    y = 240; 
  }
  return { x: x, y: y };
}
// 此版本的point函数可以正确地识别0和undefined。
point(); // { x: 320, y: 240 }
point(0, 0); // { x: 0, y: 0 }

// 另一种方式是与undefined进行比较。
if (x === undefined) { ... }

提示

  • 类型错误可能被隐式的强制转换所隐藏。
  • 重载的运算符+是进行加法运算还是字符串连接操作取决于其参数类型。
  • 对象通过valueOf方法强制转换为数字,通过toString方法强制转换为字符串。
  • 具有valueOf方法的对象应该实现toString方法,返回一个valueOf方法产生的数字的字符串表示。
  • 测试一个值是否为未定义的值,应该使用typeof或者与undefined进行比较而不是使用真值运算。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容