JavaScript中对象与数字相乘

1,049 阅读2分钟

今天在网上瞎逛,无意间看到一个问题:一个数字乘以一个日期等于多少?
看得心里一惊,毫无防备地被这种鬼马精灵的问题戳中了盲点。于是赶紧研究一番。

    3 * new Date() // 4692361990902

看来结果是3乘上了时间戳。
Date的时间戳怎么获取呢?我们知道是

    new Date().valueOf() // 1564120663634

难道是乘上了valueOf()的值?
找到了valueOf函数是在Object的原型中定义的。

    Object.prototype.valueOf // ƒ valueOf() { [native code] }

是不是说3乘上一个对象,都是乘上它的valueOf()的值呢?来试一下!

function Test(value) {
    this.value = value;
}
Test.prototype.valueOf = function() {
    return this.value;
}
const test = new Test(3);
3 * test; // 9

的确如此!

那我们再来看看默认的valueOf是什么。

function Test(value) {
    this.value = value;
}
const test = new Test(3);
test.valueOf(); // Test {value: 3}
3 * test; // NaN

返回的是对象本身。这时候3乘上它就是NaN。
常见的内置对象的valueOf值:

    Number(3).valueOf(); // 3
    String("3").valueOf(); // "3"
    [1,2,3].valueOf(); // [1, 2, 3]
    Boolean(3).valueOf(); // true
    (function(){}).valueOf(); // ƒ (){}
    ({a:3}).valueOf(); // {a: 3}
    ...

从上面结果可以粗略总结出,如果没有对valueOf进行定义的话,那么返回值即是对象本身。
再去看一下valueOf的文档。
链接

JavaScript calls the valueOf method to convert an object to a primitive value. You rarely need to invoke the valueOf method yourself; JavaScript automatically invokes it when encountering an object where a primitive value is expected.

valueOf是用来返回对象的原始值。难怪数字乘对象是乘以它的valueOf值。
那么数字与几个基本类型数据相乘会怎么样呢?

    3 * null; // 0
    3 * undefined; // NaN
    3 * "s"; // NaN
    3 * "3"; // 9
    3 * true; // 3
    3 * false; // 0
    3 * 3; // 9
    3 * NaN; // NaN
    3 * {}; // NaN
    3 * [3]; // 9
    3 * Symbol(3); // Uncaught TypeError: Cannot convert a Symbol value to a number

原来是这样,数字与基本类型数据相乘时,其他数据又会进行类型转换。
再把相乘顺序调过来会怎样?

    {} * 3; // Uncaught SyntaxError: Unexpected token *

其他结果相同,只有这个报了错。

    ({}) * 3; // NaN

{}是JavaScript的大括号,对不起,打扰了~~

总结一下。就是数字与对象相乘,会与对象的valueOf()相乘。基本类型之间相乘,会进行类型转换再相乘。