JavaScript 核心原理解析
重构你对 JavaScript 语言的认知
周爱民  《JavaScript 语言精髓与编程实践》作者,南潮科技(Ruff)首席架构师
专栏
已完结·共 28 讲
|
3.3w 人已学
|
收藏
westfall
老师给被人的回复说闭包是在函数调用的时候才创建和初始化的。但是文中又有一句话 “得到这个闭包的过程与是否调用它是无关的。”这里是不是有矛盾?
作者回复:Oh...其实主要还是我说得不清楚。 对于函数表达式来说,函数表达式总是在其它表达式运算过程中被引用的,以下面的代码为例: ``` arr.push(function() { // ... }) ``` 这个“匿名函数(表达式)”是在push()方法中被作为运算数引用的。同理,`1 + function() { ... }`这样的代码,是在+运算中被作为右操作数引用的。 函数表达式在被引用时,它自己作为运算元(运算数)会被“执行”一次,这就好象是“单值表达式”作为值也需要被“求值”一次一样。这个操作,可以理解为匿名函数表达式的实例化过程——从代码文本变成一个代码实例,而同时,这个实例的闭包就被创建了。这与“函数声明”中的函数是不一样的。 函数声明(比如说一个声明的具名函数)如下: ``` function foo() { // ... } ``` 在引擎处理到这个具名函数的声明时,它也会被实例化。但是你看到它并没有执行。执行过程要等到类似下面的代码出现时: ``` foo(); // or aCallbackPromise.then(foo) // or setTimeout(foo, 1000) ``` 类似于此的时候,当这个foo被调用时——调用行为才会创建起这个闭包来。 所以,确切地来说:函数与函数表达式,在它们的闭包的处理行为上是不一样的。函数表达式是当它被“求值到”的时候,就创建了一个闭包,而具名函数(例如foo)是在它调用、亦即时foo()发生的时候,才创建的闭包。 我应该是没有非常明确地阐述这二者的区别,这才带来了你的误解。——而在本文中,这里正好处理的是函数表达式。
2021-01-19
从未止步
懂,大概就是自己通过食材和味道可以形成自己的一套体系,深入其本身,明白其中缘由,由浅至深,由点到面,嗯嗯 领悟了,去继续捡豆子了 ,谢谢老师
作者回复:😀😀👍
2020-03-28
授人以摸鱼
我忽然想明白为啥会有迭代器的next需要支持传入参数这样的功能了……以前一直没想明白来着…… 其实就是作为生成器函数的一个应用实例,co模块需要这个功能,需要把yield返回的promise like对象的then方法传回的值从next给生成器函数传回去,这个需求抽象一下,就成了“外部执行环境会需要根据yield传出的结果进行变换后用next传入”这样的通用需求了。 所以我同时也就理解了,为啥说async await是生成器函数的语法糖了,而且这糖真甜wwwww
作者回复::) 赞的!又是大有所得~ ^^.
2020-03-26
Smallfly
1. [] 的求值过程 一开始没明白题目的意思,看到留言区的提示才理解,题目考察的是 JS 的类型转换,[] 属于对象类型,对象类型到值类型的转换过程是什么样的? 对象转值类型的规范过程称为:ToPrimitive 分为三个步骤: 1. 判断对象是否实现 [Symbol.toPrimitive] 属性,如果实现调用它,并判断返回值是否为值类型,如果不是,执行下一步。 2. 如果转换类型为 string,依次尝试调用 toString() 和 valueOf() 方法,如果 toString() 存在,并正确返回值类型就不会执行 valueOf()。 3. 如果转换类型为 number/default,依次尝试调用 valueOf() 和 toString(),如果 valueOf() 存在,并正确返回值类型就不会执行 toString()。 数组默认没有实现 [Symbol.toPrimitive] 属性,因此需要考察 2、3 两步。 [] + ’‘ 表达式为 string 转换,会触发调用 toString() 方法,结果为空字符,等价于 ’’ + ‘’ 结果为 ‘’。 +[] 表达式是 number 转换,会先触发调用 valueOf() 方法,该方法返回的是空数组本身,它不属于值类型,因此会再尝试调用 toString() 方法,返回空字符,+‘’ 结果为 0;
作者回复:加分加分。呵呵~ ^^.
2020-02-08
亦枫丶
从前几节课的疑惑,到后面几节课的承上启下,再到最后的浑然一体,这门课不仅让我学到了知识,也让我学到了体系,见识到了不一样的学习角度,老师真实让我大开眼界。 老师的文字如艺术品般,印证了那句“好的东西都是美的”。 谢谢老师
作者回复:😄多谢多谢。 我需要继续努力做得更好💪
2020-01-07
晓小东
好快,这个专栏结束了,有点舍不得,一个多月来我一直关注老师更新,反复阅听之前章节。体会深思理解,发现如果没有老师带领层层分析JavaScript 最核心那部分设计和概念,真的无缘了解这门语言了,谢谢老师给我们思维上的提升,同时也发现自己对这门语言的理解上,上了一个大大的台阶。在此由衷的感谢,真的感觉,遇到了恩师。
作者回复:😀+🤝
2020-01-03
许童童
老师的文章确实是非常有深度的。和其它的文章是完全不一样的。
作者回复:多谢多谢。^^.
2020-01-01
晓小东
老师我测很多代码得出一个总结: 参与 + 或 - 运算 + - 只认那五种值类型数据, 从包装对象实例(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
AIMD
我觉的可以这样理解, var a = {n:1}, ref = a;// 第一行 a.x = a = {n:2};// 第二行 console.log(a.x); // --> undefined console.log(ref.x); // {n:2} 1.首先声明了a变量,里面放了一个对象(即a容器里面放了{n:1}) 2.成员访问运输符的优先级高于赋值操作符,所以a.x = a = {n:2};中的a.x会被运算求值为一个引用结果( a = { n:1 x: undefined })即这个对象的地址,此时a.x已经不在是容器,就是一个Result 3.变量容器同步,此时a对象存放着( a = { n:1 x: undefined }) 4.接着从右自左执行赋值操作 ,此时a对象变成了 a = { n: 1 x: {n:2} }) 5.因为a.x已经不是容器,无法赋值为最新的状态,所以保留原来的Result,在访问a.x就是undefined ; 6.因为ref和a是同一个引用,所以ref.x就是第4步骤最新状态的a.x的值
作者回复:对的。确实是这样。^^.
2019-12-26
行问
多看看技术在历史上是怎么出现的,怎么解决问题的,溯源这种“原型链”让我大呼过瘾。一路学习下来,有完全不懂,有闻所未闻,有懵逼,有茅塞顿开等。今天的这一讲,让我理解了 "null" 在实际开发中的合理运用。
作者回复:^^ 多谢多谢。能讲得对大家有用就好。:)
2019-12-23
讲师

