Open creeperyang opened 6 years ago
讲得很清楚,手动点赞! 👍
String.fromCharCode
的一点讨论看规范 ,我们可以知道:
String.fromCharCode ( [ char0 [ , char1 [ , … ] ] ] )
可以接收多个参数,并返回同样多个字符。
比如:
String.fromCharCode(50, 51, 52) // 234
但是,我们可以看一个反例(浏览器未严格遵循规范的):
String.fromCharCode(55297, 56375) // '𐐷'
很有意思对不对?两个参数却只返回一个字符。
当然这是我查阅怎么从 utf16
编码读取字符串时发现的,具体原因也和编码有关,这里先记一下,之后给出详细解答。
https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae 讲得很透彻 ,关心这个知识点的可以自行阅读。下面是一张可能会吸引你去读这篇文章的截图:
详细解读见 #4
<script>
标签与async
和 defer
属性浏览器在解析 HTML 时碰到普通的 <script>
标签,会暂停解析,下载并执行完脚本后,再重新开始解析。我想这个大多数人应该都了解,但async
和 defer
属性有什么区别,大家可能会有疑惑。
如上图所示:
1、碰到async(<script async src="app.js"></script>
)脚本,浏览器下载脚本的同时继续解析HTML,下载完成后,浏览器暂停解析HTML并执行脚本;
2、碰到defer(<script defer src="app.js"></script>
)脚本,浏览器下载脚本的同时继续解析HTML,在HTML解析完成后按序执行脚本;更明确一点,脚本在domInteractive
后,在DOMContentLoaded
前执行。
3、async不保证各脚本的执行顺序而 defer 保证按序执行。
<input>
和清除按钮 X
的显示问题假设这样一个场景,有一个输入框 <input>
与一个清除按钮 X
:
看起来实现没什么难的,我也不是要问清除按钮怎么用纯CSS来写,问题是,按钮的 click
和输入框的 blur
事件的发生顺序?
blur
先于 click
发生,那么问题来了,blur时清除按钮就被移除,导致 click 事件没触发,也就导致文字不会被清除。
临时方案1 :blur 的回调塞到 setTimeout(fn, 0) 里,让清除按钮的操作延后,是不是就可以让 click 触发?
不是个可靠方案,放弃。
临时方案2 :不移除按钮DOM,改为设置透明度 0。这样 click 百分百可以触发,但需要考虑透明度 0 点击的时候当作无效点击。
不是完美方案。
方案3 :利用 onmousedown
的 event.preventDefault()
来让 blur
在 click
之后发生。
按钮的 onmousedown
优先于输入框的 blur 发生,在 onmousedown
中 preventDefault
即可避免 blur 发生在 click 之前。
详情见 https://stackoverflow.com/questions/17769005/onclick-and-onblur-ordering-issue。
完美。
在测试UI的时候,发现个很有意思的问题:UI一直正常,直到浏览器宽度增加到某个值,出现了水平滚动条。
怀疑是某个元素布局问题,查找,并没找出原因。
用排除法,逐一删除相比线上不同的元素,删除第一个时,UI已经恢复正常,但是反复检查这个元素,并没有什么不对的地方;换第二个删除,UI也恢复正常....
最终找到原因,删除一个元素时,垂直滚动条消失!滚动条的原因!
继续查找原因才知道:宽度单位 vw
是包括滚动条宽度的,即100vw
的宽度是 document.documentElement.offsetWidth
,使用 rem 布局时需要额外注意。
html {
font-size: calc(100vw / 3.75);
}
解决办法:
::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
隐藏滚动条即可。
1. 从 IIFE 说一说 Expression 和 Statement
IIFE (Immediately Invoked Function Expression) 即立即调用/执行函数表达式。我们常看到(包括某些库中):
上面的即 IIFE 的一种写法,匿名函数会立即执行。下面是一些等价写法:
是不是觉得很熟悉,然后觉得没什么要注意的?那下面问个问题:
它是 IIFE 吗?为什么?Console 中输入会发生什么?单独拎出来这样问是不是有些发懵?
上面的代码运行的话会报错,并且更进一步,单独执行
function(){}
也会报错:下面首先简要解释下原因:
JS 应用是由(无语法错误的) statements 组成的。
当我们单独输入:
function (){}
时,解释器其实期待的是合法的 statement,即一个函数声明。但很抱歉,函数声明必须有 name,所以这里报错了。同理,
function (){}()
是一样的错误原因,因为当解释器首先看到关键字 function 时,它就认为要接收一个函数声明了,但我们并没有满足这个规则。下面的图可以帮助理解:
接下来我们更深入一点,来全面了解下 JS 中的 Statements 和 Expression。
对 expression ,一句话:任意合法的产生值的代码单元都是表达式。所以:
5
this
a = 5
func()
(function () {})
等等都是表达式。更详细的可参考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators。
对于 statement,我们可以直接看规范 http://es5.github.io/#x12,可以看到 statement 有
等等。其中,我们重点要讲一讲 ExpressionStatement (表达式语句) ,这是我们这个问题的由来。
表达式语句的定义如上,用中文解释下就是 合法的 expression 加上
;
(即expression;
)就是表达式语句了。但是,{
开头的不是,因为会和 BlockStatement 产生歧义function
开头的不是,因为会和 FunctionDeclaration 产生歧义所以你看,一切写在规范里了。
结合规范,我们就知道开头如果是
function
,那么一律按函数定义来解析,不合法就报错;而我们可以通过()
括号/group操作符来避免。同样
{a:1}.a
报错就是因为开头是{
被当作 BlockStatement 解释了,想当作对象那加括号吧:({a:1}).a
。