资讯专栏INFORMATION COLUMN

《你不知道的JavaScript》 (中) 阅读摘要

stackvoid / 3383人阅读

摘要:这时候控制台看到的是对象的快照,然而点开看详情的话是这段代码在运行的时候,浏览器可能会认为需要把控制台延迟到后台,这种情况下,等到浏览器控制台输出对象内容时,可能已经运行,因此会在点开的时候显示,这是的异步化造成的。

本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅;

上中下三本的读书笔记:

《你不知道的JavaScript》 (上) 读书笔记

《你不知道的JavaScript》 (中) 读书笔记

《你不知道的JavaScript》 (下) 读书笔记

第一部分 类型和语法 第二章 值
43.toFixed(3)
// 报错: Invalid or unexpected token
43..toFixed(3)
// "43.000"

这是因为42.toFixed(3)这里因为.被视为常量42的一部分,所以没有.属性访问运算符来调用toFixed方法。而42..toFixed则没有问题。

第四章 强制类型转换

JSON.stringify在对象中遇到undefinedfunctionsymbol时会自动将其忽略,在数组中则会返回null,比如:

JSON.stringify([1, 23, 4, null, undefined, function(){ return 123 }])
// "[1,23,4,null,null,null]"

JS中的假值 undefinednullfalse+0-0NaN""

除了空字符串外的所有字符串都是真值

所有对象都是真值

关于真假值的判断:

