2021前端面试之JavaScript手写题
Posted hugo233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021前端面试之JavaScript手写题相关的知识,希望对你有一定的参考价值。
1.实现防抖函数(debounce)
连续触发在最后一次执行方法,场景:输入框匹配
let debounce = (fn,time = 1000) => {
let timeLock = null
return function (...args){
clearTimeout(timeLock)
timeLock = setTimeout(()=>{
fn(...args)
},time)
}
}
2.实现节流函数(throttle)
在一定时间内只触发一次,场景:长列表滚动节流
let throttle = (fn,time = 1000) => {
let flag = true;
return function (...args){
if(flag){
flag = false;
setTimeout(()=>{
flag = true;
fn(...args)
},time)
}
}
}
3.深拷贝(deepclone)
判断类型,正则和日期直接返回新对象
空或者非对象类型,直接返回原值
考虑循环引用,判断如果hash中含有直接返回hash中的值
新建一个相应的new obj.constructor加入hash
遍历对象递归(普通key和key是symbol情况)
function deepClone(obj,hash = new WeakMap()){
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return new Date(obj);
if(obj === null || typeof obj !== 'object') return obj;
//循环引用的情况
if(hash.has(obj)){
return hash.get(obj)
}
//new 一个相应的对象
//obj为Array,相当于new Array()
//obj为Object,相当于new Object()
let constr = new obj.constructor();
hash.set(obj,constr);
for(let key in obj){
if(obj.hasOwnProperty(key)){
constr[key] = deepClone(obj[key],hash)
}
}
//考虑symbol的情况
let symbolObj = Object.getOwnPropertySymbols(obj)
for(let i=0;i<symbolObj.length;i++){
if(obj.hasOwnProperty(symbolObj[i])){
constr[symbolObj[i]] = deepClone(obj[symbolObj[i]],hash)
}
}
return constr
}
4.数组扁平化的实现(flat)
let arr = [1,2,[3,4,[5,[6]]]]
console.log(arr.flat(Infinity))//flat参数为指定要提取嵌套数组的结构深度,默认值为 1
//用reduce实现
function fn(arr){
return arr.reduce((prev,cur)=>{
return prev.concat(Array.isArray(cur)?fn(cur):cur)
},[])
}
5.函数柯里化
function sumFn(a,b,c){return a+ b + c};
let sum = curry(sumFn);
sum(2)(3)(5)//10
sum(2,3)(5)//10
function curry(fn,...args){
let fnLen = fn.length,
argsLen = args.length;
//对比函数的参数和当前传入参数
//若参数不够就继续递归返回curry
//若参数够就调用函数返回相应的值
if(fnLen > argsLen){
return function(...arg2s){
return curry(fn,...args,...arg2s)
}
}else{
return fn(...args)
}
}
6.使用闭包实现每隔一秒打印 1,2,3,4
for (var i=1; i<=5; i++) {
(function (i) {
setTimeout(() => console.log(i), 1000*i)
})(i)
}
7.手写一个 jsonp
const jsonp = function (url, data) {
return new Promise((resolve, reject) => {
// 初始化url
let dataString = url.indexOf('?') === -1 ? '?' : ''
let callbackName = `jsonpCB_${Date.now()}`
url += `${dataString}callback=${callbackName}`
if (data) {
// 有请求参数,依次添加到url
for (let k in data) {
url += `${k}=${data[k]}`
}
}
let jsNode = document.createElement('script')
jsNode.src = url
// 触发callback,触发后删除js标签和绑定在window上的callback
window[callbackName] = result => {
delete window[callbackName]
document.body.removeChild(jsNode)
if (result) {
resolve(result)
} else {
reject('没有返回数据')
}
}
// js加载异常的情况
jsNode.addEventListener('error', () => {
delete window[callbackName]
document.body.removeChild(jsNode)
reject('javascript资源加载失败')
}, false)
// 添加js节点到document上时,开始请求
document.body.appendChild(jsNode)
})
}
jsonp('http://192.168.0.103:8081/jsonp', {
a: 1,
b: 'heiheihei'
})
.then(result => {
console.log(result)
})
.catch(err => {
console.error(err)
})
8.手写一个观察者模式
class Subject{
constructor(name){
this.name = name
this.observers = []
this.state = 'XXXX'
}
// 被观察者要提供一个接受观察者的方法
attach(observer){
this.observers.push(observer)
}
// 改变被观察着的状态
setState(newState){
this.state = newState
this.observers.forEach(o=>{
o.update(newState)
})
}
}
class Observer{
constructor(name){
this.name = name
}
update(newState){
console.log(`${this.name}say:${newState}`)
}
}
// 被观察者 灯
let sub = new Subject('灯')
let mm = new Observer('小明')
let jj = new Observer('小健')
// 订阅 观察者
sub.attach(mm)
sub.attach(jj)
sub.setState('灯亮了来电了')
9.EventEmitter 实现
class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
let callbacks = this.events[event] || [];
callbacks.push(callback);
this.events[event] = callbacks;
return this;
}
off(event, callback) {
let callbacks = this.events[event];
this.events[event] = callbacks && callbacks.filter(fn => fn !== callback);
return this;
}
emit(event, ...args) {
let callbacks = this.events[event];
callbacks.forEach(fn => {
fn(...args);
});
return this;
}
once(event, callback) {
let wrapFun = function (...args) {
callback(...args);
this.off(event, wrapFun);
};
this.on(event, wrapFun);
return this;
}
}
10.生成随机数的各种方法?
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
总结一下
面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。
还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。
万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。
为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。
前端面试题汇总
JavaScript
性能
linux
前端资料汇总
完整版PDF资料免费分享,只需你点赞支持,动动手指点击此处就可免费领取了。
前端工程师岗位缺口一直很大,符合岗位要求的人越来越少,所以学习前端的小伙伴要注意了,一定要把技能学到扎实,做有含金量的项目,这样在找工作的时候无论遇到什么情况,问题都不会大。
以上是关于2021前端面试之JavaScript手写题的主要内容,如果未能解决你的问题,请参考以下文章
面试前端面试常考手写题 - JavaScript - CSS
JavaScript手撕前端面试题:手写new操作符 | 手写Object.freeze
JavaScript手撕前端面试题:手写Object.create | 手写Function.call | 手写Function.bind