# 前端面试题及答案汇总(七) 71-80
# 第 71 题: 实现一个字符串匹配算法,从长度为 n 的字符串 S 中,查找是否存在字符串 T,T 的长度是 m,若存在返回所在位置。
var findStr = function(S, T) {
if (T.length > S.length) {
return -1;
}
if(T === '' && S !== '') {
return -1;
}
S = String(S);
T = String(T);
let m = S.length;
let n = T.length;
let p = 0;
while(p + n <= m) {
let temp = S.slice(p, p + n);
if(temp === T) {
return p;
}
p++;
}
return -1;
}
findStr('asdfqwer', '')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 第 72 题: 为什么普通 for 循环的性能远远高于 forEach 的性能,请解释其中的原因。
- for 循环当然是最简单的,因为它没有任何额外的函数调用栈和上下文;
- forEach 其次,因为它其实比我们想象得要复杂一些,它的函数签名实际上是array.forEach(function(currentValue, index, arr), thisValue)它不是普通的 for 循环的语法糖,还有诸多参数和上下文需要在执行的时候考虑进来,这里可能拖慢性能;
- map 最慢,因为它的返回值是一个等长的全新的数组,数组创建和赋值产生的性能开销很大。
# 第 73 题: 介绍下 BFC、IFC、GFC 和 FFC
BFC(Block formatting contexts):块级格式上下文 页面上的一个隔离的渲染区域,那么他是如何产生的呢?可以触发BFC的元素有float、position、overflow、display:table-cell/ inline-block/table-caption ;BFC有什么作用呢?比如说实现多栏布局’
IFC(Inline formatting contexts):内联格式上下文 IFC的line box(线框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的padding/margin影响)IFC中的line box一般左右都贴紧整个IFC,但是会因为float元素而扰乱。float元素会位于IFC与与line box之间,使得line box宽度缩短。 同个ifc下的多个line box高度会不同 IFC中时不可能有块级元素的,当插入块级元素时(如p中插入div)会产生两个匿名块与div分隔开,即产生两个IFC,每个IFC对外表现为块级元素,与div垂直排列。 那么IFC一般有什么用呢? 水平居中:当一个块要在环境中水平居中时,设置其为inline-block则会在外层产生IFC,通过text-align则可以使其水平居中。 垂直居中:创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。
GFC(GrideLayout formatting contexts):网格布局格式化上下文 当为一个元素设置display值为grid的时候,此元素将会获得一个独立的渲染区域,我们可以通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间。那么GFC有什么用呢,和table又有什么区别呢?首先同样是一个二维的表格,但GridLayout会有更加丰富的属性来控制行列,控制对齐以及更为精细的渲染语义和控制。
FFC(Flex formatting contexts):自适应格式上下文 display值为flex或者inline-flex的元素将会生成自适应容器(flex container),可惜这个牛逼的属性只有谷歌和火狐支持,不过在移动端也足够了,至少safari和chrome还是OK的,毕竟这俩在移动端才是王道。Flex Box 由伸缩容器和伸缩项目组成。通过设置元素的 display 属性为 flex 或 inline-flex 可以得到一个伸缩容器。设置为 flex 的容器被渲染为一个块级元素,而设置为 inline-flex 的容器则渲染为一个行内元素。伸缩容器中的每一个子元素都是一个伸缩项目。伸缩项目可以是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说,Flexbox 定义了伸缩容器内伸缩项目该如何布局。
# 第 74 题: 使用 JavaScript Proxy 实现简单的数据绑定
<body>
hello,world
<input type="text" id="model">
<p id="word"></p>
</body>
<script>
const model = document.getElementById("model")
const word = document.getElementById("word")
var obj= {};
const newObj = new Proxy(obj, {
get: function(target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
console.log('setting',target, key, value, receiver);
if (key === "text") {
model.value = value;
word.innerHTML = value;
}
return Reflect.set(target, key, value, receiver);
}
});
model.addEventListener("keyup",function(e){
newObj.text = e.target.value
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 第 75 题:数组里面有10万个数据,取第一个元素和第10万个元素的时间相差多少
# 第 76 题:输出以下代码运行结果
这题考察的是对象的键名的转换。
- 对象的键名只能是字符串和 Symbol 类型。
- 其他类型的键名会被转换成字符串类型。
- 对象转字符串默认会调用 toString 方法。
// example 1
var a={}, b='123', c=123;
a[b]='b';
// c 的键名会被转换成字符串'123',这里会把 b 覆盖掉。
a[c]='c';
// 输出 c
console.log(a[b]);
2
3
4
5
6
7
8
9
// example 2
var a={}, b=Symbol('123'), c=Symbol('123');
// b 是 Symbol 类型,不需要转换。
a[b]='b';
// c 是 Symbol 类型,不需要转换。任何一个 Symbol 类型的值都是不相等的,所以不会覆盖掉 b。
a[c]='c';
// 输出 b
console.log(a[b]);
2
3
4
5
6
7
8
9
10
11
// example 3
var a={}, b={key:'123'}, c={key:'456'};
// b 不是字符串也不是 Symbol 类型,需要转换成字符串。
// 对象类型会调用 toString 方法转换成字符串 [object Object]。
a[b]='b';
// c 不是字符串也不是 Symbol 类型,需要转换成字符串。
// 对象类型会调用 toString 方法转换成字符串 [object Object]。这里会把 b 覆盖掉。
a[c]='c';
// 输出 c
console.log(a[b]);
2
3
4
5
6
7
8
9
10
11
12
13
# 第 77 题:算法题「旋转数组」
function rotate(arr, k) {
if(!arr || arr.length === 0) {
return null;
}
let len = arr.length;
let num = k % len;
return arr.splice(-num).concat(arr);
}
console.log(rotate([1,2,3,4,5,6],8))
2
3
4
5
6
7
8
9
# 第 78 题:Vue 的父组件和子组件生命周期钩子执行顺序是什么
# 第 79 题:input 搜索如何防抖,如何处理中文输入
# 第 80 题:介绍下 Promise.all 使用、原理实现及错误处理
function promiseAll(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject()
}
let count = 0;
let len = promises.length;
let res = new Array(len);
for (let i = 0; i < len; i++) {
(function (i) {
Promise.resolve(promises[i]).then((value) => {
count++;
res[i] = value;
if (count === len) {
return resolve(res);
}
}, (reason) => {
return reject(reason);
})
})(i)
}
})
}
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
promiseAll([p1, p2, p3]).then(function (value) {
console.log(value)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29