从 2019 年 10 月底开始,我坚持每个工作日发布一篇题为“今天我学到了”的沸点。就这样点滴积累,到现在已经攒够足够的量,所以集结拿出来与大家共同分享。
当初之所以做这样一件事情,一方面是督促自己每日坚持学习;另一方面,我发现有时候学到的知识点比较琐粹,一句话就能讲完,但又不够一篇文章的体量,又得找个地方记录下来,否则过后可能又会忘记。我发现沸点是个不错的地方,于是就开始我的分享之旅。
在分享的过程中,会有一些“你说的这个问题不是什么新鲜事了”、“你才知道吗……”、“...毫无意义” 之类的声音,其实我并不太在乎。将这些话列出来也没有也别的意思,只是想说:我发布的这些沸点,对我来说肯定是有用的,是让我学到的,如果你已经知道了,那我祝贺你;如果你还不知道,希望在我学到后,也能让你也学到,大家一起点滴进步。
好了,再多说都是废话了。下面开始正文:
JavaScript
1. str.replace 方法
'2019.12.13'.replace('.', '-')
的结果是 "2019-12.13"
,默认只替换第一个匹配的 .
,如果需要替换所有的 .
,就要用到正则表达式的全局标记 g
了。
2. Array.from 方法的映射功能
Array.from()
方法将可迭代对象转为数组的同时,还可以做映射(map)操作。
3. 使用科学计数法显示的数字范围
JavaScript 中以下四个区间范围的数字会使用科学计数法显示:
- (-∞, -1e+21]
- [-1e-7, 0)
- (0, 1e-7]
- [1e+21, +∞)
4. Symbol.toStringTag
Object.prototype.toString()
可以用来检查对象类型。
var toString = Object.prototype.toString;
toString.call('foo'); // "[object String]"
toString.call([1, 2]); // "[object Array]"
toString.call(3); // "[object Number]"
toString.call(true); // "[object Boolean]"
toString.call(undefined); // "[object Undefined]"
toString.call(null); // "[object Null]"
从 ES2015 开始,可以使用内置的 Symbol.toStringTag
,自定义对象返回的类型值。
let Obj = {
get [Symbol.toStringTag]() { return 'Wow' }
}
Object.prototype.toString.call(obj) // "[object Wow]"
你可能不知道的是,有些内置对象已经在使用 Symbol.toStringTag
定义自己的类型了。
Object.prototype.toString.call(new Map()); // "[object Map]"
Object.prototype.toString.call(function* () {}); // "[object GeneratorFunction]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"
参考链接:developer.mozilla.org/en-US/docs/…
5. location 对象的属性说明
6. export default 命令的本质
JavaScript 的 export default
命令本质上是向外输出了一个叫 default
的变量。
// module.js
const apple = '🍏', banana = '🍌'
export default apple
export { banana }
// import.js
import apple, { banana } from 'm.js'
// 等同于
// module.js
const apple = '🍏', banana = '🍌'
export {
apple as default,
banana
}
// import.js
import { default as apple, banana } from 'm.js'
就是说:
export default xx
是export { xx as default }
的另一种写法import xx
是import { default as xx }
的另一种写法
7. 模板字符串的另一种用法
模板字符串(``)除了提供常用的插值语法(${}
)外,还有一个用法,这个用法为函数提供了一种特殊调用形式 func`x`。
简单地讲:alert`123` 等同于 alert(123)
而当其中包含变量时,该模板字符串会被拆解成多个参数,再调用函数:
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
即实际调用的参数为:
- 第一个参数,是「模板字符串排除变量部分」后,其余各部分字符串组成的数组。
- 从第二个参数开始,则由「模板字符串中的变量」组成的列表。
参考链接:es6.ruanyifeng.com/#docs/strin…"
8. 用 Array.from 处理包含 emoji 的字符串
字符串的 .length
属性或 .charAt()
方法对像 😃 这样的 Unicode 码点大于 0xFFFF 的字符检查是错误的。我们可以使用 ES6 引入的 Array.from
方法处理,能得到正确结果。
const str = '😎'
// .length 属性或 .charAt() 方法对 Unicode 码点大于 0xFFFF 的字符检查是错误的
str.charAt(0) // "�"
str.length // 2
// 使用 ES6 引入的 Array.from 方法处理,能得到正确结果
function charAt(str, index) {
return Array.from(str)[index] || ''
}
function strLength(str) {
return Array.from(str).length
}
charAt('😎', 0) // "😎"
strLength('😎') // 1
9. 统计字符串的字节长度
JavaScript 可以使用以下两种方式,统计一个字符串占据的字节长度:
- new TextEncoder().encode('👀⛰️').byteLength // 10,或者
- new Blob(['👀⛰️']).size // 10
10. 引入 Lodash ES 模块构建
著名的 JS 工具库 Lodash 提供了使用 ES 模块语法引入的构建——lodash-es。因此我们还能这样使用它:
<script type="module">
import { uniq } from 'https://cdn.jsdelivr.net/npm/lodash-es@4.17.15/lodash.min.js'
uniq([1,1,2]) // [1,2]
</script>
11. Fullscreen API
全屏(Fullscreen) API 的简单使用:
- 开启全屏:
elem.requestFullscreen()
- 退出全屏:
document.exitFullscreen()
demo 地址:codepen.io/zhangbao/pe…
12. 网页顺滑滚动的原生方案
实现网页顺滑滚动(smooth scroll)的原生方式有四种:
- html { scroll-behavior: smooth; }
- window.scroll({ behavior: 'smooth' })
- window.scrollBy({ behavior: 'smooth' })
- elem.scrollIntoView({ behavior: 'smooth' })
demo 地址:codepen.io/zhangbao/pe…
13. 原型链继承说明
JavaScript 中的原型链继承:
- 使用构造函数
Animal
生成的的实例对象(new Animal()
),其内部的[[Prototype]]
链(即__proto__
属性)指向Animal.prototype
。 - ES6 类继承语法
class Rabbit extends Animal { ... }
实际做了两件事:Rabbit.prototype
内部的[[Prototype]]
链指向Animal.prototype
,同时Rabbit
内部的[[Prototype]]
链指向Animal
继承细节见下图。
14. 派发自定义事件
使用 new CustomEvent()
和 target.dispatchEvent(event)
API 就能实现 DOM 元素上的自定义事件派发。
function fireEvent(name, target, detail) {
const event = new CustomEvent(name, {
bubbles: true,
detail,
});
target.dispatchEvent(event);
};
demo 地址:codepen.io/zhangbao/pe…
15. 整数与不同进制间的转换
我们可以使用 numObj.toString(radix)
方法将整数转为不同进制的字符串;同时,可以使用 parseInt(string, radix)
将不同进制的字符串转为十进制数字。
16. 在整数上调用方法会报错
JavaScript 中直接在整数上调用方法,会报错
1.toString() // Uncaught SyntaxError: Invalid or unexpected token
这是把调用方法时使用的点当成小数点了,避免报错发生的方式有三种:
- 用
String
函数显式转为字符串 - 数字与点之间空一格
- 数字后连续两个点
- 用圆括号包围数字
17. 复制文本
使用 JavaScript 复制文本分三步:
- 选择文本(
input.select()
) - 复制文本(
document.execCommand('copy')
) - 移除文本选择(
window.getSelection().removeAllRanges()
)
demo 地址:codepen.io/zhangbao/pe…
18. 检查空对象
JavaScript 中检查空对象的两种方式:
19. 输入框文本全选
实现输入框文本全选功能,有两个API可供选择:
HTMLInputElement.select()
HTMLInputElement.setSelectionRange()
<input onClick="this.select();" value="via select()" />
<input onClick="this.setSelectionRange(0, this.value.length)" value="via setSelectionRange()" />
demo 地址:codepen.io/zhangbao/pe…
20. 一个解构赋值知识点
你可能不知道的解构赋值知识点:
- 扩展运算符的解构赋值,只能复制目标对象的自身属性
- 单纯的解构赋值,可以复制目标对象继承的属性
21. URLSearchParams API
URLSearchParams API 可以用来操作浏览器地址栏里的 url 参数。
以 "example.com/?q=URLUtils…" 为例。先来初始化下:
var searchParams = new URLSearchParams(location.search)
再来操作:
- 获取参数:
searchParams.get('topic') // 'api'
- 添加/更新参数:
searchParams.set('topic', 'More webdev')
- 当前参数:
searchParams.toString() // "q=URLUtils.searchParams&topic=More+webdev"
- 删除参数:
searchParams.delete('topic')
- 是否包含参数:
searchParams.has('topic') // false
searchParams.toString() // "q=URLUtils.searchParams"
参考链接:developer.mozilla.org/en-US/docs/…
CSS
22. 响应式字体设置
可以使用 vw
和 @media
查询实现网站字体尺寸的响应式设置。
html {
font-size: 1.6666666666666667vw;
}
@media (max-width: 600px) {
html {
font-size: 14px;
}
}
@media (max-width: 400px) {
html {
font-size: 17px;
}
}
23. attr() 功能函数
我们可以在伪元素(比如 ::after
)的 content
属性里使用 attr()
函数获取元素属性值,而且还支持使用空格做字符串连接。
demo 链接:codepen.io/zhangbao/pe…
24. background-clip 干什么的?
CSS background-clip
用于限定只让在哪个区域的背景可见。可取值包括:border-box
、padding-box
、content-box
和有趣的 text。
取值 padding-box
,表示只让在 padding box 区域内的背景可见,border-box
(默认值)和 content-box
作用类似;当取值 text
时(就比较有趣了),表示只在文本区域内的背景是可见,或者说“文本被背景填充了”,不过需要把文本颜色设置成透明的(transparent
)才能看到效果。
demo 地址:codepen.io/zhangbao/fu…
25. auto-fit
与 auto-fill
的区别
Grid 布局中 auto-fit
与 auto-fill
关键字的区别。
1fr
情况:auto-fill
会尽可能多的,在可用空间内分配更多 grid item 坑位;auto-fit
则尽可能拉伸当前的 grid item ,以便填充可用空间。- 固宽情况:
auto-fill
在空间充裕的情况下会分配额外的 grid item 坑位;auto-fit
则不会。
demo 地址:codepen.io/zhangbao/pe…
26. 百分比 padding 的计算依据
CSS 百分比 padding
是依据父元素的 width
计算的。如下图所示,Child 的 padding-top: 25%
,最终解析为 400 * 0.25,也就是 100px
。
demo 地址:codepen.io/zhangbao/pe…
27. text-decoration-skip-ink
CSS text-decoration-skip-ink
属性用于设置,下划线经过字符突出的上/下边缘时,是自动跳过还是直接穿过。
28. text-decoration-style
text-decoration-style
有 5 个可能的取值:solid
、double
、dotted
、dashed
和 wavy
。渲染结果如下:
demo 地址:codepen.io/zhangbao/pe…
29. 使用 scaleX(-1)/scaleY(-1) 实现翻转功能
使用 scaleX(-1)
/scaleY(-1)
实现元素在 X轴/Y轴 方向上的翻转。
demo 地址:codepen.io/zhangbao/pe…
30. :placeholder-shown
:placeholder-shown
与 <input>
的 <textarea>
的 placeholder
属性有关。当输入框中的占位文本显示时,就匹配这个输入框。有几个边缘情况,需要注意:
demo 地址:codepen.io/zhangbao/pe…
31. 逻辑属性:inline-size、block-size
inline-size
、block-size
属性的含义与网页的书写模式(writing-mode
)有关。以文字排版为例:
- 文字书写的方向称为 x/inline 轴,元素在这个轴上占据的尺寸称为 inline size。
- 文字折行的方向称为 y/block 轴,元素在这个轴上占据的尺寸称为 block size。
因此这两个属性跟 width
、height
存在某种对应关系:
- 在默认书写模式(
writing-mode: horizontal-tb;
)下,width = inline-size,height = block-size - 而在垂直书写模式下(比如
writing-mode: vertical-rl;
)下,width = block-size,height = inline-size
demo 地址:codepen.io/zhangbao/pe…
32. clip-path
使用 clip-path
属性裁剪元素的两种方式:
demo 地址:codepen.io/zhangbao/fu…
33. :nth-child 与 :nth-of-type 的区别
:nth-child(1)
与 :nth-of-type(1)
的区别:
span:nth-child(1)
匹配的是:1. <span>
;2. 是父元素的第一个孩子。判断条件使用 JS 表达是下面这样的:
if (parent.children[0] && parent.children[0].tagName === 'SPAN') {
/* 为元素应用样式... */
}
a:nth-of-type(1)
匹配的是:在父元素范围内第一个出现的 <a>
,查找逻辑使用 JS 表达是下面这样的:
if (document.querySelectorAll('.nav > a')[0]) {
/* 为元素应用样式... */
}
demo 地址:codepen.io/zhangbao/pe…
34. Flex 项目的内容尺寸 & 基础尺寸
Flex 项目的最终渲染尺寸是基于内容尺寸/基础尺寸进行的:
- 当 Flex 项目设置了
flex-basis
或width
(同时设置时,flex-basis
优先级高于width
)时,它是基于此基础尺寸缩减/增长的。 - 当 Flex 项目未设置
flex-basis
或width
时,则是基于内容尺寸(max-content
)缩减/增长的。
demo 地址(Firefox 中打开观察):codepen.io/zhangbao/fu…
35. 区分鼠标聚焦和 Tab 键索引聚焦
:focus-visible
伪类可以区分一个元素是通过鼠标点击聚焦的,还是通过 Tab 键索引聚焦的。
这样就能实现以下的交互效果——点击 <button>
时不会出现 outline,而用 Tab 键索引时出现 outline。
demo 地址:codepen.io/zhangbao/pe…
36. writing-mode
在不同的 writing-mode
取值下,文字排版(文档流)方向的表现:
demo 地址:codepen.io/zhangbao/fu…
37. Grid 项目最终渲染尺寸
使用了 grid-template-columns: 1fr 1fr
之后,就能保证两个 Grid 项目一样宽吗?不一定。
如果一个 Grid 项目的 min-content
大于最终计算出来的 1fr
的值,那么这个 Grid 项目最终渲染尺寸是 min-content
。
demo 地址:codepen.io/zhangbao/fu…
38. visibility 属性
CSS 的 visibility
属性有一个有趣的地方——父元素 visibility: hidden
,子元素 visibility: visible
,最终的呈现效果是:父元素不可见,这个子元素却是可见的。
demo 地址:codepen.io/zhangbao/fu…
39. text-decoration 是个复合属性
CSS 中的 text-decoration
是个复合属性,语法如下:
text-decoration: <'text-decoration-line'> || <'text-decoration-style'> || <'text-decoration-color'>
其中每个单独属性的初始值如下:
text-decoration-line: none
text-decoration-style: solid
text-decoration-color: currentcolor
就是说,当我们使用 text-decoration: underline
的时候,实际作用的是 text-decoration: underline solid currentcolor
。
链接:developer.mozilla.org/en-US/docs/…
HTML
40. rel="nofollow"
某些个人网站上会出现一些垃圾评论外链,有些外链的目的是为了提高自己网站的搜索引擎排名。
为了告知搜索引擎此外链不被网站信任,无需计入搜索排名。可以这样做:
<a rel="nofollow" target="_blank">
更进一步,添加避免本页面被外链网页操作的代码:
<a rel="nofollow noopener noreferrer" target="_blank">
41. rel="noopener noreferrer"
在当前页面使用 <a target="_blank">
或 window.open()
打开新页面时,如果不做特殊处理,在新页面中可以使用 window.opener
访问当前页面的 window
对象。
后果是在新页面中能够重置当前页面的 url 地址:window.opener.location = 'evil.com'
为了避免这类事情发生,我们可以使用下图的做法。
参考链接:mathiasbynens.github.io/rel-noopene…
(完)