2021年的准备工作——手写代码

98 阅读4分钟

手写代码系列

手写代码心得

1.手写深拷贝
function deepClone(obj){
    if(typeof obj !='object || obj==null){
        //如果object是null,或者不是对象和数组,直接返回
        return obj
    };
    let result;
    if(obj instanceof Array){
        result=[]
    }else {
        result={}
   };
   for(let key in object){
       //保证key不是原型的属性
       if(obj.hasOwnProperty(key)){
           result[key]=deepClone(obj[key])
       }
   };
   return result;
}
2.手写promise(简易版)

手写promise 手写promise


/*
 * pending:初始化成功
 * fulfilled:成功
 * rejected:失败
 * */

function Promise(executor) {// 执行器
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.fulfilledCallback = [];
    this.rejectCallback = [];
    let resolve = (value)=>{
        if(this.status=='pending'){
            this.status = 'resolve';
            this.value = value;
            this.fulfilledCallback.forEach(fn=>fn())
        }
    };
    let reject = (reason)=>{
        if(this.status =='pending'){
            this.status = 'reject';
            this.reason = reason;
            this.rejectCallback.forEach(fn=>fn())
        }
    };
    try{
        executor(resolve,reject)
    }catch(e){
        reject(e)
    }
}
Promise.prototype.then = function (onfulfilled,onrejected) {
    if(this.status == 'resolve'){
        onfulfilled(this.value)
    }
    if(this.status == 'reject'){
        onrejected(this.reason)
    }
    if(this.status == 'pending'){
        this.fulfilledCallback.push(()=>{
            onfulfilled(this.value)
        });
        this.rejectCallback.push(()=>{
            onrejected(this.reason)
        })
    }
};

var a = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(10)
    })
});
a.then((res)=>{
    console.log(res);
});
3.手写promise(复杂版)

手写promise(复杂版)


class _Promise {
    constructor(executor){
        // 校验executor
        if(typeof executor !== "function"){
            throw new Error(`Promise resolver ${executor} is not a function!`);
        };

        this.value = undefined; //终值=>resolve的值
        this.reason = undefined;//拒因=>reject的值
        this.state = "pending";//状态

        this.onFulfilledCallbacks = [];// 成功回调
        this.onRejectedCallbacks = [];// 失败回调

        const resolve = (value)=>{
            // 成功后的一系列操作(状态的改变,成功回调的执行)
            if(this.state === "pending"){
                this.state = "fulfilled";
                this.value = value;
                this.onFulfilledCallbacks.forEach(fn=>fn(this.value));
            };
        };
        const reject = (reason)=>{
            // 失败后的一系列操作(状态的改变,成功回调的执行)
            if(this.state === "pending"){
                this.state = "rejected";
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn=>fn(this.reason));
            }
        };
        try{
            executor(resolve,reject);
        }catch(err){
            reject(err);
        }
    }
    then(onFulfilled,onRejected){

        // onFulfilled未传值或传的值不是function的时候
        // 自动把onFulfilled变成一个函数
        if(typeof onFulfilled !== "function"){
            onFulfilled = value => value;
        };

        //onRejected未传值或传的值不是function的时候
        //自动把onFulfilled变成一个函数,并抛出错误
        if(typeof onRejected !== "function"){
            onRejected =  reason => { throw reason }
        };

        const promise2 = new _Promise((resolve,reject)=>{
            if(this.state === "pending"){
                this.onFulfilledCallbacks.push(
                    (value)=>{
                        setTimeout(()=>{
                            const x = onFulfilled(value);
                            resolve(x);
                        })
                    }
                );
                this.onRejectedCallbacks.push(
                    (reason)=>{
                        setTimeout(()=>{
                            const x = onRejected(reason);
                            reject(x);
                        })
                    }
                );

            };

            if(this.state === "fulfilled"){
                setTimeout(()=>{
                    const x = onFulfilled(this.value);
                    resolve(x);
                });
            };

            if(this.state === "rejected"){
                setTimeout(()=>{
                    const x = onRejected(this.reason);
                    reject(x);
                });
            };
        });

        return promise2;
    }
};

new _Promise((resolve,reject)=>{
    resolve(3);
})
.then(
value => console.log("value",value)
)
.then(value => console.log("value",value))
4.手写call,apply,bind函数

手写call,apply,bind函数

