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
4
从未止步
懂,大概就是自己通过食材和味道可以形成自己的一套体系,深入其本身,明白其中缘由,由浅至深,由点到面,嗯嗯 领悟了,去继续捡豆子了 ,谢谢老师
作者回复:😀😀👍
2020-03-28
3
授人以摸鱼
我忽然想明白为啥会有迭代器的next需要支持传入参数这样的功能了……以前一直没想明白来着……
其实就是作为生成器函数的一个应用实例,co模块需要这个功能,需要把yield返回的promise like对象的then方法传回的值从next给生成器函数传回去,这个需求抽象一下,就成了“外部执行环境会需要根据yield传出的结果进行变换后用next传入”这样的通用需求了。
所以我同时也就理解了,为啥说async await是生成器函数的语法糖了,而且这糖真甜wwwww
作者回复::)
赞的!又是大有所得~ ^^.
2020-03-26
11
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
32
亦枫丶
从前几节课的疑惑,到后面几节课的承上启下,再到最后的浑然一体,这门课不仅让我学到了知识,也让我学到了体系,见识到了不一样的学习角度,老师真实让我大开眼界。
老师的文字如艺术品般,印证了那句“好的东西都是美的”。
谢谢老师
作者回复:😄多谢多谢。
我需要继续努力做得更好💪
2020-01-07
3
晓小东
好快,这个专栏结束了,有点舍不得,一个多月来我一直关注老师更新,反复阅听之前章节。体会深思理解,发现如果没有老师带领层层分析JavaScript 最核心那部分设计和概念,真的无缘了解这门语言了,谢谢老师给我们思维上的提升,同时也发现自己对这门语言的理解上,上了一个大大的台阶。在此由衷的感谢,真的感觉,遇到了恩师。
作者回复:😀+🤝
2020-01-03
2
许童童
老师的文章确实是非常有深度的。和其它的文章是完全不一样的。
作者回复:多谢多谢。^^.
2020-01-01
1
晓小东
老师我测很多代码得出一个总结:
参与 + 或 - 运算 + - 只认那五种值类型数据,
从包装对象实例(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
1
行问
多看看技术在历史上是怎么出现的,怎么解决问题的,溯源这种“原型链”让我大呼过瘾。一路学习下来,有完全不懂,有闻所未闻,有懵逼,有茅塞顿开等。今天的这一讲,让我理解了 "null" 在实际开发中的合理运用。
作者回复:^^
多谢多谢。能讲得对大家有用就好。:)
2019-12-23
12
编辑推荐
包含这门课的学习路径
前端工程师
24门课程 109.3w人学习
看过的人还看了