一、js
1. setTimeout 的运行机制
1.1 js的运行机制如下:
-
- 所有同步任务都在主线程上执行,形成一个
执行栈(Call Stack)
- 所有同步任务都在主线程上执行,形成一个
-
- 主线程之外,还存在一个
"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件
- 主线程之外,还存在一个
-
- 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
-
- 主线程不断重复上面的第三步。
1.2 setTimeout运行机制
setTimeout 和 setInterval的运行机制,其实就是将指定的代码移出本次执行,等到下一轮 Event Loop 时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮 Event Loop 时重新判断。
这意味着,setTimeout指定的代码,必须等到本次执行的所有同步代码都执行完,才会执行。
2. String.prototype.padStart
把指定字符串填充到字符串头部,返回新字符串。
str.padStart(targetLength [, padString])
targetLength
当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
padString可选
填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "
示例:
'abc'.padStart(10); // " abc"
'abc'.padStart(10, "foo"); // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0"); // "00000abc"
'abc'.padStart(1); // "abc"
应用场景
日期格式化:yyyy-mm-dd的格式:
const now = new Date()
const year = now.getFullYear()
// 月份和日期 如果是一位前面给它填充一个0
const month = (now.getMonth() + 1).toString().padStart(2, '0')
const day = (now.getDate()).toString().padStart(2, '0')
console.log(year, month, day)
console.log( `${year}-${month}-${day}` ) //输入今天的日期 2023-02-01
数字替换(手机号,银行卡号等)
const tel = '118378395882'
//银行卡
const newTel = tel.slice(-4).padStart(tel.length, '*')
console.log(newTel) // *******5882
//手机号隐藏中间 4位
const newTel1 = tel.slice(0,3)+tel.slice(-4).padStart(tel.length-3, '*')
console.log(newTel1) // 183****5882
3. String.prototype.padEnd
把指定字符串填充到字符串尾部,返回新字符串。 语法同上String.prototype.padStart
3.1 应用场景
在JS前端我们处理时间戳的时候单位是ms毫秒,但是,后端同学返回的时间戳则不一样是毫秒,可能只有10位,以s秒为单位。所以,我们在前端处理这个时间戳的时候,保险起见,要先做一个13位的补全,保证单位是毫秒。
timestamp = +String(timestamp).padEnd(13, '0')
4. for await of
异步迭代器(for-await-of):循环等待每个Promise对象变为resolved状态才进入下一步。
4.1 for...of 是同步运行的
function TimeOut(time){
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for (let item of arr) {
console.log(Date.now(),item.then(console.log))
}
}
test()
上述代码证实了 for of 方法不能遍历异步迭代器,得到的结果并不是我们所期待的,于是 for await of 就粉墨登场啦!
4.2 for...await...of
ES9 中可以用 for...await...of 的语法来操作
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for await (let item of arr) {
console.log(Date.now(), item)
}
}
test()
// 1675240005623 2000
// 1675240005624 1000
// 1675240006617 3000
5. 空值合并运算符(Nullish coalescing Operator)
空值合并操作符( ?? )是一个逻辑操作符,当左侧的操作数为 null或者undefined时,返回其右侧操作数,否则返回左侧操作数。
const foo = undefined ?? "foo"
const bar = null ?? "bar"
console.log(foo) // foo
console.log(bar) // bar
与逻辑或操作符(||)不同,逻辑或操作符会在左侧操作数为假值时返回右侧操作数。也就是说,如果使用 || 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如'',0,NaN,false)时。见下面的例子。
const foo = "" ?? 'default string';
const foo2 = "" || 'default string';
console.log(foo); // ""
console.log(foo2); // "default string"
const baz = 0 ?? 42;
const baz2 = 0 || 42;
console.log(baz); // 0
console.log(baz2); // 42
5.1 注意点
将 ?? 直接与 AND(&&)和 OR(||)操作符组合使用是不可取。
6. 可选链 Optional chaining
6.1 介绍
可选链操作符( ?. )允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。
const user = {
address: {
street: 'xx街道',
getNum() {
return '80号'
}
}
}
const street = user && user.address && user.address.street
const num = user && user.address && user.address.getNum && user.address.getNum()
console.log(street, num)
用了 Optional Chaining ,上面代码会变成
const user = {
address: {
street: 'xx街道',
getNum() {
return '80号'
}
}
}
const street2 = user?.address?.street
const num2 = user?.address?.getNum?.()
console.log(street2, num2)
可选链中的 ? 表示如果问号左边表达式有值, 就会继续查询问号后面的字段。根据上面可以看出,用可选链可以大量简化类似繁琐的前置校验操作,而且更安全。
6.2 与空值合并操作符一起使用
let customer = {
name: "jimmy",
details: { age: 18 }
};
let customerCity = customer?.city ?? "广州";
console.log(customerCity); // "广州"
6.3 注意点
可选链不能用于赋值
7.1 globalThis
在以前,从不同的 JavaScript 环境中获取全局对象需要不同的语句。在 Web 中,可以通过 window、self 取到全局对象,在 Node.js 中,它们都无法获取,必须使用 global。
在松散模式下,可以在函数中返回 this 来获取全局对象,但是在严格模式和模块环境下,this 会返回 undefined。
以前想要获取全局对象,可通过一个全局函数
const getGlobal = () => {
if (typeof self !== 'undefined') {
return self
}
if (typeof window !== 'undefined') {
return window
}
if (typeof global !== 'undefined') {
return global
}
throw new Error('无法找到全局对象')
}
const globals = getGlobal()
console.log(globals)
现在globalThis 提供了一个标准的方式来获取不同环境下的全局 this 对象(也就是全局对象自身)。不必担心它的运行环境。全局作用域中的 this 就是globalThis。
8. 数字分隔符
欧美语言中,较长的数值允许每三位添加一个分隔符(通常是一个逗号),增加数值的可读性。比如,1000可以写作1,000。
ES2021中允许 JavaScript 的数值使用下划线(_)作为分隔符。
- 值分隔符没有指定间隔的位数
- 小数和科学计数法也可以使用数值分隔符
数值分隔符有几个使用注意点。
- 不能放在数值的最前面(leading)或最后面(trailing)。
- 不能两个或两个以上的分隔符连在一起。
- 小数点的前后不能有分隔符。
- 科学计数法里面,表示指数的
e或E前后不能有分隔符。
9. 请求的 Content-Type
HTTP中,提交数据的方式,最常用的就是GET和POST。
GET方式,是把参数按键值对通过QueryString的方式放在URL尾部,比如: http://www.example.com/test.html?a=1&b=2
POST方法,通常是把要提交的表单放在一个Form中,指明action后就可以提交数据。
提交数据时需要通过表单enctype属性(规定在发送到服务器之前应该如何对表单数据进行编码)根据content type进行编码。
并且,如果是GET,用”?”连接,编码方式为“application/x-www-form-urlencoded”;如果是POST,则根据enctype属性确定content type,默认也为”application/x-www-form-urlencoded”。
9.1 关于Content-Type
在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。浏览器会在某些情况下进行MIME嗅探,并不一定遵循此标题的值; 为了防止这种行为,可以将标题 X-Content-Type-Options 设置为 nosniff。
在请求中 (如POST 或 PUT),客户端告诉服务器实际发送的数据类型。
语法
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something[1 to 70 characters]
media-type 资源或数据的 media type
charset 字符编码标准
boundary 对于多部分(multipart)实体,boundary 是必需的,它用于封装消息的多个部分的边界。其由1到70个字符组成,浏览器自动生成,该字符集对于通过网关鲁棒性良好,不以空白结尾。
10. 遍历数组的方式
这张图涵盖了数组大部分的方法
10.1 for
标准的for循环语句,也是最传统的循环语句
var arr = [1,2,3,4,5]
for(var i=0;i<arr.length;i++){
console.log(arr[i])
}
最简单的一种遍历方式,也是使用频率最高的,性能较好,但还能优化
优化版for循环语句
var arr = [1,2,3,4,5]
for(var i=0,len=arr.length;i<len;i++){
console.log(arr[i])
}
使用临时变量,将长度缓存起来,避免重复获取数组长度,尤其是当数组长度较大时优化效果才会更加明显。
这种方法基本上是所有循环遍历方法中性能最高的一种
10.2 for...in
任意顺序遍历一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。
一般常用来遍历对象,包括非整数类型的名称和继承的那些原型链上面的属性也能被遍历。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性就不能遍历了.
var arr = [1,2,3,4,5]
for(var i in arr){
console.log(i,arr[i])
} //这里的i是对象属性,也就是数组的下标
/**
0 1
1 2
2 3
3 4
4 5 **/
10.3 for...of(不能遍历对象)
在可迭代对象(具有 iterator 接口)(Array,Map,Set,String,arguments)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句,不能遍历对象
let arr=["前端","面试题宝典","真好用"];
for (let item of arr){
console.log(item)
}
//遍历对象
let person={name:"alex",age:18,city:"上海"}
for (let item of person){
console.log(item)
}
// 我们发现它是不可以的 我们可以搭配Object.keys使用
for(let item of Object.keys(person)){
console.log(person[item])
}
// alex 18 上海
这种方式是es6里面用到的,性能要好于forin,但仍然比不上普通for循环
10.4 reduce
reduce()方法对数组中的每个元素执行一个由你提供的reducer函数(升序执行),将其结果汇总为单个返回值
const arr = [1,2,3,4]
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4 = 10
console.log('arr',arr1.reduce(reducer));
10.5 数组遍历各个方法的速度:传统的for循环最快,for-in最慢
for-len
>for>for-of>forEach>map>for-in
javascript原生遍历方法的建议用法:
- 用
for循环遍历数组 - 用
for...in遍历对象 - 用
for...of遍历类数组对象(ES6) - 用
Object.keys()获取对象属性名的集合
为何for… in会慢?
因为for … in语法是第一个能够迭代对象键的JavaScript语句,循环对象键({})与在数组([])上进行循环不同,引擎会执行一些额外的工作来跟踪已经迭代的属性。因此不建议使用for...in来遍历数组
二、css
2. css来实现禁止移动端页面的左右划动手势
CSS属性 touch-action 用于设置触摸屏用户如何操纵元素的区域(例如,浏览器内置的缩放功能)。
html{
touch-action: none;
touch-action: pan-y;
}
2.2 opacity: 0、visibility: hidden、display: none 优劣和适用场景
2.21 结构
display:none: 会让元素完全从渲染树中消失,渲染的时候不占据任何空间, 不能点击, visibility: hidden:不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,不能点击 opacity: 0: 不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,可以点击
2.22 继承
display: none和opacity: 0:是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示。 visibility: hidden:是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式。
2.23 性能
display: none : 修改元素会造成文档回流,读屏器不会读取display: none元素内容,性能消耗较大 visibility:hidden: 修改元素只会造成本元素的重绘,性能消耗较少读屏器读取visibility: hidden元素内容 opacity: 0 :修改元素会造成重绘,性能消耗较少
3. 使用css完成视差滚动效果
3.1 视差滚动(Parallax Scrolling)是指多层背景以不同的速度移动,形成立体的运动效果,带来非常出色的视觉体验
3.2 实现方式
使用css形式实现视觉差滚动效果的方式有:
- background-attachment
- transform:translate3D
3.21 background-attachment
作用是设置背景图像是否固定或者随着页面的其余部分滚动
值分别有如下:
- scroll:默认值,背景图像会随着页面其余部分的滚动而移动
- fixed:当页面的其余部分滚动时,背景图像不会移动
- inherit:继承父元素background-attachment属性的值
完成滚动视觉差就需要将background-attachment属性设置为fixed,让背景相对于视口固定。即使一个元素有滚动机制,背景也不会随着元素的内容而滚动
也就是说,背景一开始就已经被固定在初始的位置
section {
height: 100vh;
}
.g-img {
background-image: url(...);
background-attachment: fixed;
background-size: cover;
background-position: center center;
}
3.22 transform:translate3D
同样,让我们先来看一下两个概念transform和perspective:
- transform: css3 属性,可以对元素进行变换(2d/3d),包括平移 translate,旋转 rotate,缩放 scale,等等
- perspective: css3 属性,当元素涉及 3d 变换时,perspective 可以定义我们眼睛看到的 3d 立体效果,即空间感
<style>
html {
overflow: hidden;
height: 100%
}
body {
/* 视差元素的父级需要3D视角 */
perspective: 1px;
transform-style: preserve-3d;
height: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
#app{
width: 100vw;
height:200vh;
background:skyblue;
padding-top:100px;
}
.one{
width:500px;
height:200px;
background:#409eff;
transform: translateZ(0px);
margin-bottom: 50px;
}
.two{
width:500px;
height:200px;
background:#67c23a;
transform: translateZ(-1px);
margin-bottom: 150px;
}
.three{
width:500px;
height:200px;
background:#e6a23c;
transform: translateZ(-2px);
margin-bottom: 150px;
}
</style>
<div id="app">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
</div>
transform实现视觉差动的原理如下:
- 容器设置上 transform-style: preserve-3d 和 perspective: xpx,那么处于这个容器的子元素就将位于3D空间中,
- 子元素设置不同的 transform: translateZ(),这个时候,不同元素在 3D Z轴方向距离屏幕(我们的眼睛)的距离也就不一样
- 滚动滚动条,由于子元素设置了不同的 transform: translateZ(),那么他们滚动的上下距离 translateY 相对屏幕(我们的眼睛),也是不一样的,这就达到了滚动视差的效果
4. 让Chrome支持小于12px 的文字
解决方案有:
- zoom
- -webkit-transform:scale()
- -webkit-text-size-adjust:none
4.1 Zoom
zoom 的字面意思是“变焦”,可以改变页面上元素的尺寸,属于真实尺寸
其支持的值类型有:
- zoom:50%,表示缩小到原来的一半
- zoom:0.5,表示缩小到原来的一半
使用 zoom 来”支持“ 12px 以下的字体
.div{
font-size: 12px;
display: inline-block;
zoom: 0.8;
}
4.2 -webkit-transform:scale()
针对chrome浏览器,加webkit前缀,用transform:scale()这个属性进行放缩
注意的是,使用scale属性只对可以定义宽高的元素生效,所以,下面代码中将span元素转为行内块元素:
.span{
font-size: 12px;
display: inline-block;
-webkit-transform:scale(0.8);
}
4.3 -webkit-text-size-adjust:none
该属性用来设定文字大小是否根据设备(浏览器)来自动调整显示大小
属性值:
- percentage:字体显示的大小;
- auto:默认,字体大小会根据设备/浏览器来自动调整;
- none:字体大小不会自动调整
4.4 总结
Zoom 非标属性,有兼容问题,缩放会改变了元素占据的空间大小,触发重排
-webkit-transform:scale() 大部分现代浏览器支持,并且对英文、数字、中文也能够生效,缩放不会改变了元素占据的空间大小,页面布局不会发生变化