[]==false隐式转换

一元操作符 +、-
先来看看 + 或 - 在一个类型值前面,这里会执行 ToNumber 类型转换。如果是 - 在前面的话,还会将结果的符号取反,如:-“123” 的结果是 -123。并且如果原类型是对象的话也是遵循 ToNumber 的转换规则;

var a = '123';
var b = +a;
var c = -a;

console.log(b); // 123
console.log(c); // -123

二元操作符
解析后需要时数字
相减 a - b
当执行减法操作时,两个值都会先执行 ToNumber 转换,所以这个是比较简单的,当类型是对象时也是遵循同样的规则。

console.log('124' - true); //123
console.log(124 - true); //123
console.log(true - 124); //-123

相加 a + b
如果 + 的操作数中有对象,则执行 ToPrimitive 并且 hint 是 Number
如果 + 中有一个操作数是字符串(或通过第一步得到字符串),则执行字符串拼接(另一个操作数执行 ToString 转换),否则执行 ToNumber 转换后相加

console.log('124' + true); //'124true'
console.log(true + '124'); //'124true'
console.log(124 + true); //125

相加的情况有点复杂,
第一步,先看操作数里面有没有对象,如果有就是执行 hint 是 Number 的 ToPrimitive 操作。大家可以回忆下上篇说的 ToPrimitive 的内容,这里要注意的是这里的 ToPrimitive 并没有将操作数强制转化为 Number 类型。因为 hint 是 Number,所以先执行 valueOf() ,如果返回了字符串那转换结果就是字符串了;如果返回的不是基本类型值才会执行 toString(),如果都没有返回基本类型值就直接抛异常了。

第二步,如果有一个操作数是字符串,那么整个结果就是字符串拼接的,否则就是强转数字加法;第二个操作数就会按这个规则进行对应的类型转换。

对象情况下的代码:

var a = Object.create(null);
a.valueOf = function() {
  return '123';
}
a.toString = function() {
  return '234';
}
console.log(a + 6); // "1236"

以上的执行结果说明了执行 ToPrimitive 并且 hint 是 Number 结论是正确的,因为 “123” 是 valueOf 返回的。两个操作数相加的其他情况大家也可以自己试试,记住我上面的总结就完了。

a && b、a || b

在 JS 中我们都知道 && 和 || 是一种"短路”写法,一般我们会用在 if 或 while 等判断语句中。这一节我们就来说说 && 和 || 出现的隐式类型转换。

我们通常把 && 和 || 称为逻辑操作符,但我觉得 《你不知道的 Javascript(中卷)》中有个说法很好:称它们为"选择器运算符"。看下面的代码:

var a = 666;
var b = 'abc';
var c = null;

console.log(a || b); // 666
console.log(a && b); // "abc"
console.log(a || b && c); // 666

&& 和 || 会对操作数执行条件判断,如果操作数不是布尔值,会先执行 ToBoolean 类型转换后再执行条件判断。最后 && 和 || 会返回一个操作数的值还不是返回布尔值,所以称之为"选择器运算符"很合理。

这里有个可能很多人都不知道的情况是:在判断语句的执行上下文中,&& 和 || 的返回值如果不是布尔值,那么还会执行一次 ToBoolean 的隐式转换:

var a = 666;
var b = 'abc';
var c = null;

if (a && (b || c)) {
  console.log('yes');
}

如果要避免最后的隐式转换,我们应该这样写:

if (!!a && (!!b || !!c)) {
  console.log('yes');
}
a == b 和 a === b

从这里开始是 JS 中隐式转换最容易中坑的地方。。

首先我们先明确一个规则:"== 允许在相等比较中进行类型转换,而 === 不允许。"

所以如果两个值的类型不同,那么 === 的结果肯定就是 false 了,但这里要注意几个
特殊情况:

NaN !== NaN
+0 === -0

ES5 规范定义了 == 为"抽象相等比较",即是说如果两个值的类型相同,就只比较值是否相等;如果类型不同,就会执行类型转换后再比较。下面我们就来看看各种情况下是如何转换的。

null == undefined
这个大家记住就完了,null == undefined // true。也就是说在 == 中 null 与 undefined 是一回事。

所以我们判断变量的值是 null 或者 undefined 就可以这样写了:if (a == null) {…}。

数字和字符串的抽象相等比较
一个操作数是字符串一个是数字,则字符串会被转换为数字后再比较,即是:ToNumber(字符串) == 数字。

var a = 666;
var b = '666';
console.log(a == b); // true

布尔值与其他类型的抽象相等比较
注意,这里比较容易犯错了:

var a = '66';
var b = true;
console.log(a == b); // false

虽然 ‘66’ 是一个真值,但是这里的比较结果却不是 true,很容易掉坑里。大家记住这个规则:布尔值如果与其他类型进行抽象比较,会先用 ToNumber 将布尔值转换为数字再比较。

显然 ‘66’ == 1 的结果当然是 false 咯。

对象与非对象的抽象相等比较

先说下规则:如果对象与非对象比较,则先执行 ToPrimitive(对象),并且 hint 参数为空;然后得到的结果再与非对象比较。

这里值得注意的是:在 ToPrimitive() 调用中如果 hint 参数为空,那么 [[DefaultValue]] 的调用行为跟 hint 是Number 时一样——先调用 valueOf() 不满足条件再调用 toString()。

注意这里有个例外情况:如果对象是 Date 类型,则 [[DefaultValue]] 的调用行为跟 hint 是 String 时一样。

我们来测试一下是不是这样的:

var a = Object.create(null);
a.valueOf = function() {
  console.log('a.valueOf is invoking.');
  return 666;
};
a.toString = function() {
  console.log('a.toString is invoking.');
  return '456';
};

console.log(a == 666);

console.log(a == '456');

a.valueOf = undefined;

console.log(a == '456');

// a.valueOf is invoking.
// true
// a.valueOf is invoking.
// false
// a.toString is invoking.
// true

根据输出来看依据上面的规则来解释是 OK 的。

a > b、a < b

按惯例先总结规则,情况略微复杂:

第一步:如果操作数是对象则执行 ToPrimitive(对象),并且 hint 参数为空。

第二步:

如果双方出现非字符串,则对非字符串执行 ToNumber,然后再比较
如果比较双方都是字符串,则按字母顺序进行比较
我们还是用代码来测试下:

var a = Object.create(null);
a.valueOf = function() {
  console.log('a.valueOf is invoking.');
  return '666';
};
a.toString = function() {
  console.log('a.toString is invoking.');
  return true;
};

console.log(a > '700');
// a.valueOf is invoking.
// false

a.valueOf = undefined;
console.log(a < 2);
// a.toString is invoking.
// true

这里注意下当测试 a < 2 时,toString() 返回了 true,然后会执行 ToNumber(true) 返回 1,最后 1 < 2 的结果就是 true。

a ≥ b,a ≤ b
最后这里也是一个比较容易中坑的地方。

根据规范 a ≤ b 会被处理为 a > b,然后将结果反转,即处理为 !(a > b);a ≥ b 同理按照 !(a < b) 处理。

我们来看个例子:


var a = { x: 666 };
var b = { x: 666 };

console.log(a >= b); // true
console.log(a <= b); // true

这里 a 和 b 都是字面量对象,valueOf() 的结果还是对象,所以转为执行 toString(),结果都是’[object Object]’,当然 a < b 和 a > b 的结果都是 false,然后取反结果就是 true 了。≤ 和 ≥ 的结果都是 true~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值