前端资料汇总
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。
首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。
更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。
找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。
最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。
if (this.cache[name]) {
// 创建副本,如果回调函数内继续注册相同事件,会造成死循环 const tasks = this.cache[name].slice()
for (let fn of tasks) {
fn();
}
if (once) {
delete this.cache[name]
}
}
}
}
// 测试 const eventBus = new EventEmitter()
const task1 = () => { console.log(‘task1’); }
const task2 = () => { console.log(‘task2’); }
eventBus.on(‘task’, task1)
eventBus.on(‘task’, task2)
setTimeout(() => {
eventBus.emit(‘task’)
}, 1000)
9. 柯里化:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
function curry(func) {
return function curried(…args) {
// 关键知识点:function.length 用来获取函数的形参个数 // 补充:arguments.length 获取的是实参个数 if (args.length >= func.length) {
return func.apply(this, args)
}
return function (…args2) {
return curried.apply(this, args.concat(args2))
}
}
}
// 测试 function sum (a, b, c) {
return a + b + c
}
const curriedSum = curry(sum)
console.log(curriedSum(1, 2, 3))
console.log(curriedSum(1)(2,3))
console.log(curriedSum(1)(2)(3))
10. es5 实现继承
function create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
// Parent function Parent(name) {
this.name = name
}
Parent.prototype.sayName = function () {
console.log(this.name)
};
// Child function Child(age, name) {
Parent.call(this, name)
this.age = age
}
Child.prototype = create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.sayAge = function () {
console.log(this.age)
}
// 测试 const child = new Child(18, ‘Jack’)
child.sayName()
child.sayAge()
11. instanceof
function isInstanceOf(instance, klass) {
let proto = instance.proto
let prototype = klass.prototype
while (true) {
if (proto === null) return false
if (proto === prototype) return true
proto = proto.proto
}
}
// 测试 class Parent {}
class Child extends Parent {}
const child = new Child()
console.log(isInstanceOf(child, Parent), isInstanceOf(child, Child), isInstanceOf(child, Array))
12. 异步并发数限制
/**
- 关键点 * 1. new promise 一经创建,立即执行 * 2. 使用 Promise.resolve().then 可以把任务加到微任务队列,防止立即执行迭代方法 * 3. 微任务处理过程中,产生的新的微任务,会在同一事件循环内,追加到微任务队列里 * 4. 使用 race 在某个任务完成时,继续添加任务,保持任务按照最大并发数进行执行 * 5. 任务完成后,需要从 doingTasks 中移出 */
function limit(count, array, iterateFunc) {
const tasks = []
const doingTasks = []
let i = 0
const enqueue = () => {
if (i === array.length) {
return Promise.resolve()
}
const task = Promise.resolve().then(() => iterateFunc(array[i++]))
tasks.push(task)
const doing = task.then(() => doingTasks.splice(doingTasks.indexOf(doing), 1))
doingTasks.push(doing)
const res = doingTasks.length >= count ? Promise.race(doingTasks) : Promise.resolve()
return res.then(enqueue)
};
return enqueue().then(() => Promise.all(tasks))
}
// test const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i))
limit(2, [1000, 1000, 1000, 1000], timeout).then((res) => {
console.log(res)
})
13. 异步串行 | 异步并行
// 字节面试题,实现一个异步加法 function asyncAdd(a, b, callback) {
setTimeout(function () {
callback(null, a + b);
}, 500);
}
// 解决方案 // 1. promisify const promiseAdd = (a, b) => new Promise((resolve, reject) => {
asyncAdd(a, b, (err, res) => {
if (err) {
reject(err)
} else {
resolve(res)
}
})
})
// 2. 串行处理 async function serialSum(…args) {
return args.reduce((task, now) => task.then(res => promiseAdd(res, now)), Promise.resolve(0))
}
// 3. 并行处理 async function parallelSum(…args) {
if (args.length === 1) return args[0]
const tasks = []
for (let i = 0; i < args.length; i += 2) {
tasks.push(promiseAdd(args[i], args[i + 1] || 0))
}
const results = await Promise.all(tasks)
return parallelSum(…results)
}
// 测试 (async () => {
console.log(‘Running…’);
const res1 = await serialSum(1, 2, 3, 4, 5, 8, 9, 10, 11, 12)
console.log(res1)
const res2 = await parallelSum(1, 2, 3, 4, 5, 8, 9, 10, 11, 12)
console.log(res2)
console.log(‘Done’);
})()
14. vue reactive
// Dep module class Dep {
static stack = []
static target = null
deps = null
constructor() {
this.deps = new Set()
}
depend() {
if (Dep.target) {
this.deps.add(Dep.target)
}
}
notify() {
this.deps.forEach(w => w.update())
}
static pushTarget(t) {
if (this.target) {
this.stack.push(this.target)
}
this.target = t
}
static popTarget() {
this.target = this.stack.pop()
}
}
// reactive function reactive(o) {
if (o && typeof o === ‘object’) {
Object.keys(o).forEach(k => {
defineReactive(o, k, o[k])
})
}
return o
}
function defineReactive(obj, k, val) {
let dep = new Dep()
Object.defineProperty(obj, k, {
get() {
dep.depend()
return val
},
set(newVal) {
val = newVal
dep.notify()
}
})
if (val && typeof val === ‘object’) {
reactive(val)
}
}
// watcher class Watcher {
constructor(effect) {
this.effect = effect
this.update()
}
update() {
Dep.pushTarget(this)
this.value = this.effect()
Dep.popTarget()
return this.value
}
}
// 测试代码 const data = reactive({
msg: ‘aaa’
})
new Watcher(() => {
console.log(‘===> effect’, data.msg);
})
setTimeout(() => {
data.msg = ‘hello’
}, 1000)
15. promise
// 建议阅读 Promises/A+ 标准 class MyPromise {
constructor(func) {
this.status = ‘pending’
this.value = null
this.resolvedTasks = []
this.rejectedTasks = []
this._resolve = this._resolve.bind(this)
this._reject = this._reject.bind(this)
try {
func(this._resolve, this._reject)
} catch (error) {
this._reject(error)
}
}
_resolve(value) {
setTimeout(() => {
this.status = ‘fulfilled’
this.value = value
this.resolvedTasks.forEach(t => t(value))
})
}
_reject(reason) {
setTimeout(() => {
this.status = ‘reject’
this.value = reason
this.rejectedTasks.forEach(t => t(reason))
})
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this.resolvedTasks.push((value) => {
try {
const res = onFulfilled(value)
if (res instanceof MyPromise) {
res.then(resolve, reject)
} else {
resolve(res)
}
} catch (error) {
reject(error)
}
})
this.rejectedTasks.push((value) => {
try {
const res = onRejected(value)
if (res instanceof MyPromise) {
res.then(resolve, reject)
} else {
reject(res)
}
} catch (error) {
reject(error)
}
})
})
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
// 测试 new MyPromise((resolve) => {
setTimeout(() => {
resolve(1);
}, 500);
}).then((res) => {
console.log(res);
return new MyPromise((resolve) => {
setTimeout(() => {
resolve(2);
}, 500);
});
}).then((res) => {
console.log(res);
throw new Error(‘a error’)
}).catch((err) => {
console.log(‘==>’, err);
})
16.数组扁平化
// 方案 1 function recursionFlat(ary = []) {
const res = []
ary.forEach(item => {
if (Array.isArray(item)) {
res.push(…recursionFlat(item))
} else {
res.push(item)
}
})
return res
}
// 方案 2 function reduceFlat(ary = []) {
return ary.reduce((res, item) => res.concat(Array.isArray(item) ? reduceFlat(item) : item), [])
}
// 测试 const source = [1, 2, [3, 4, [5, 6]], ‘7’]
console.log(recursionFlat(source))
console.log(reduceFlat(source))
17. 对象扁平化
function objectFlat(obj = {}) {
const res = {}
function flat(item, preKey = ‘’) {
Object.entries(item).forEach(([key, val]) => {
const newKey = preKey ? ${preKey}.${key}
: key
if (val && typeof val === ‘object’) {
flat(val, newKey)
} else {
res[newKey] = val
}
})
}
flat(obj)
return res
}
// 测试 const source = { a: { b: { c: 1, d: 2 }, e: 3 }, f: { g: 2 } }
console.log(objectFlat(source));
最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。