前端面试笔试题
Liuyi 2020-10-28 面试,JS
# 前端面试笔试题
# 手写防抖,节流函数
防抖,规定时间间隔内内只执行一次。
function debounce(fn, delay) {
let timer;
return function() {
let _this = this
let ars = arguments
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(function(){
fn.apply(_this, ars);
},delay);
}
}
function testdebounce() {
console.log('test')
}
var testdebounceFn = debounce(testdebounce, 1000)
document.onmousemove = () => {
testdebounceFn();
}
//
1
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
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
节流: 任务频繁触发下只有任务触发的间隔超过指定间隔的时候,任务才会触发。
function debounce(fn, delay) {
let timer;
return function() {
let _this = this
let ars = arguments
if(timer) {
return;
}
timer = setTimeout(function(){
fn.apply(_this, ars);
timer = null
},delay);
}
}
function testdebounce() {
console.log('test')
}
var testdebounceFn = debounce(testdebounce, 1000)
document.onmousemove = () => {
testdebounceFn();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 三个对象合并成一个对象,对象的解构赋值
let obj1 = { a:1, name: ‘mock’ }
let obj2 = { b:2, name: 'mock2' }
let obj3 = { c:3, age: '12' }
let obj4 = { ...obj1, ...obj2 , ...obj3 }
//浅复制 //同名属性会覆盖
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 一个数字,里面的成员都是对象,去重。
let list = [
{ “id”: 1, “name”: “abc”},
{ “id”: 2, "name”: “abcd”},
{ "id": 3, "name": "abc"},
{ "id": 4, 'name': "abc"}
]
function merge(arr) {
let er = []
let res = []
for ( let item of arr ) {
if( er.indexOf(item.name) == -1 ) {
er.push(item.name)
res.push(item)
}
}
return res;
}
let test = merge(list);
console.log(test)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 将一个一维数组或者二维数组转换成二维数组
let list = [
{ "id": 0, pid: 0, "name": "abc", title: 'title1'},
{ "id": 1, pid: 0, "name": "abcd", title: 'title2'},
{ "id": 2, pid: 1, "name": "abc1", title: 'title3'},
{ "id": 3, pid: 1, 'name': "abc2", title: 'title4'},
{ "id": 4, pid: 2, "name": "abc3", title: 'title5'},
{ "id": 5, pid: 5, 'name': "abc4", title: 'title6'}
]
list = [
[
{ "id": 0, pid: 0, "name": "abc", title: 'title1'
, children: []
},
{ "id": 1, pid: 0, "name": "abcd",, title: 'title2'
children: [
{ "id": 2, pid: 1, "name": "abc", title: 'title3'
, children: []
},
{ "id": 3, pid: 1, 'name': "abc",
, title: 'title4'
children: [
{ "id": 4, pid: 2, "name": "abc",, title: 'title5'},
]
},
]
},
],
[
{
"id": 5,
pid: 5,
'name': "abc4",
title: 'title6',
children: []
}
]
]
1
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
30
31
32
33
34
35
36
37
38
39
40
41
42
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
30
31
32
33
34
35
36
37
38
39
40
41
42
# 二叉树递归(深拷贝),并且记录路径 。
# Vue 手写一个Vue 双向绑定。
# JS除去字符串两端的空格
str = str.replace(/^s*|s*$/g,"");
1
# 怎么实现事件代理,vue怎么实现事件代理
# 实现函数柯里化
function createCurry(func, args) {
var arity = func.length;
var args = args || [];
return function() {
var _args = [].slice.call(arguments);
[].push.apply(_args, args);
// 如果参数个数小于最初的func.length,则递归调用,继续收集参数
if (_args.length < arity) {
return createCurry.call(this, func, _args);
}
// 参数收集完毕,则执行func
return func.apply(this, _args);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
1
2
3
2
3
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
var _args = [].slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var adder = function () {
var _adder = function() {
// [].push.apply(_args, [].slice.call(arguments));
_args.push(...arguments);
return _adder;
};
// 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return _adder;
}
// return adder.apply(null, _args);
return adder(..._args);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 将数组array划分成length为size的几个子数组
/**
* chunk(['a', 'b', 'c', 'd'], 2)
* // => [['a', 'b'], ['c', 'd']]
*
* chunk(['a', 'b', 'c', 'd'], 3)
* // => [['a', 'b', 'c'], ['d']]
*/
function chunk(arr, size) {
size = Math.max(size, 0);
let length = arr == null ? 0 : arr.length;
let resLength = Math.ceil(length/size);
let index = 0;
let resIndex = 0;
console.log(resLength)
let res = []
while( resIndex < resLength) {
res[resIndex] = arr.slice(index, index + size);
resIndex++;
index = index + size;
}
return res;
}
console.log(chunk(['a', 'b', 'c', 'd'], 3));
1
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
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
# 生成一个长度为5的数组,数组每个成员都是2~32之间,且不重复,不可以使用for循环跟while,使用递归
let res = Array(5);
let index = 0;
let num = getRandomInt();
function deepRandom(arr, num) {
if(arr.indexOf(num) < 0) {
arr[index] = num;
index++
} else {
num = getRandomInt()
}
if(index >= arr.length) {
console.log(arr)
return;
} else {
deepRandom(arr, num)
}
}
function getRandomInt() {
return random = Math.floor(Math.random() * 31 + 2);
}
deepRandom(res,num);
1
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
30
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
30
# 去掉字符串当中最后一个指定的字符
let str = "abdhdgshajdgsadshadjjj”;
function delateStr (str, del) {
if(typeof str === 'string') {
return str.split('').reverse().join('').replace(del,'').split('').reverse().join('');
} else {
console.log('请输入字符串');
}
}
console.log(delateStr(str,'d'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 将下划线命名法变成大驼峰命名法
function demoStr (str) {
let strarr = str.split('_');
let tes = strarr.map(element => {
return element.slice(0,1).toUpperCase() + element.slice(1).toLowerCase();
});
return tes.join('');
}
console.log(demoStr('my_name'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 统计某一字符或字符串在另一个字符串中出现的次数
function somestr (str, target) {
let length = str.length;
let count = target.length;
let sum = 0;
for(let i = 0; i < length - count; i++) {
if(str.slice(i,i + count) == target) {
sum++
}
}
return sum;
}
let sum = somestr('aabbccdbbcdebbceff', 'c');
console.log(sum)
//别人的答案:
parent.split(child).length - 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 写一个判断数据类型的方法。
function type (obj) {
return Object.prototype.toString.call(obj).replace(/\[object\s|\]/g,'');
}
// 问题的关键在于 typeof不能检测出 object 跟 array
1
2
3
4
5
6
2
3
4
5
6
# 写一个简单的字符串加密方法
// 利用 base64, 浏览器环境自带 btoa / atob 方法
// Node.js 需要引入相关库
const str = "abcdefg";
console.log(btoa(str));
console.log(atob(btoa(str)));
// 凯撒密码
const encodeCaesar = ({str = "", padding = 3}) =>
!str
? str
: str
.split("")
.map((s) => String.fromCharCode(s.charCodeAt() + padding))
.join("");
const decodeCaesar = ({str = "", padding = 3}) =>
!str
? str
: str
.split("")
.map((s) => String.fromCharCode(s.charCodeAt() - padding))
.join("");
console.log(encodeCaesar({str: “hello world”}));
console.log(decodeCaesar({str: "khoor#zruog"}));
1
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
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
# 简单描述下什么是回调函数
function(callback,url) {
callback();
}
1
2
3
2
3
# 写一个除去制表符跟换行符的方法
const removeSymbol = (str) => str.replace(/\t|\n|\v|\r|\f/g, "");
1
2
2
# 写一个返回顶部的方法
1. 利用 a 标签的锚点。在顶部放一个 a 标签 <a name=“top”>顶部</a>,在需要回到顶部的位置放置一个 a 标签,地址为 top。 <a href="#top">回到顶部</a>。要做成隐藏的锚点,可以把内部的内容去掉,name 是必须的。
2. 利用 #,在 url 后增加 # 不会让页面刷新,并且可以回到顶部。可以对 location.href 进行设置 location.href += '#'。当这个方法执行多次即有多个 # 时,页面不会有响应。
3. 利用 javascript 设置 scrollTop = 0,一般设置在最外层,即 document.documentElement.scrollTop = 0 就可以返回顶部。
1
2
3
2
3
# 数组去重包含多维数组
arr = [1, 2, 3, [1, 2, [3, 4]], [1]]
//降维
function flatcopy(arr2) {
var res = [];
arr2.forEach(element => {
if(Object.prototype.toString.call(element) == '[object Array]') {
res = res.concat(flatcopy(element))
} else {
res.push(element)
}
});
return res;
}
//去重
function uniq (arr) {
var res = []
arr.forEach(element => {
if(res.indexOf(element) == -1) {
res.push(element)
}
})
return res;
}
//es6
//降维
let res = arr.flat(Infinity)
//去重
let res2 = new Set(res)
console.log([...res2])
console.log(uniq(flatcopy(arr)))
1
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
30
31
32
33
34
35
36
37
38
39
40
41
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
30
31
32
33
34
35
36
37
38
39
40
41
# 写一个验证中文的方法
function isChinese(str) {
const re = /^[\u4e00-\u9fa5]+$/;
return re.test(str);
}
//使用的Unicode 编码 4e00 和 9fa5 分别表示第一个汉字和最后一个汉字的编码
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 手动实现一个new方法
// 先一本正经的创建一个构造函数,其实该函数与普通函数并无区别
var Person = function(name, age) {
this.name = name;
this.age = age;
this.getName = function() {
return this.name;
}
}
function New(func) {
// 声明一个中间对象,该对象为最终返回的实例
let res = {}
if(func.prototype != null) {
// 将实例的原型指向构造函数的原型
res.__proto__ = func.prototype
}
//ret为构造函数执行的结果,这里通过apply,将构造函数内部的this指向修改为指向res,即为实例对象
let ret = func.apply(res, Array.prototype.slice.call(arguments, 1))
if ((typeof ret === “object” || typeof ret === “function”) && ret !== null) {
return ret;
}
// 如果没有明确指定返回对象,则默认返回res,这个res就是实例对象
return res;
}
// 通过new声明创建实例,这里的p1,实际接收的正是new中返回的res
var p1 = New(Person, 'tom', 20);
console.log(p1.getName());
1
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
30
31
32
33
34
35
36
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
30
31
32
33
34
35
36
# 快速实现一个数组随机排序
// 基础的
function outOfOrder(arr) {
return arr.sort(function(){ return Math.random() < 0.5 ? 1 : -1 })
}
console.log(outOfOrder([1,2,3,4,5]))
//洗牌法
Array.prototype.shuffle = function() {
var input = this;
for (var i = input.length-1; i >=0; i--) {
var randomIndex = Math.floor(Math.random()*(i+1));
var itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
return input;
}
var tempArray = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
tempArray.shuffle();
console.log(tempArray);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 解释一下代码意思
[].forEach.call($$(“*”),function(a){ a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16) })
• [].forEach.call() => 调用引用数组的forEach方法
• $$(‘*’) => document.querySelectorAll(‘*’)
• ~~a => parseInt(a)
• 1<<24 => 对二进数1小数点右移24位
• (parseInt(Math.random()*(1<<24)).toString(16)) => 获得了一个位于0-16777216之间的随机整数,也就是随机颜色,再使用toString(16)将它转化为十六进制数。
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 判断一个字符串是不是回文字符串
function judgeStr(s) {
let str = s.toLocaleLowerCase().replace(/[^a-zA-Z0-9]/g,'')
let strRe = str.split('').reverse().join('');
return str === strRe;
}
// 双指针循环遍历
function isPalindrome(str) {
let lp = 0,
rp = str.length - 1;
while (lp <= rp) {
if (str[lp++] != str[rp--]) return false;
}
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 写一个新年倒计时
const countDown = (range = “day”) => {
const nowDate = new Date();
const currentYear = nowDate.getFullYear();
const nextYear = new Date(currentYear + 1, 0, 1);
const rangeBase = {
sec: 1000,
minute: 1000 * 60,
hour: 1000 * 60 * 60,
day: 1000 * 60 * 60 * 24,
week: 1000 * 60 * 60 * 24 * 7,
month: 1000 * 60 * 60 * 24 * 30
};
return Math.floor(
(nextYear.valueOf() - nowDate.valueOf()) /
(rangeBase[range] || rangeBase.day)
);
};
// setInterval(() => {
// let day = countDown(‘sec’)
// console.log('距离过年还有:' + day + '秒')
// }, 1000);
1
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
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
# 写一个函数找出给定数组中的最大差值
function minMaxCalc(arr) {
const max = arr.reduce((a,b) => {
return a - b > 0 ? a : b
})
const min = arr.reduce((a,b) => {
return a - b < 0 ? a : b
})
return max - min
}
console.log(minMaxCalc([1,2,3,4,5,6,7,8]))
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 写出4个使用this最典型的例子
构造函数
function Constructor(name) {
this.name = name
}
call bind apply 使用this
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 写一个九九乘法表
const MAXLRNGTH = 7
table = ‘’
for(let lh = 1; lh < 10; lh++) {
for(let rh = 1; rh < 10; rh++) {
if(rh <= lh) {
table += `${rh}*${lh}=${rh*lh}`.padEnd(MAXLRNGTH)
}
}
table += '\n'
}
console.log(table)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13