前端面试手写题系列 X

前端面试手写题系列 X

前端面试 手写题系列 已经完结,包含了以下的题目:

1. 手写拍平数组 flat
2. 手写防抖和节流函数
3. 手写深拷贝
4. 手写快排
5. 手写 call、apply、bind
6. 手写一个 sleep 函数
7. 手写冒泡排序
8. 函数柯里化
9. 对象扁平化
10. 手写 new 过程
11. 求数组中的最大值
12. 手写 instanceof
13. 手写 foreach 函数
14. 手写迭代器
15. 手写 filter
16. 实现一个 compose 函数
17. 正则相关(去哪儿原题)
18. 实现一个任务调度函数(得物原题)
19. 数组转化为 tree
20. 不使用 a 标签,实现 a 标签的功能
21. 手写插入排序
22. LRU 算法
23. 归并排序
24. 求两个数组的交集、并集、补集、差集
25. 提取 url 中的参数
26. 实现一个洗牌函数 shuffle
27. 希尔排序

1.手写拍平数组 flat

拍平数组:就是将 [1, 2, 3, [4, 5]]变为 [1, 2, 3, 4, 5]
举个实际应用的例子:

const list = [
	{
		id: 1,
		name: '1号线',
		tranship: ['2号线', ['3号线', 's8号线']]
	},
	{
		id: 2,
		name: '2号线',
		tranship: ['1号线', '4号线']
	},
	{
		id: 3,
		name: '3号线',
		tranship: ['10号线', '4号线']
	}
]

// 求所有的能够转到路线

// ['2号线', ['3号线', 's8号线']]  +    ['1号线', '4号线']  +   ['10号线', '4号线']  = [所有的线路]

// 思路: concat

代码:
JavaScript 本身的 flat 函数:

const arr = ['2号线', ['3号线', 's8号线'], '1号线', '4号线', '10号线', '4号线']

console.log(arr.flat())

结果:

PS E:\demo> node test.js
[
  '2号线',  '3号线',
  's8号线', '1号线',
  '4号线',  '10号线',
  '4号线'
]

但是官方的函数只能拍平一层。
自己手写的函数:

const arr = ['2号线', ['3号线', 's8号线', ['s10号线']], '1号线', '4号线', '10号线', '4号线']

function MyFlat(arr) {
	while (arr.some(item => item instanceof Array)) {
		arr = Array.prototype.concat.apply([], arr)
		console.log(arr)
	}
	return arr
}

console.log(MyFlat(arr))

// console.log([].concat([1, [1, 2]]))
// console.log(Array.prototype.concat.apply([], [1, [1, 2]])) // [] + 1, [1,2]

2.手写防抖和节流函数

image.png

防抖:

例子:

游戏中的回城就可以认为是防抖,在回城的读秒过程中,如果再次执行回城操作,那么会重新进行读秒,只有整个读秒过程都没有再次执行回城操作,那么等到读秒结束才能成功回城。

应用场景:
  • 输入框频繁输入内容,搜索或者提交信息。
  • 频繁点击按钮,触发某个事件。
  • 监听浏览器滚动事件。
  • 监听用户缩放浏览器resize事件。
function debounce(func, wait = 1000) {
	// 设定定时器
	let timer = null
	// 返回的函数是用户调用的函数
	// 如果已经设定过定时器就清空上一次的定时器
	// 开启一个新的定时器,延迟执行传入的方法
	return function () {
		if (timer) clearTimeout(timer)
		timer = setTimeout(() => {
			func.apply(null, arguments)
		}, wait)
	}
}

function debounce1(func, wait = 1000) {
	// 设定定时器
	let timer = null
	// 返回的函数是用户调用的函数
	// 如果已经设定过定时器就清空上一次的定时器
	// 开启一个新的定时器,延迟执行传入的方法
	return function (args) {
		if (timer) clearTimeout(timer)
		timer = setTimeout(() => {
			func.apply(null, [args])
		}, wait)
	}
}

const submit = value => {
	console.log(value)
}

// submit(1)

let submit1 = debounce1(submit, 2000)

submit1(1)

节流函数:

例子:

节流类似于技能cd,不管你按了多少次,必须等到cd结束后才能释放技能。也就是说在如果在cd时间段,不管你触发了几次事件,只会执行一次。只有当下一次cd转换,才会再次执行。

function throttle(fn, wait = 1000) {
	let timer = null
	return function () {
		if (timer) {
			return
		}
		timer = setTimeout(() => {
			fn.apply(this, arguments)
			timer = null
		}, wait)
	}
}

const scroll = val => {
	console.log(val)
}

let scroll1 = throttle(scroll, 0.1)

// 模拟滚动条滚动,假设滚动条在滚动,一直在触发 scroll1 函数
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)
scroll1(1)

结果:只会执行一次,我们模拟的是一直在滚动滚动条,每隔 0.1ms 执行一次,所以只打印出了一个值,因为 我们模拟的数量过少,这些 scroll1 函数在 0.1ms 之内都完成了。

PS E:\demo> node test.js
1

image.png

关于 apply 和 call

其实节流函数的执行也可以使用下面的这种方法,叫做剩余参数的写法:

function throttle1(fn, wait = 1000) {
	let timer = null
	return function (...arg) {
		if (timer) {
			return
		}
		timer = setTimeout(() => {
			fn.call(this, ...arg)
			timer = null
		}, wait)
	}
}

剩余参数值得就是 arg,他是一个数组,然后我们可以使用 ...arg的形式将数组里面的值取出来,所以可以理解 fn.call(this, ...arg) 第二个参数 ...arg实际上是一个一个单独的参数,而不是和 apply 一样的数组作为参数。

手写题系列文章

前端手写题系列 I
前端手写题系列 II
前端手写题系列 III
前端手写题系列 IV
前端手写题系列 V
前端手写题系列 VI
前端手写题系列 VII
前端手写题系列 VIII
前端手写题系列 IX
前端手写题系列 X

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

城南顾北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值