算法
-
冒泡排序
-
选择排序
-
快速排序
-
二叉树查找: 最大值、最小值、固定值
-
二叉树遍历
-
二叉树的最大深度
-
给予链表中的任一节点,把它删除掉
-
链表倒叙
-
如何判断一个单链表有环
由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
开源分享:docs.qq.com/doc/DSmRnRG… const REJECTED = 'rejected';
function MyPromise(fn) { const self = this; this.state = PENDING; this.value = null; this.reason = null; this.resolvedCallbacks = []; this.rejectedCallbacks = [];
function resolve(value) { if (value instanceof MyPromise) { value.then(resolve, reject) } // 保证代码执行顺序为本轮事件循环的末尾 setTimeout(() => { if (self.state === PENDING) { self.state = RESOLVED; self.value = value; self.resolvedCallbacks.forEach(cb => cb(value)); } }, 0) }
function reject(reason) { setTimeout(() => { if (self.state === PENDING) { self.state = REJECTED; self.reason = reason; self.rejectedCallbacks.forEach(cb => cb(reason)); } }, 0) } try { fn(resolve, reject); } catch (e) { reject(e); } }
MyPromise.prototype.then = function (onFulfilled, onReject) { const self = this; return new MyPromise((resolve, reject) => { let fulfilled = () => { try { const result = onFulfilled(self.value); return result instanceof MyPromise ? result.then(result) : resolve(result); } catch (e) { reject(e); } }; let rejected = () => { try { const result = onReject(self.reason); return result instanceof MyPromise ? result.then(resolve, reject) : reject(result); } catch (e) { reject(e); } } switch (self.state) { case PENDING: case RESOLVED: case RESOLVED:
}
}) }
MyPromise.all = (promises) => { return new MyPromise((resolve, reject) => { if (!Array.isArray(promises)) { throw new TypeError('arguments must be array'); } let resolvedCounter = 0; let promiseNum = promises.length; let resolvedResult = [];
for (let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(value => {
resolvedCounter++;
resolvedResult[i] = value;
if (resolvedCounter === promiseNum) {
return resolve(resolvedResult);
}
}, error => {
return reject(error);
})
}
}) } MyPromise.race = function(args) { return new Promise((resolve, reject) => { for(let i = 0; len = args.length; i++) { args[i].then(resolve, reject); } }) }
### 防抖函数
防抖是n秒内会重新计时
function debounce(fn, wait) { let timer = null; return function() { if(timer) { clearTimeout(timer); timer = null; } timer = setTimeout(() => { fn.apply(this, arguments); }, wait); } }
### 节流函数
n秒内不重新计时
function throttle(fn, delay) { let timer = null; return function () { if (timer) return; timer = setTimeout(() => { timer = null; return fn.apply(this, arguments); }, delay) } }
### 实现类型判断函数
function getType(value) { if (value === null) { return value + ''; } if(typeof value === 'object') { return Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); } else { return typeof value; } }
### 实现call函数
执行步骤:
* 判断call的调用者是否为函数,不是函数需要抛出错误,call调用者就是上下文this,也就是需要被调用的函数
* 判断需要被调用的函数的的上下文对象是否传入,不存在就设置为window
* 处理传入的参数,截取第一个参数后的所有参数,作为被调用函数
* 将需要被调用的函数,绑在传入的上下文上,作为一个属性
* 使用传入的上下文调用这个函数,并返回结果
* 删除绑定的属性
* 返回结果
Function.prototype.myCall = function(context) { if(typeof this !== 'function') { throw new TypeError('need function'); } let args = arguments.slice(1); let result = null;
context = context || window;
context.fn = this; result = context.fn(...args);
delete context.fn; return result; }
### 实现apply函数
唯一的不同就是最后参数的获取方式
Function.prototype.myApply = function(context) { if(typeof this !== 'function') { throw new TypeError('need function'); } let args = arguments[1]; let result = null;
context = context || window;
context.fn = this; result = context.fn(...args);
delete context.fn; return result; }
### 实现bind
* 先判断调用者是否为函数
* 缓存当前需要bind的函数,就是上面的调用者,也是是bind函数的上下文
* 返回一个函数,利用闭包原理实现对this的保存
* 函数内部用apply函数来处理函数调用
* + 需要判断函数作为构造函数的情况,这个时候的this就是当前调用这个闭包函数的this
+ 作为普通函数,直接使用传入的上下文就好了
Function.prototype.myBind = function(context) { if(typeof this !== 'function') { throw new TypeError('need function'); } let args = [...arguments].slice(1); let fn = this;
return function F() { return fn.apply( this instanceof F ? this : context, args.concat(...arguments) ) } }
### 浅拷贝
// es6的Object.assign Object.assign(target, source1, source2);
// 扩展运算符 {...obj1, ...obj2}
// 数组的浅拷贝 Array.prototype.slice Array.prototype.concat
// 手动实现 function shallowCopy(object) { if(!object || typeof object !== 'object') return; let newObj = Array.isArray(object);
for(let key in object) { if(object.hasOwnProperty(key)) { newObj[key] = object(key); } } return newObj; }
### 深拷贝deepclone
可能的问题:
* json方法出现函数或symbol类型的值的时候,会失效
* 处理循环引用问题
* 处理可迭代类型的数据
* 处理包装类型
* 处理普通类型
**简单版本参考vue版本:**
* 判断类型是否为原始类型,如果是,无需拷贝,直接返回
* 为避免出现循环引用,拷贝对象时先判断存储空间中是否存在当前对象,如果有就直接返回
* 开辟一个存储空间,来存储当前对象和拷贝对象的对应关系
* 对引用类型递归拷贝直到属性为原始类型
const deepClone = (target, cache = new WeakMap()) => { if(target === null || typeof target !== 'object') { return target } if(cache.get(target)) { return target } const copy = Array.isArray(target) ? [] : {} cache.set(target, copy) Object.keys(target).forEach(key => copy[key] = deepClone(obj[key], cache)) return copy }
### 实现Object.assign
就是实现一个浅拷贝
Object.myAssign = function (target, ...source) { if (target === null) { throw new TypeError('can not be null'); } let ret = Object(target); source.forEach(obj => { if (!obj !== null) { for (let key in obj) { if (obj.hasOwnProperty(key)) { ret[key] = obj[key]; } } } }); return ret; }
### 简单实现async/await中的async函数
async/await语法糖就是使用Generator函数+自动执行器来运作的,注意只要要实现async函数就是实现**一个generate函数+执行器的语法糖**
// 定义了一个promise,用来模拟异步请求,作用是传入参数++ function getNum(num){ return new Promise((resolve, reject) => { setTimeout(() => { resolve(num+1) }, 1000) }) }
//自动执行器,如果一个Generator函数没有执行完,则递归调用 function asyncFun(func){ var gen = func();
function next(data){ var result = gen.next(data); if (result.done) return result.value; result.value.then(function(data){ next(data); }); }
next(); }
// 所需要执行的Generator函数,内部的数据在执行完成一步的promise之后,再调用下一步 var func = function* (){ var f1 = yield getNum(1); var f2 = yield getNum(f1); console.log(f2) ; }; asyncFun(func);
### 实现一个Object.freeze
**锁定对象的方法**
* Object.preventExtensions()
no new properties or methods can be added to the project 对象不可扩展, 即不可以新增属性或方法, 但可以修改/删除
* Object.seal()
same as prevent extension, plus prevents existing properties and methods from being deleted 在上面的基础上,对象属性不可删除, 但可以修改
* Object.freeze()
same as seal, plus prevent existing properties and methods from being modified 在上面的基础上,对象所有属性只读, 不可修改
以上三个方法分别可用Object.isExtensible(), Object.isSealed(), Object.isFrozen()来检测
var deepFreeze =function (obj) { var allProps = Object.getOwnPropertyNames(obj); // 同上:var allProps = Object.keys(obj); allProps.forEach(item => { if (typeof obj[item] === 'object') { deepFreeze(obj[item]); } }); return Object.freeze(obj); }
模拟实现一个Object.freeze,使用了Object.seal
function myFreeze(obj) { if (obj instanceof Object) { Object.seal(obj); let p; for (p in obj) { if (obj.hasOwnProperty(p)) { Object.defineProperty(obj, p, { writable: false }); myFreeze(obj[p]);// 递归,实现更深层次的冻结 } } } }
### 用ES5实现一下map和reduce函数
Array.prototype.myMap = (fn, context) => { var arr = Array.prototype.slice.call(this); var mapArray = []; for (let i = 0; i < arr.length; i++) { mapArray.push(fn.call(context, arr[i], i, this)); } return mapArray; }
Array.prototype.myReduce = (fn, initialValue) => { var arr = Array.prototype.slice.call(this); var res, startIndex; res = initialValue ? initialValue : arr[0]; startIndex = initialValue ? 0 : 1; for(let i = startIndex; i< arr.length; i++) { res = fn.call(null, res, arr[i], i, this); } return res; }
## 给大家推荐一个实用面试题库
## 算法
1. 冒泡排序
2. 选择排序
3. 快速排序
4. 二叉树查找: 最大值、最小值、固定值
5. 二叉树遍历
6. 二叉树的最大深度
7. 给予链表中的任一节点,把它删除掉
8. 链表倒叙
9. 如何判断一个单链表有环

>由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://docs.qq.com/doc/DSmRnRGxvUkxTREhO)**