常见的水平垂直方式有几种?
代码语言:html复制//利用绝对定位,先将元素的左上角通过 top:50%和 left:50%定位到页面的中心,然后再通过 translate 来调整元素的中心点到页面的中心。该方法需要考虑浏览器兼容问题。
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
//利用绝对定位,设置四个方向的值都为 0,并将 margin 设置为 auto,由于宽高固定,因此对应方向实现平分,可以实现水平和垂直方向上的居中。该方法适用于盒子有宽高的情况:
.parent {
position: relative;
}
.child {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
//利用绝对定位,先将元素的左上角通过 top:50%和 left:50%定位到页面的中心,然后再通过 margin 负值来调整元素的中心点到页面的中心。该方法适用于盒子宽高已知的情况
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px; /* 自身 height 的一半 */
margin-left: -50px; /* 自身 width 的一半 */
}
//使用 flex 布局,通过 align-items:center 和 justify-content:center 设置容器的垂直和水平方向上为居中对齐,然后它的子元素也可以实现垂直和水平的居中。该方法要**考虑兼容的问题**,该方法在移动端用的较多:
.parent {
display: flex;
justify-content:center;
align-items:center;
}
//另外,如果父元素设置了flex布局,只需要给子元素加上`margin:auto;`就可以实现垂直居中布局
.parent{
display:flex;
}
.child{
margin: auto;
}
----问题知识点分割线----
代码输出结果
代码语言:javascript复制const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);
输出结果如下:
代码语言:javascript复制1
2
4
timerStart
timerEnd
success
代码执行过程如下:
- 首先遇到Promise构造函数,会先执行里面的内容,打印
1
; - 遇到定时器
steTimeout
,它是一个宏任务,放入宏任务队列; - 继续向下执行,打印出2;
- 由于
Promise
的状态此时还是pending
,所以promise.then
先不执行; - 继续执行下面的同步任务,打印出4;
- 此时微任务队列没有任务,继续执行下一轮宏任务,执行
steTimeout
; - 首先执行
timerStart
,然后遇到了resolve
,将promise
的状态改为resolved
且保存结果并将之前的promise.then
推入微任务队列,再执行timerEnd
; - 执行完这个宏任务,就去执行微任务
promise.then
,打印出resolve
的结果。
----问题知识点分割线----
函数柯里化
柯里化(currying) 指的是将一个多参数的函数拆分成一系列函数,每个拆分后的函数都只接受一个参数。
对于已经柯里化后的函数来说,当接收的参数数量与原函数的形参数量相同时,执行原函数; 当接收的参数数量小于原函数的形参数量时,返回一个函数用于接收剩余的参数,直至接收的参数数量与形参数量一致,执行原函数。
----问题知识点分割线----
对浏览器的缓存机制的理解
浏览器缓存的全过程:
- 浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时对比使用;
- 下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用 expires 头判断是否过期;
- 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的请求;
- 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;
- 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200;
很多网站的资源后面都加了版本号,这样做的目的是:每次升级了 JS 或 CSS 文件后,为了防止浏览器进行缓存,强制改变版本号,客户端浏览器就会重新下载新的 JS 或 CSS 文件 ,以保证用户能够及时获得网站的最新更新。
----问题知识点分割线----
如何避免ajax数据请求重新获取
一般而言,ajax请求的数据都放在redux中存取。
----问题知识点分割线----
Promise.resolve
代码语言:javascript复制Promise.resolve = function(value) {
// 1.如果 value 参数是一个 Promise 对象,则原封不动返回该对象
if(value instanceof Promise) return value;
// 2.如果 value 参数是一个具有 then 方法的对象,则将这个对象转为 Promise 对象,并立即执行它的then方法
if(typeof value === "object" && 'then' in value) {
return new Promise((resolve, reject) => {
value.then(resolve, reject);
});
}
// 3.否则返回一个新的 Promise 对象,状态为 fulfilled
return new Promise(resolve => resolve(value));
}
----问题知识点分割线----
数组去重
使用 indexOf/includes 实现
代码语言:javascript复制function unique(arr) {
var res = [];
for(var i = 0; i < arr.length; i ) {
if(res.indexOf(arr[i]) === -1) res.push(arr[i]);
// if(!res.includes(arr[i])) res.push(arr[i]);
}
return res;
}
使用 filter(forEach) indexOf/includes 实现
代码语言:javascript复制// filter
function unique(arr) {
var res = arr.filter((value, index) => {
// 只存第一个出现的元素
return arr.indexOf(value) === index;
});
return res;
}
// forEach
function unique(arr) {
var res = [];
arr.forEach((value) => {
if(!res.includes(value)) res.push(value);
});
return res;
}
非 API 版本(原生)实现
代码语言:javascript复制function unique(arr) {
var res = [];
for(var i = 0; i < arr.length; i ) {
var flag = false;
for(var j = 0; j < res.length; j ) {
if(arr[i] === res[j]) {
flag = true;
break;
}
}
if(flag === false) res.push(arr[i]);
}
return res;
}
ES6 使用 Set 扩展运算符(...)/Array.from() 实现
代码语言:javascript复制function unique(arr) {
// return [...new Set(arr)];
return Array.from(new Set(arr));
}
----问题知识点分割线----
documentFragment 是什么?用它跟直接操作 DOM 的区别是什么?
MDN中对documentFragment
的解释:
DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。
当我们把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。在频繁的DOM操作时,我们就可以将DOM元素插入DocumentFragment,之后一次性的将所有的子孙节点插入文档中。和直接操作DOM相比,将DocumentFragment 节点插入DOM树时,不会触发页面的重绘,这样就大大提高了页面的性能。
----问题知识点分割线----
写版本号排序的方法
题目描述:有一组版本号如下'0.1.1', '2.3.3', '0.302.1', '4.2', '4.3.5', '4.3.4.5'。现在需要对其进行排序,排序的结果为 '4.3.5','4.3.4.5','2.3.3','0.302.1','0.1.1'
实现代码如下:
代码语言:javascript复制arr.sort((a, b) => {
let i = 0;
const arr1 = a.split(".");
const arr2 = b.split(".");
while (true) {
const s1 = arr1[i];
const s2 = arr2[i];
i ;
if (s1 === undefined || s2 === undefined) {
return arr2.length - arr1.length;
}
if (s1 === s2) continue;
return s2 - s1;
}
});
console.log(arr);
----问题知识点分割线----
谈一谈队头阻塞问题
什么是队头阻塞?
对于每一个HTTP请求而言,这些任务是会被放入一个任务队列中串行执行的,一旦队首任务请求太慢时,就会阻塞后面的请求处理,这就是HTTP队头阻塞
问题。
有什么解决办法吗