-爱代码爱编程
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
最近24届秋招也在如火如茶地进行中,小编也是在实习之余,利用有限的时间来准备秋招,今天分享前端几个常见的手写题:
一、Promise.all
/**
*
* @param {*} promises
* @returns
* Promise.all(iterable) 方法返回一个 Promise 实例,
* 此实例在 iterable 参数内所有的 promise 都“完成(resolvedresolved)”或
* 参数中不包含 promise 时回调完成(resolveresolve);如果参数中 promise
* 有一个失败(rejectedrejected),此实例回调失败(rejectreject),
* 失败的原因是第一个失败 promise 的结果。
*/
function promiseAll(promises) {
return new Promise((resolve,reject)=> {
if(!Array.isArray(promises)) {
return reject(new TypeError('arguments must be an array'))
}
var resolvedCounter = 0
var promiseNum = promises.length;
var resolvedValues = new Array(promiseNum);
for(let i = 0; i < promiseNum; i++) {
(function(i){
Promise.resolve(promises[i]).then(function(value){
resolvedCounter++
resolvedValues[i] = value
if(resolvedCounter == promiseNum) {
return resolve(resolvedValues)
}
},function(reason){
console.log(reason);
reject(reason)
})
})(i)
}
})
}
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
promiseAll([p1,p2,p3]).then(function(res) {
console.log(res);
})
Promise.all([p1,p2,p3]).then(function(res) {
console.log(res);
})
二、防抖函数
// 改进
export function debounce<Fn extends Function>(fn:Fn, delay:number,immediate = false) {
let timeout: number | undefined
const debounced = function(args:any) {
const later = () => {
timeout = undefined
if(!immediate) {
fn.apply(null,args)
}
}
// 判断是否立即执行
const callNow = immediate && !timeout // timeout没有意味着还没有计时器
clearTimeout(timeout)
timeout = setTimeout(later,delay)
// 如果需要立即执行,则立即执行
if(callNow) {
fn.apply(null, args)
}
}
debounced.cancel = function() {
clearTimeout(timeout)
timeout = undefined
}
}
三、节流
export function throttle<Fn extends Function>(fn:Fn, delay:number, immediate = false) {
// 最后一次执行的时间
let last = Date.now()
return function (args:any) {
// 当前时间
let now = Date.now()
//当前距离上一次执行的时间大于间隔时间
if(now - last >= delay) {
fn.apply(null, args)
last = now
}
}
}
四、数据扁平化
var arr = [1, [2, [3, 4]]];
const res = [];
function flatten(arr) {
arr.map((item) => {
if (Array.isArray(item)) {
flatten(item);
} else {
res.push(item);
}
});
return res;
}
function flattens(arr) {
while (arr.some((item) => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
//console.log(flatten(arr));
//console.log(flattens(arr));
console.log([].concat(...arr));
// 原地解法
const arr1 = [0, 1, 2, [[[3, 4]]]];
console.log(arr1.flat(3)); // 3 代表数组内最多嵌套层数
// expected output: [0, 1, 2, 3, 4]
五、简单手写Vue双向数据绑定
class Vue {
constructor(options) {
this.$options = options
this.$data = options.data
// 对data做响应式处理
observe(this.$data)
// 代理data到vm上
proxy(this)
//执行编译
new Complie(options.el, this)
}
}
//对data选项执行响应式具体操作
function observe(obj) {
if (typeof obj !== "object" || obj == null) {
return
}
new Observer(obj)
}
class Observer {
constructor(value) {
this.value = value
this.walk(value)
}
walk(obj) {
Object.keys(obj).forEach((key) => {
defineReactive(obj, key, obj[key])
})
}
}
// 编译过程
class Compiler {
constructor(el,vm) {
this.$vm = vm
this.$el = document.querySelector(el) // 获取dom元素
if(this.$el) {
this.compile(this.$el)
}
}
compile(el) {
const childNodes = el.childNodes
Array.from(childNodes).forEach(node => {
if(this.isElement(node)) { //判断是否为节点
console.log("编译元素" + node.nodeName);
}
else if (this.isInterpolation(node)) {
console.log('编译插值文本' + node.textContent); // 判断是否为插值文本 {{}}
}
if(node.childNodes && node.childNodes.length > 0) { // 判断是否有子元素
this.compile(node) // 对子元素进行递归遍历
}
})
}
isElement(node) {
return node.nodeType == 1
}
isInterpolation(node) {
return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent)
}
}
// 负责更新视图
class Watcher {
constructor(vm,key,updater) {
this.vm = vm
this.key = key
this.updateFn = updater
// 创建实例时,把当前实例指定到Dep.target静态属性上
Dep.target = this
// 读一下key ,触发get
this.vm[this.key]
// 置空
Dep.target = null
}
// 未来执行dom更新函数,由dep调用
update() {
this.updateFn.call(this.vm,this.vm[this.key])
}
}
// 声明一个Dep
class Dep {
constructor() {
this.deps = []
}
addDep(dep){
this.deps.push(dep)
}
notify() {
this.deps.forEach((dep)=> dep.update())
}
}
// 依赖收集创建Dep实例
function defineReactive(obj,key,val) {
this.observe(val)
const dep = new Dep()
Object.defineProperty(obj, key, {
get() {
Dep.target && dep.addDep(Dep.target) // Dep.target也就是Watcher实例
return val
},
set(newVal) {
if(newVal === val) return
dep.notify() // 通知dep执行更新方法
}
})
}
六、手写深拷贝
七、手写call
八、实现LPU缓存算法
class LRUCache {
#map; // 私有属性
#length; // 私有属性
constructor(length) {
this.#map = new Map()
this.length = length
}
get(key) {
if(!this.#map.has(key)) {
return
}
const value = this.#map.get(key)
// 删除之前的数据
this.#map.delete(key)
// 再把数据加进去
this.#map.set(key,value)
return value
}
set(key,value) {
// 如果之前有这条数据,就删掉
if(this.#map.has(key)) {
this.#map.delete(key)
}
// 统一变成添加行为
this.#map.set(key,value)
if(this.#map.size > this.#length) {
const firstKeyValue = this.#map.keys().next().value
// 如果大于最大长度,我们需要删除第一个key值
this.#map.delete(firstKeyValue)
}
}
}
总结
以上就是今天要讲的内容,期望大家秋招都能成功拿到心仪的offer!