周爱民

《JavaScript 语言精髓与编程实践》作者,南潮科技(Ruff)首席架构师

周爱民,前端“绿皮书”《JavaScript 语言精髓与编程实践》作者,专注于软件开发与架构、项目管理二十余年,曾任盛大网络平台架构师、支付宝业务架构师、豌豆荚首席架构师等职。著有《Delphi 源代码分析》《大道至简:软件工程实践者的思想》《大道至易:实践者的思想》《程序原...查看更多
编辑推荐
包含这门课的学习路径

前端工程师

24门课程 109.3w人学习
看过的人还看了
重学前端
程劭非(winter)
前手机淘宝前端负责人

57讲 | 105394 人已学习

¥59¥129
数据结构与算法之美
王争
前 Google 工程师

81讲 | 283832 人已学习

¥68¥199
浏览器工作原理与实践
李兵
前盛大创新院高级研究员

46讲 | 56428 人已学习

¥59¥129
左耳听风
陈皓
网名“左耳朵耗子”,资深技术专家

119讲 | 181026 人已学习

¥98¥399
设计模式之美
王争
前 Google 工程师,《数据结构与算法之美》专栏作者

113讲 | 123497 人已学习

¥98¥299
MySQL 实战 45 讲
林晓斌
网名丁奇,前腾讯云数据库负责人

49讲 | 224964 人已学习

¥68¥199