JavaScript核心原理解析
周爱民
《JavaScript语言精髓与编程实践》作者,南潮科技(Ruff)首席架构师
立即订阅
3697 人已学习
课程目录
已更新 23 讲 / 共 21 讲
0/3登录后,你可以任选3讲全文学习。
开篇词 (1讲)
开篇词 | 如何解决语言问题?
免费
从零开始:JavaScript语言是如何构建起来的 (5讲)
01 | delete 0:JavaScript中到底有什么是可以销毁的
02 | var x = y = 100:声明语句与语法改变了JavaScript语言核心性质
03 | a.x = a = {n:2}:一道被无数人无数次地解释过的经典面试题
04 | export default function() {}:你无法导出一个匿名函数表达式
05 | for (let x of [1,2,3]) ...:for循环并不比使用函数递归节省开销
从表达式到执行引擎:JavaScript是如何运行的 (6讲)
06 | x: break x; 搞懂如何在循环外使用break,方知语句执行真解
07 | `${1}`:详解JavaScript中特殊的可执行结构
08 | x => x:函数式语言的核心抽象:函数与表达式的同一性
09 | (...x):不是表达式、语句、函数,但它却能执行
10 | x = yield x:迭代过程的“函数式化”
11 | throw 1;:它在“最简单语法榜”上排名第三
从原型到类:JavaScript是如何一步步走向应用编程语言的 (6讲)
12 | 1 in 1..constructor:这行代码的结果值,既可能是true,也可能是false
13 | new X:从构造器到类,为你揭密对象构造的全程
14 | super.xxx():虽然直到ES10还是个半吊子实现,却也值得一讲
15 | return Object.create(new.target.prototype):做框架设计的基本功:写一个根类
16 | [a, b] = {a, b}:让你从一行代码看到对象的本质
17 | Object.setPrototypeOf(x, null):连Brendan Eich都认错,但null值还活着
从粗通到精通的进阶之路:唯一不变的是变化本身 (2讲)
18 | a + b:动态类型是灾难之源还是最好的特性?(上)
19 | a + b:动态类型是灾难之源还是最好的特性?(下)
不定期加餐 (3讲)
加餐 | 捡豆吃豆的学问(上):这门课讲的是什么?
免费
加餐 | 捡豆吃豆的学问(下):这门课该怎么学?
免费
加餐 | 让JavaScript运行起来
免费
JavaScript核心原理解析
登录|注册

19 | a + b:动态类型是灾难之源还是最好的特性?(下)

周爱民 2019-12-27
你好,我是周爱民。
上一讲,我们说到如何将复杂的类型转换缩减到两条简单的规则,以及两种主要类型。这两条简单规则是:
从值 x 到引用:调用 Object(x) 函数。
从引用 x 到值:调用 x.valueOf() 方法;或,调用四种值类型的包装类函数,例如 Number(x),或者 String(x) 等等。
两种主要类型则是字符串数字值
当类型转换系统被缩减成这样之后,有些问题就变得好解释了,但也确实有些问题变得更加难解。例如 @graybernhardt 在讲演中提出的灵魂发问,就是:
如果将数组跟对象相加,会发生什么?
如果你忘了,那么我们就一起来回顾一下这四个直击你灵魂深处的示例:
> [] + {}
'[object Object]'
> {} + []
0
> {} + {}
NaN
> [] + []
''
而这个问题,也就是这两讲的标题中“a + b”这个表达式的由来。也就是说,如何准确地解释“两个操作数相加”,与如何全面理解 JavaScript 的类型系统的转换规则,关系匪浅!

集中精力办大事