new Boolean(false)       // true
new Number(0)            // true
new String("")           // true
Boolean("false")         // true
Boolean("0")             // true
Boolean("""")            // true
Boolean([])              // true
Boolean({})              // true
Boolean(function() {})   // true
第五章 语法 结果值

语句都有个结果值:

赋值表达式 b = a 的结果值是a的值

规范定义 var 的结果值是 undefined

代码块 { ... } 的结果值是其最后一个语句表达式的结果

标签语句

{ foo: bar() } 这里的 foo标签语句,带标签的循环跳转可以使用 continuereak 来实现执行标签所在循环的下一轮循环或跳出标签所在循环;

foo: for (var i = 0; i < 4; i++){
    for (var j = 0; j < 4 ; j++){
        if ((i * j) === 3){
            console.log("stoping", i, j)
            break foo;
        }   
        console.log(i, j)
    }
}
// 0 0
// 0 1
// 0 2
// 0 3
// 1 0
// 1 1
// 1 2
// stoping 1 3

这里的 break foo 不是指跳转到标签 foo 所在位置继续执行,而是跳出标签 foo 所在的循环/代码块,继续执行后面的代码。因此这里的标签语句并非传统意义上的 goto

关联

运算符有优先级,那么如果多个相同优先级的运算符同时出现,执行的顺序就和关联顺序有关了,JS默认的执行顺序是从左到右,但是有时候不是,比如:

? : 三元运算符是右关联,比如? : ? : ,其实是? : (? :) 这样的顺序

= = 连等是右关联,比如 a=b=c=2,其实是 (a=(b=(c=2)))

函数参数

像函数传递参数时,arguments 数组中对应单元会和命名参数建立关联(linkage)以得到相同的值;相反,不传递参数就不会建立关联:

function foo(a){
    a=42
    console.log(arguments[0])
}
foo(2)             // 42
foo()            // undefined

注意:严格模式没有建立关联一说;

try...finally

finally 中的代码总是会在 try 之后执行,即使 try 中已经 return 了,如果有 catch 的话则在 catch 之后执行;

function foo(){
    try{
        return("returned")
    } finally {
        console.log("finally")
    }
}
console.log(foo())
// finally
// returned

如果 finally 中抛出异常,函数会终值,如果之前 try 中已经 return 了返回值,则返回值会被丢弃;

finally 中的 return 会覆盖 trycatch 中 return 的返回值;

finally 中如果没有 return,则会返回前面 return 的返回值;

switch

switch 中的 case 执行的匹配是 === 严格相等的,也就是说如果不是 true,是真值也是不通过的:

switch(true) {
    case ("hello" || 10):
        console.log("world")    // 不会执行
        break;
    default:
        console.log("emmm")
}
// emmm

所以这里的字符串即使是真值,也是不被匹配,所以可以通过强制表达式返回 Boolean 值,比如 !!("hell0" || 10)

default 是可选的,无需放在最后一个,且并非必不可少:

switch(10){
    case 1:
    case 2:
    default:
        console.log("hello")
    case 3:
        console.log(3)
        break;
    case 4:
        console.log(4)
}
// hello
// 3

上面这个例子的逻辑是:首先找匹配的 case,没找到则运行 default,因为其中没有 break,所以继续执行 case 3 中的代码,然后 break;

附录 全局 DOM 变量

由于浏览器历史遗留问题,在创建带有 id 属性的 DOM 元素的时候也会创建同名的全局变量:

console.log(foo) // 打印出DOM元素

所以说 HTML 中尽量少用 id 属性...

第二部分 异步和性能 第一章 异步:现在和将来 异步控制台

某些浏览器的 console.log 并不会把传入的内容立即输出,原因是在许多程序(不只是JS)中,I/O 是非常低速的阻塞部分,所以,从页面UI的角度来说,浏览器在后台异步处理控制台 I/O 能够提高性能,这时用户可能根本意识不到其发生。

var a = { b: 1 }
console.log(a)
a.b++

这时候控制台看到的是 a 对象的快照 {b:1},然而点开看详情的话是 {b:2} ;这段代码在运行的时候,浏览器可能会认为需要把控制台 I/O 延迟到后台,这种情况下,等到浏览器控制台输出对象内容时,a.b++ 可能已经运行,因此会在点开的时候显示 {b:2},这是 I/O 的异步化造成的。

如果遇到这种情况:

使用JS调试器中的断点,而不要依赖控制台输出;

把对象序列化到一个字符串中,以强制执行一次快照,比如通过 JSON.stringify

第三章 Promise 回调未调用

如果 Promise 状态一直未改变,怎么得到通知呢,这里可以使用 Promise.race 竞态,如果在设置时间内还未返回,那么 Promise 将会被 reject

function timeoutPromise(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => { reject("Timeout!") }, delay)
  })
}
 
Promise.race([foo(), timeoutPromise(3000)])
  .then(() => console.log("Promise 及时完成"))
  .catch(() => console.log("Promise 超时了"))
第四章 生成器 输入和输出
function* foo(x) {
  return x * (yield "hello")
}
const it = foo(6)
 
let res = it.next()
res.value       // hello
 
res = it.next(7)
res.value       // 42

可以看到第一个 next 并没有传参,因为只有暂停的 yield 才能接受这样一个通过 next 传递的参,而在生成器刚生成还没有 next() 这时候还没有暂停的 yield 来接受这样一个值,所以会默默丢弃传递给第一个 next 的任何参数。

生成器中的 Promise 并发
function* foo() {
  const r1 = yield request("http://some.url.1")
  const r2 = yield request("http://some.url.2")
}

这种方式的两个请求是串行的,yield 只是代码中一个多带带的暂停点,不能同时在两个点上暂停,如果希望并行的发送,那么考虑:

function* foo() {
  const p1 = request("http://some.url.1")
  const p2 = request("http://some.url.2")
  const r1 = yield p1
  const r2 = yield p2
}

PS:欢迎大家关注我的公众号【前端下午茶】,一起加油吧~

另外可以加入「前端下午茶交流群」微信群,长按识别下面二维码即可加我好友,备注加群,我拉你入群~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100748.html

相关文章

  • 你不知道JavaScript》 (下) 阅读摘要

    摘要:本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅不错,下册的知识点就这么少,非常不推介看下册上中下三本的读书笔记你不知道的上读书笔记你不知道的中读书笔记你不知道的下读书笔记第三 本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 不错,下册的知识点就这么少,非...

    Jacendfeng 评论0 收藏0
  • 你不知道JavaScript》 (上) 阅读摘要

    摘要:但是如果非全局的变量如果被遮蔽了,无论如何都无法被访问到。但是如果引擎在代码中找到,就会完全不做任何优化。结构的分句中具有块级作用域。第四章提升编译器函数声明会被提升,而函数表达式不会被提升。 本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 上中下三本的读书笔记: 《你不知道的JavaScript》 (上) 读书笔记...

    FingerLiu 评论0 收藏0
  • 2017年 最好javascript 书籍

    摘要:请记住,这些书中的一些可能不是最新的,但概念和基础仍应适用。是最好的老师之一。的秘密由部分组成。在你完成这些书后,查看书籍和最好的本土书籍。 我看过三本,第1本,第二本,第四本。第一本买的的实体书,其他两本看的是电子书。第一本是大名鼎鼎老道写的,书很薄,但是非常经典。javascirpt忍者秘籍是jquery的作者写的,也是非常经典。you dont kown js系列也是非常好。看了...

    mingzhong 评论0 收藏0
  • H5 知识点 - 收藏集 - 掘金

    摘要:目录不要过度依赖一前端掘金毫无疑问,是一款非常优秀的库,它让我们开发项目变得更加便捷容易。但是作为一个前端工作者,我们肯定也希望在我们的网页里也能看到这么酷分钟搞定常用基础知识前端掘金基础智商划重点在实际开发中,已经非常普及了。 跨域解决方案总结 - 前端 - 掘金为什么需要跨域? 就得先知道同源策略. 同源策略 同源策略是为了保证数据的安全性,一个域的脚本不能去操作另外一个域的脚本的...

    frontoldman 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<