前端核心手写面试题(看你的马步扎实不扎实)
Posted 有两把刷子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端核心手写面试题(看你的马步扎实不扎实)相关的知识,希望对你有一定的参考价值。
防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
防抖: <input id="input" type="text">
</body>
<script>
// 监听拿到input输入的值
input.addEventListener('input', function (e)
val(e.target.value)
)
// 防抖的核心代码
function fn(time, fun)
let flag // 定义状态
return function (value)
clearTimeout(flag)// 在执行之前 清除 定时器的 flag 不让他执行
flag = setTimeout(() =>
fun(value)
, time)
let val = fn(1000, function (val)
console.log(val)
)
</script>
</html>
节流
<body>
<button id="button">手在快1秒执行一次</button>
</body>
<script>
/*
定时器版本的
fns 回调函数
time 间隔时间
function throttle(fns, time)
let flag // 定义一个空状态
return function () // 内部函数访问外部函数形成闭包
if (!flag) // 状态为空执行
flag = setTimeout(() =>
fns.apply(this, arguments) // 改变this指向 吧 event 事件对象传出去
flag = null
, time)
*/
function throttle(fun, time)
let flag = 0
return function ()
let now = +new Date().valueOf()
// 当前的值 减去上一次的值 >= 传过来的事件 执行
if (now - flag >= time)
fun.apply(this, arguments)
flag = now
button.onclick = throttle((e) =>
console.log(e)
, 1000)
</script>
深拷贝
var arr =
a: 2,
b: [33]
function cloneDeep(arr = )
// 终止递归 判断如果传进来的数据不是 object 或者 传进来的是一个 null 直接返回
if (!arr || typeof arr != 'object' || arr == null) return arr
// 声明一个对象
let result
// 用 instanceof 判断原型链上是否有该类型的原型 是 Array => [] ! Arrays =>
arr instanceof Array ? result = [] : result =
// forin 循环对象的key值
for (const key in arr)
// 对象 key 赋值 result
result[key] = cloneDeep(arr[key])
T
vv ro
let arr2 = cloneDeep(arr)
// let arr2 = [...arr]
arr2.b[0] = 5
console.log(arr);// a: 2, b: Array(1) Array a: 2 b: [33]
console.log(arr2);// a: 2, b: Array(1) Array a: 2 b: [5]
// 修改新对象不影响原来的对象
类型判断
/*
实现一个类型判断
[] 返回 array
返回object
/^$/ RegExp
1 number
*/
// 第一种方案
function type_of(obj)
let res = Object.prototype.toString.call(obj).split(' ')[1] // 输出 RegExp]
/*
res.substring(0, res.length - 1) 从第 0 项开始截取 截取到它的长度 -1
也就是最后一项的前一项 把最后的一项 ] 给干掉
*/
return res.substring(0, res.length - 1).toLowerCase()
// 第二种方案
function type_of(obj)
// .slice(8, -1) 从 第 8项开始截取 -1 不要最后一项
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
数字千位分割
const format = (n) =>
let num = n.toString() // 拿到传进来的 number 数字 进行 toString
let len = num.length // 在拿到字符串的长度
// 当传进来的结果小于 3 也就是 千位还把结果返回出去 小于3 不足以分割
if (len < 3)
return num
else
let render = len % 3 //传入 number 的长度 是否能被 3 整除
console.log(render)
/*
match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。
var str = '123123000'
str.match(/\\w3/g).join(',') // 123,123,000
*/
if (render > 0) // 说明不是3的整数倍
return num.slice(0, render) + ',' + num.slice(render, len).match(/\\d3/g).join(',')
else
return num.slice(0, len).match(/\\d3/g).join(',')
let str = format(298000)
console.log(str)
生成随机数
MDN随机数 https://developer.mozilla.org/zh-CN/docs/Web/javascript/Reference/Global_Objects/Math/random
// 生成随机数
function random(min, max)
// Math.floor() 向下进行取证
return Math.floor(Math.random() * (max - min + 1) + min)
console.log(random(3, 5))
手写call方法
// 给function的原型上面添加一个 _call 方法
Function.prototype._call = function (context)
// 判断调用者是否是一个函数 this 就是调用者
if (typeof this != 'function')
return
// 如果有 context 传参就是传参者 没有就是window
that = context || window
// 保存当前调用的函数
that.fn = this // 吧 this == fns 存到that.fn来
// 截取传过来的参数
/*
arguments
a: 1
fn: ƒ fns()
*/
// 通过 slice 来截取传过来的参数
const local = [...arguments].slice(1)
// 传入参数调用函数
let result = that.fn(...local)
// 删出 fn 属性
delete that.fn
return result
let obj = a: 1
function fns(a, b)
console.log(a, b);
console.log(this)
fns._call(obj, 23, 555)
手写apply
Function.prototype.myApply = function (context)
if (typeof this !== 'function')
// 判断当前调用者是否为函数
return
// 保存传入的this指向
that = context || window
// 保存当前调用的函数
that.fn = this
let result
// 这里开始判断传入的参数是否存在,此时参数是一个数组形式[thisArg,[传参]]
// 那么如果arguments[1]即传参存在的时候,就是需要传参调用保存的函数
// 如果不存在就直接调用函数
if (arguments[1])
result = that.fn(...arguments[1])
else
result = that.fn()
return result
let obj =
a: 1
function fn(...val)
console.log(this)
console.log(...val)
fn.apply(obj, [1, 4, 5, 6, 7, 9])
手写 bind
Function.prototype._bind = function (context)
// 当调用用了_bind 函数 this 指向调用 _bind 的那个函数
// this 不是 function 不让使用 抛出类型错误
if (typeof this != 'function')
throw new TypeError('Error')
// 获取参数 除了传过来的第一项我全都要
const args = [...arguments].slice(1)
// 吧 function 进行一个缓存
fn = this
// 返回一个函数 因为 bind 不是立即调用的
return function Fn()
// 判断 this 原型链上是否又该类型的原型 Fn
return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments))
let obj =
a: 1
function fn(...val)
console.log(this) // obj
console.log(...val) // 231, 31242344, 432
fn._bind(obj, 231, 31242344, 432)()
数组去重
/*
数组的去重
*/
let ylbsz = [1, 35, 6, 78, 66, 6, 35]
function _set(arr)
// 放一个新数组
let newArr = []
for (let i = 0; i < arr.length; i++)
if (newArr.indexOf(arr[i]) == -1)
newArr.push(arr[i])
return newArr
console.log(_set(ylbsz))
console.log([...new Set([11, 11, 222, 222])])
// 字符串去重
let str = '123321你好你好'
console.log([...new Set(str.split(''))].join(''))
数组排序(冒泡)
function sort(arr)
// 外层循环控制的是比较的轮数,你要循环几轮
// arr.length (5 ) - 1 = 4
for (let i = 0; i < arr.length - 1; i++)
// 内层循环控制的每一轮交换的次数
// 第一轮要比较4次 下标为 0 arr.length - 1(4) - i(0) = 4
// 第二轮要比较3次 下标为 1 arr.length - 1(4) - i(1) = 3
// 第三轮要比较2次 下标为 2 arr.length - 1(4) - i(2) = 2
// 第四轮要比较1次 下标为 3 arr.length - 1(4) - i(3) = 1
// 内层循环控制的每一轮交换的次数
for (let j = 0; j < arr.length - 1 - i; j++)
// arr[j] 第一项 arr[j + 1] 第二项
// arr[j] 第二项 arr[j + 1] 第三项
// ....
if (arr[j] > arr[j + 1])
// 大于后一项 做一个交换变量 es6 结构赋值 的变量交换
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
return arr
console.log(sort([200, 100, 3, 9, 4]));
数组的排序(快排)
let arr = [1, 4, 6, 7, 7, 9]
// 1. 取出我们数组的中间项 用splice 拿到中间项
// 2. 在声明两个空数组,一个空数组用来放置 中间一项 大于 循环的每一项的话 就把他放到左边的数组里,下
// 余的话就放到右边的数组
// 3.接下来就是循环便利了
// 最后再次利用函数自己调用自己一直执行 递归
// 4. 如果传进来的数组 小于等于 1 的话就终止递归循环
// 做一个快排
function fn(arr)
// 如果传进来的数组 小于等于 1 的话就终止递归循环
if (arr.length <= 1) return arr
// 总长度除以2的话就可以拿到中间一项的下标
let n = Math.floor(arr.length / 2)
// splice 返回被删除的元素 下标为 0 就是只拿第一项 因为它只返回一个数据 就是被删除的一项
let cen = arr.splice(n, 1)[0]
// 2. 在声明两个空数组,一个空数组用来放置 中间一项 大于 循环的每一项的话 就把他放到左边的数组里,下
// 余的话就放到右边的数组
let leftArr = []
let rightArr = []
// 接下来就是循环便利了 判断
for (let j = 0; j < arr.length; j++)
let item = arr[j]
// > 如果是大于就是 从大到小 如果是小于 < 从小到大
cen < item ? rightArr.push(item) : leftArr.push(item)
return fn(leftArr).concat(cen, fn(rightArr))
console.log(fn(arr))
数组排序(插入排序)
function insert(arr)
// 1、准备一个数组这个数组就是新抓的牌,开始先抓一张牌进来
let handle = []
handle.push(arr[0])
// 2、第二次开始按顺序抓牌一直把牌抓光了
for (let i = 1; i < arr.length; i++)
// a 是新抓的牌
let a = arr[i]
// 和手里的牌进行比较(从后向前比)
// handle.length - 1 因为下标是从 0 开始数的
for (let j = handle.length - 1; j >= 0; j--)
// 每一次要比较手里的牌
let b = handle[j]
// 如果当前新牌a比b 大了,可就要放到 b 的后面
// 如果 a > b 就是表示从小到大
// a < b 送大到小
if (a > b)
// 如果想要放到 j 的后面就要加上一个 1,
/**
* 比如说我要插队一般要插就是插到 a 的前面
* 但是我想要插到 a 的后面怎么办
* 那这个时候就要插到 a 下一个人的人前面就可以了
*
*/
handle.splice(j + 1, 0, a)
break
// 还有一种情况就是如果你比较到第一项的还比较吗,不比较了
// 我们吧新牌放到最前面即可
if (j == 0)
handle.unshift(a)
return handle
console.log(insert([2, 8, 5, 92, 52, 4]))
数组的最大值最小值
const array = [5, 4, 7, 8, 9, 2];
let num = array.reduce((a, b) => a > b ? a : b);
console.log(num) // 9
let nums = array.reduce((a, b) => a < b ? a : b);
console.log(nums) // 2
对象去重
/*@ 数据处理对象去重*/
let arr = [
a: 1,
b: 2,
id: 6666
,
a: 1,
b: 2,
id: 6666
C语言经典面试题丨快来测一测你的基础语法扎不扎实,你能做出几题?