highlight: a11y-dark
面试题:
- 手写new
- 手写bind
- 手写深拷贝
- 柯里化
- 手写一个防抖节流
- 手写一个函数缓存
1. new
function customNew(fn,...args){
// 1. 创建一个空对象
var obj = {};
// 2. 让构造函数的原型对象 赋值给 实例对象的__proto__
obj.__proto__ = fn.protoType;
// 3. 改变构造函数的指针
let result = fn.apply(obj,args);
// 4. 根据返回值判断
return result instanceof Object ? result : obj;
}
2. bind
Function.prototype.customBind1 = function(...args1){
const [first, ...rest] = args1;
let fn = this;
return function Fn(...args){
// 正常这里就是直接 _this = context; 但是为了兼容new 的情况, 加了一个 检测函数是不是Fn类型的
let _this = fn instanceof Fn ? new Fn(...args) : first;
return fn.apply(_this, [...args, ...rest]);
}
}
3. 深拷贝
function deepCopy1(obj, hash= new WeakMap()){
let isOject = Object.prototype.toString.call(obj) == '[object Object]';
let isArray = Array.isArray(obj);
if(!isArray && !isOject){
// 不是对象或者数组: reg data fn
// function 的返回值是[object function]
// reg 的返回值是[object RegExt]
return obj;
}
if(hash.has(obj)){
// 循环引用自身
return hash.get(obj);
}
let new_obj = Array.isArray(obj) ? new Array(): new Object();
hash.set(obj,'key');
for(let key in obj){ // in 遍历包括原型链上的属性
if(obj.hasOwnProperty(key)){ // 判断只是自身的属性,过滤掉原型链上的属性
new_obj[key] = deepCopy1(obj[key],hash);
}
}
return new_obj;
}
4. 柯里化
function curryFn(fn){
// 这里不能使用argument 因为闭包会让第二个函数能访问到第一个函数内部的argument变量
const arity = fn.length;
function currtied (...args){
if(args.length >= arity){
return fn(...args);
}else{
return function (...next){
return currtied(...args, ...next)
}
}
}
return currtied;
}
function add(a,c,b){
return a+b+c;
}
5. 防抖节流
// 非立即执行
// 点击后延迟4s执行
// 定时器版本
function throttle(func,wait){
let timer;
return function(){
const context = this;
const args = arguments;
if(!timer){ // timer没有值的时候
timer = setTimeout(()=>{
func.apply(context,args);
timer = null;
},wait)
}
}
}
// 立即执行,时间戳版本的
function throttle2(func,wait){
let oldTime = Date.now();
return function(){ // 闭包为了能访问到外层的变量
let newTime = Date.now();
if(newTime - oldTime >=wait){
console.log("this 指向", this)
func.apply(null,arguments);
oldTime = Date.now();
}
}
}
// 防抖:n秒后执行,n秒内再次触发的话,从触发时刻开始重新计时
// 版本1: 立即执行 + 非立即执行
function debounce(func, wait, immediate) {
let timer;
return function () {
const context = this;
const args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
let callNow = !timer; // 把上次的时间存下来
timer = setTimeout(function () {
timer = null;
}, wait);// 然后在n秒后记忆清空
if (callNow) { // 如果没有 是第一次的话直接调用原始的目标函数
func.apply(context, args)
}
} else {
timer = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
}
// 版本2:非立即执行
function debounce2(func, wait) {
let timer;
return function () {
const context = this;
const args = arguments;
clearInterval(timer);
timer = setTimeout(() => {
func.apply(this, args)
}, wait);
}
}
- 函数缓存
function memoize(func, content){
let cache = {};
content = content || this;
return function(...key){
if(!cache[key]){
cache[key] = func.apply(content, key)
}else{
return cache[key];
}
}
}