一般来说,运算符很容易知道操作数的类型,例如“a - b”中的减号,我们一看就知道意图,是两个数值求差,所以 a 和 b 都应该是数值;又例如“obj.x”中的点号,我们一看也知道,是取对象 obj 的属性名字符串 x
当需要引擎“推断目的”时,JavaScript 设定推断结果必然是三种基础值(boolean、number 和 string)。由于其中的 boolean 是通过查表来进行的,所以就只剩下了 number 和 string 类型需要“自动地、隐式地转换”。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《JavaScript核心原理解析》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(6)

  • 晓小东
    难道是这个吗, 如果作为标识符var x 确实没想出。
    >> Symbol() === Symbol() // false
    2019-12-28
  • sprinty
    强行找到一种方法, 但和本节所讲没啥关系:

    Object.defineProperty(global, 'x', {
        get: function() {
            return Math.random();
        }
    })

    x === x // false
    2019-12-27
  • 晓小东
    老师我测很多代码得出一个总结:
    参与 + 或 - 运算 + - 只认那五种值类型数据,
    从包装对象实例(String, Number, Boolean, Symbol),和数组Object 对象调用valueOf可以看出
    只要valueOf 返回五种值类型数据, 就不会toString()方法, 反之如果还是对象类型,即使是包装对象实例,还是会调用toString方法
    总结是: 在toPrimitive()中要获取五种值类型数据包括undefined 和 null, 大部分情况下引擎都是按数据值类型进行预测: 如下:
    {}; + []
    String(1) + [];
    1 - [];
    都是valueOf -> toString 过程

    最终在toPrimitivie() 中 根据 + 或者 - 以及运算符两侧值类型 调用相应String 或者Number 进行转换 求值
    所以最终的结果只有三种 字符串、数值、和 NaN

    直接toString就是在模板字符串中(目前发现这一种除了Date)
    `${x}`

    测试代码如下
    代码链接 https://repl.it/@XiaoDHuang/MadEuphoricTabs

    let valueOf = Array.prototype.valueOf
    let toString = Array.prototype.toString;

    Array.prototype.valueOf = function() {
        console.log(this.flag + " valueOf")
        return valueOf.call(this);
    }

    Array.prototype.toString = function() {
        console.log(this.flag + ' toString');
        return toString.call(this);
    }

    var x = [];

    x.flag = '{}; + []';
    {}; + x;

    x.flag = 'String(1) + []';
    console.log(1 + x);

    x.flag = '1 - []';
    console.log(1 - x);

    x.flag = '`${x}`'
    console.log(`${x}`);

    作者回复: 是的呀。

    > 总结是: 在toPrimitive()中要获取五种值类型数据包括undefined 和 null, ...
    ------

    在上一小节里不是讲过了么?原文是:
    > > 一种关于“原始值”的简单解释是:所有 5 种能放入私有槽(亦即是说它们有相应的包装类)的值(Values),都是原始值;并且,再加上两个特殊值 undefined 和 null,那么就是所谓原始值(Primitive values)的完整集合了。

    > 只要valueOf 返回五种值类型数据, 就不会toString()方法, 反之如果还是对象类型,即使是包装对象实例,还是会调用toString方法...
    ----
    这在这一讲的“步骤4”中也讲到了。原文是:
    > > 这需要利用到对象的valueOf()和toString()方法:当预期是“number”时,valueOf()方法优先调用;否则就以toString()为优先。并且,重要的是,上面的预期只决定了上述的优先级,而当调用优先方法仍然得不到非对象值时,还会顺序调用另一方法。

    最后,关于Date()类型中顺序相反的问题,本讲里也是解释了的哟哟哟哟~ ^^.

    2019-12-27
  • Astrogladiator-埃蒂纳度斯
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

    看了下mdn,还真是只有NaN这么一种情况。

    If Type(x) is different from Type(y), return false.
    If Type(x) is Number or BigInt, then
    Return ! Type(x)::equal(x, y).
    Return ! SameValueNonNumeric(x, y).

    Assert: Type(x) is not Number or BigInt.
    Assert: Type(x) is the same as Type(y).
    If Type(x) is Undefined, return true.
    If Type(x) is Null, return true.
    If Type(x) is String, then
    If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false.
    If Type(x) is Boolean, then
    If x and y are both true or both false, return true; otherwise, return false.
    If Type(x) is Symbol, then
    If x and y are both the same Symbol value, return true; otherwise, return false.
    If x and y are the same Object value, return true. Otherwise, return false.

    按照https://tc39.es/ecma262/#sec-samevaluenonnumeric的说明测试了下也没有找到其他的可能

    好奇这个答案是什么

    作者回复: 绝对是还有的。至少一个。^^.

    2019-12-27
    1
  • 晓小东
    老师这个“其中的 boolean 是通过查表来进行的“ 这个查表该如何理解???

    作者回复: Here:

    https://tc39.es/ecma262/#sec-toboolean

    2019-12-27
  • 潇潇雨歇
    想不出啦……NaN不是唯一的吗
    2019-12-27
    5
收起评论
6
返回
顶部