1) call
Function.prototype.myCall = function(context, ...args) { // 解构context 与arguments
   if(typeof this !== 'function') { // this 必须是函数
     throw new TypeError(`It's must be a function`)
   }
   if(!context) context = window; // 没有context,或者传递的是 null undefined,则重置为window
   const fn = Symbol(); // 指定唯一属性,防止 delete 删除错误
   context[fn] = this; // 将 this 添加到 context的属性上
   const result = context[fn](...args); // 直接调用context 的 fn
   delete context[fn]; // 删除掉context新增的symbol属性
   return result; // 返回返回值
}
2)apply
Function.prototype.myApply = function(context, args = []) { // 解构方式
   if(typeof this !== 'function') {
     throw new TypeError(`It's must be a function`)
   }
   if(!context) context = window;
   const fn = Symbol();
   context[fn] = this;
   const result = context[fn](...args);
   delete context[fn];
   return result;
}
3)bind
Function.prototype.myBind = function (context, ...args) {
  const fn = this;
  if(typeof fn !== 'function'){
      throw new TypeError('It must be a function');
  }
  if(!context) context = window;
  return function (...otherArgs) {
    return fn.apply(context, [...args, ...otherArgs]);
  };
};
5.手写New操作符
//它创建了一个全新的对象。
//它会被执行[[Prototype]](也就是__proto__)链接。
//它使this指向新创建的对象。。
//通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
//如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用将返回该对象引用。
function New(func) {
    var res = {};
    if (func.prototype !== null) {
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
    return res;
}
6.手写防抖

手写防抖

function debounce(func, ms = 1000) {
  let timer;
  return function (...args) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      func.apply(this, args)
    }, ms)
  }
}

// 测试
const task = () => { console.log('run task') }
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
7.手写节流
function throttle(fn, wait) {
	let prev = new Date();
	return function() { 
	    const args = arguments;
		const now = new Date();
		if (now - prev > wait) {
			fn.apply(this, args);
			prev = new Date();
		}
	}
8.手写柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

function curry(fn, args) {
    var length = fn.length;
    var args = args || [];
    return function(){
        newArgs = args.concat(Array.prototype.slice.call(arguments));
        if (newArgs.length < length) {
            return curry.call(this,fn,newArgs);
        }else{
            return fn.apply(this,newArgs);
        }
    }
}

function multiFn(a, b, c) {
    return a * b * c;
}

var multi = curry(multiFn);

multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);


//es6方式

const curry = (fn, arr = []) => (...args) => (
  arg => arg.length === fn.length
    ? fn(...arg)
    : curry(fn, arg)
)([...arr, ...args])

let curryTest=curry((a,b,c,d)=>a+b+c+d)
curryTest(1,2,3)(4) //返回10
curryTest(1,2)(4)(3) //返回10
curryTest(1,2)(3,4) //返回10
9.手写事件监听
function bindEvent(elem,type,selector,fn){
    if(fn==null){
        fn=selector;
        selector=null;    
    }
    elem.addEventListener(type,event=>{
        const {target}=event;
        if(selector){
            if(target.matches(selector)){
    		fn.call(target,event)
            }
        }else{
            fn.call(target,event)        
        }
    })
}
10.手写深度比较isEqual()
const obj1  = {a:100,b:{x:10,y:20}}
const obj2  = {a:100,b:{x:10,y:20}}
isEqual(obj1,obj2)   ===  true

//实现
//判断是否是对象或数组
function isObject(obj) {
    return typeof obj === 'object' && obj !== null
}

function isEqual(obj1,obj2) {
  // 两个数据有任何一个不是对象或数组
  if (!isObject(obj1) || !isObject(obj2)) {
    // 值类型(注意:参与equal的一般不会是函数)
    return obj1 === obj2
  }
  // 如果传的两个参数都是同一个对象或数组
  if (obj1 === obj2) {
    return true
  }

  // 两个都是对象或数组,而且不相等
  // 1.先比较obj1和obj2的key的个数,是否一样
  const obj1Keys = Object.keys(obj1)
  const obj2Keys = Object.keys(obj2)
  if (obj1Keys.length !== obj2Keys.length) {
    return false
  }

  // 如果key的个数相等,就是第二步
  // 2.以obj1为基准,和obj2依次递归比较
  for (let key in obj1) {
    // 比较当前key的value  --- 递归
    const res = isEqual(obj1[key], obj2[key])
    if (!res) {
      return false
    }
  }

  // 3.全相等
  return true
}

const arr1 = [1, 2, 3]
const arr2 = [1,2,3,4]
console.log(isEqual(arr1,arr2))  // false