# new 关键字

new 关键字实现分为三步:

1、根据构造函数的原型创建新的对象
2、执行构造函数,绑定 this 指向为新对象,传入参数
3、返回执行后的结果

function myNew(constructor,...args){
    // 创建对象,原型为构造函数的原型对象
    const obj = Object.create(constructor.prototype);
    // 执行构造函数,传入创建的对象和参数
    const res = constructor.apply(obj,args); // 注意 apply 方法是函数对象的方法,普通对象不可用
    return (res && typeof res === 'object')?res:obj;    
}
function A (){
    this.name='sdjf'
}
const ab = myNew(A)
console.log(ab);

# 手写 class

function Example(name) {
    if(!new.target) throw new TypeError("该函数应该使用new来调用");
    this.name = name
}
Object.definePropertie(Example.prototype,"init",{
    enumerable:false,
    value: function () {
        'use strict';
        if(new.target) throw new Error("init函数不能使用new来调用");
        let fn = function () {
            console.log(this.name);
        }
        fn.call(this);
    }
})

# 闭包的简单使用

// 闭包隐藏数据,只提供 API 操作
function createCache() {
  const cache = {};
  return {
    get(key){
      return cache[key]
    },
    set(key,val){
      cache[key] = val;
    }
  }
}

# 判断数据类型

function myTypeOf(obj) {
   // 使用 toString
       const typeMap = {
           "[object Object]": "Object",
           "[object Array]": "Array",
           "[object String]": "String",
           "[object Number]": "Number",
           "[object Boolean]": "Boolean",
           "[object Function]": "Function",
           "[object Null]": "Null", // 注意这里是 "Null" 而不是 "null"
           "[object Undefined]": "Undefined", // 注意这里是 "Undefined" 而不是 "undefined"
           "[object Symbol]": "Symbol",
           "[object BigInt]": "BigInt"
       };
   return typeMap[Object.prototype.toString.call(obj)];
   // 或者根据类型进行判断
   switch (typeof obj) {
       case "object":
           if(Array.isArray(obj)) return "Array"
           if(obj === "null") return "null";
           return "Object";
       case "number":
           return "Number";
       case "string":
           return "String";
       case "undefined":
           return "undefined";
       case "bigint":
           return "BigInt";
       case "boolean":
           return "Boolean";
       case "function":
           return "Function";
       case "symbol":
           return "Symbol";
       default:
           return "unknown"
   }
}

# 数组去重

function unique(arr) {
   return new Array(...new Set(arr))
}

# 数组扁平化 (扁平一层)

function arrFlat(arr) {
   if(arr.flat){
     return arr.flat(); //Array.flat 方法默认扁平一层
   }
   // 兼容 es5 版本:
   const res = [];
   arr.forEach(item=>{
       if(Array.isArray(item)) res.push(...item);
       else res.push(item) 
   })
   return res;
}

# 手写对象的 [Symbol.iterator] 迭代器协议(普通对象不内置迭代器)

// 内置迭代器的异质对象有:Array,String,Set,Map
Symbol.myIterator = Symbol('myIterator');
Object.prototype[Symbol.myIterator] = function () {
   const iterKeys = Object.keys(this);
   let iterIndex = 0;
   return {
       next: ()=> {
           if (iterIndex < iterKeys.length) {
               return {
                   value: this[iterKeys[iterIndex++]],
                   done: false
               };
           } else {
               return {
                   value: undefined,
                   done: true
               };
           }
       }
   }
}

# 手写 for of 循环(for of 便利前提是对象内置迭代器)

function myForOf(obj,fn) {
   if(!obj[Symbol.iterator]) throw new TypeError('obj不存在迭代器')
   const myIterator = obj[Symbol.iterator]();
   let cur = myIterator.next();
   while (!cur.done) {
       fn(cur.value);
       cur = myIterator.next();
   }
}

# 手写 for in 循环(for in 的前提是对象属性可被枚举,Object.keys 也是)

function myForIn(obj,fn) {
   const keys = Object.keys(obj);
   keys.forEach(item=>{
       fn({[item]:obj[item]});
   })
}

# 浅拷贝,返回新的对象,丢失原型链

function shallowClone(objLike) {
   if(typeof objLike !== 'object') return objLike;
   const res = Array.isArray(objLike)?[]:{};
   for(let item in objLike){
       if(objLike.hasOwnProperty(item)){
           res[item] = objLike[item];
       }
   }
   return res;
}

# 手写深拷贝

// 是否是对象类型
const isObject = (obj) => typeof obj === 'object' || typeof obj === 'function' && obj !== null;
function deepClone(target,map = new WeakMap()) {
   if(structuredClone) return structuredClone(target);
   // 兼容 structuredClone, 因为要进行递归处理,所以需要增加默认参数
   if(map.get(target)) return target;
   let constructor = target.constructor; // 获取到 constructor
   // 如果是日期或者正则,就新创建一个实例
   if(/^(RegExp|Date)$/i.test(constructor.name)){
       return new constructor(target);
   }
   if(isObject(target)){
       map.set(target,true);
       const cloneTarget = Array.isArray(target) ? []:{};
       for(let prop in target){
           if(target.hasOwnProperty(prop)){
               cloneTarget[prop] = deepClone(target[prop],map);
           }
       }
       return cloneTarget;
   }else {
       return target;
   }
}
// > 注意:1、原型链不能形成闭环(报错),2、__proto__的值只能是对象或者 null,3、一个对象只能又一个 [[Prorotype]],4、__proto__是内部 [[Prototype]] 的 getter/setter。

# 手写全局事件总线

class EventEmitter{
   #cache = {};
   constructor(){}
   on(name,fn){
       if(this.#cache[name]){
           this.#cache[name].push(fn);
       }else{
           this.#cache[name] = [fn]
       }
   }
   off(name,fn){
       if(!this.#cache[name]) return;
       this.#cache[name] = this.#cache[name].filter(item=>{
          return item !== fn;
       })
   }
   emit(name){
       this.#cache[name].forEach(item=>{
           item();
       })
   }
}
// 复习 CustomEvent、Event 和 EventTarget(dispatchEvent 和 addEventListener)
const sayHiEvent = new CustomEvent('sayHi',{
   detail:{
       name:"sayHi事件"
   }
})
const eventTarget = new EventTarget();
eventTarget.addEventListener('sayHi',(e)=>{
   console.log(e.detail,'e.detail');
})
// eventTarget.dispatchEvent(sayHiEvent)
// 深度思考:为什么 eventTarget 使用 dispatchEvent 时,要传入 Event 事件,而不是 type 类型?
// 因为一个 DOM 同一事件不能重复,并且同一事件类型一般要创建很多个事件(用于不同的 DOM,因此不能复用同一事件),此时用类型很难对其标识

# 遍历输出构造类

function consoClass(classFn) {
   let a = Object.getPrototypeOf(classFn);
   while (a !== null) {
       console.log(a);
       a = Object.getPrototypeOf(a);
   }
}
// HTMLElement--Element--Node--EventTarget--Object--null
consoClass(HTMLElement)

# 图片懒加载

const imgList = [...document.querySelectorAll("image")];
const imgLength = imgList.length;
const imgLazyLoad = (function () {
   let count = 0;
   return function () {
       let deleteIndexList = [];
       // 遍历图片列表
       imgList.forEach((item,index)=>{
           let rect = item.getBoundingClientRect();
           // 如果 rect.top 小于 window.innerHeight,代表以及进入视野之内
           if(rect.top < 0){
               item.src = item.dataset.src;
               deleteIndexList.push(index);
           }
       })
       imgList = imgList.filter((item,index)=>!deleteIndexList.includes(index));
   }
})()
document.addEventListener("scroll",imgLazyLoad);

# 函数防抖(多次执行,重新计时)

function debounce(fn,time) {
   let timer = null;
   return function () {
       const bindFn = fn.bind(this,...arguments)
       clearTimeout(timer);
       setTimeout(() => {
           bindFn();
       }, time);
   }
}

# 函数节流(固定时间只执行一次)

function th(fn,time) {
   let timer = null;
   return function () {
       if(timer) return;
       const bindFn = fn.bind(this,...arguments)
       timer = setTimeout(() => {
           bindFn();
           clearTimeout(timer);
       }, time);
   }
}

# 函数柯里化

function curry(fn) {
   // 将 fn 函数进行柯里化
   return function curried(...args) {
       if(args.length >= fn.length){
           return fn.apply(this,args);
       }else{
           return function (...args2) {
               return curried.apply(this,args.concat(args2))
           }
       }
   }
}

# 函数偏函数化

function partial(fn,...args) {
   return (...arg) => {
       return fn(...args,...arg);
   }
}

# 使用 jsonp 进行跨域 get 请求

const jsonp = ({ url, params, callbackName }) => {
   const generateUrl = () => {
       let dataSrc = ''
       for (let key in params) {
           if (params.hasOwnProperty(key)) {
               dataSrc += `${key}=${params[key]}&`
           }
       }
       dataSrc += `callback=${callbackName}`
       return `${url}?${dataSrc}`
   }
   return new Promise((resolve, reject) => {
       const scriptEle = document.createElement('script')
       scriptEle.src = generateUrl()
       document.body.appendChild(scriptEle)
       window[callbackName] = data => {
           resolve(data)
           document.removeChild(scriptEle)
       }
   })
}

# AJAX 封装 get 请求 JSON 数据

function getJSON(url) {
   return new Promise((resolve,reject)=>{
       const xhr = new XMLHttpRequest();
       xhr.open("GET",url,false);
       xhr.setRequestHeader("Accept","application/json");
       xhr.onreadystatechange = function () {
           if(xhr.status !== 4) return;
           if(xhr.status === 200 || xhr.status === 304) {
               resolve(xhr.responseText);
           }else {
               reject(new Error(xhr.responseText));
           }
       }
       xhr.send();
   })
}

# 实现 forEach

Array.prototype.myForEach = function (callback,thisArg) {
   if(this === null) throw new TypeError("this is null or not defined");
   // 如果回调不是函数
   if(typeof  callback !== 'function') throw new TypeError(callback + "is not a function");
   const superThis = Object(this); // 将 this 进行兼容,确保不是 null 或 undefined
   const len = superThis.length >>> 0; // 确保该函数的参数是正整数或 0
   let k = 0;
   while (k < len) { // 当 k 小于 0 进行遍历
       if(k in superThis){
           callback.call(thisArg,superThis[k],k,superThis);
       }
       k++;
   }
}

# 实现 map

Array.prototype.myMap = function (callback,thisArg) {
   if(this.null) throw new TypeError("this is null or defined");
   if(typeof callback !== "function") throw new TypeError(callback.name + "is not a function");
   const thisObj = Object(this); // 保证 thisObj 不是 null 或 undefined,使用 Object 可以传入数组,使用 Array 需要列出来
   const len = thisObj.length >>> 0; // 无符号右移 0,内部全部流程:valueOf、toString、Number,然后无符号左移(去小数)
   let k =0;res = []
   while (k < len) {
       if(k in thisObj){
           res[k]=callback.call(thisArg,thisObj[k],k,thisObj);
       }
       k++;
   }
   return res;
}

# 实现 filter

Array.prototype.myFilter = function (callback,thisArg) {
   if(this == null) return new TypeError("this is null or undefined")
   if(typeof callback !== "function") return new TypeError(callback.name + "is not a function")
   // 处理 filter
   const thisObj = Object(this);
   const len = thisObj.length >>> 0;
   let res = [],k = 0;
   while (k < len) {
       if(k in thisObj){
           if(callback.call(thisArg,thisObj[k],k,thisObj)){
               res.push(thisObj[k]);
           }
       }
       k++;
   }
   return res;
}

# 实现 some

Array.prototype.mySome = function (callback,thisArg) {
   if(this == null) return new TypeError("this is null or undefined");
   if(typeof callback !== "function") return new TypeError(callback.name + "is not a function")
   const thisObj = Object(this);
   let len = thisObj.length,k = 0;    
   while (k < len) {
       if(k in thisObj){
           if(callback.call(thisArg,thisObj[k],k,thisObj)){
               return true;
           }
       }
       k++;
   }
   return false;
}

# 实现 reduce

Array.prototype.myReduce = function (callback,initialValue) {
   if(this == null) return new TypeError("this is null or undefined");
   if(typeof callback !== "function") return TypeError(callback.name + "is not a function");
   const thisObj = Object(this); // 防止 null 或者 undefined
   const len = thisObj.length;
   let res,k=0;
   while (k < len) {
       if(k in thisObj){
           // 进行执行
           initialValue = callback(initialValue,thisObj[k]);
       }
       k++;
   }
   return initialValue;
}

# 手写 call、apply 和 bind

Function.prototype.myCall = function (thisContext) {
    // 将 this(函数),绑定 this, 传入参数
    thisContext = thisContext || window; //this 默认为 window
    const fn = Symbol(thisContext);
    thisContext[fn] = this; // 将 this 函数挂载到 thisContext 环境中
    let args = [...arguments].slice(1);
    thisContext[fn](...args); // 用对象 [属性] 的方式使用函数(绑定 this)
    delete thisContext[fn]; // 最后删除属性
}
// 小结:使用 call 绑定 this 的关键就在于:将 this(也就是函数)挂载到 thisContext(需要绑定的 this 上),使用对象 [属性] 的方式进行执行,从而自动绑定 this
Function.prototype.myApply = function (thisContext) {
    const fn = Symbol("myApply");
    // 将 fn 绑定到黄经中
    thisContext[fn] = this;
    // 执行
    const args = [...arguments].slice(1);
    thisContext[fn](args);
    delete thisContext[fn]; // 删除属性之后,垃圾回收机制自动回收 fn
}
Function.prototype.myBind = function (thisContext) {
    // 函数绑定
    // 返会一个函数,绑定 this 指向,到固定的函数上
    const thisFn = this;
    const arg = [...arguments].slice(1); // 保存传入的参数
    return function () {
        const newArg = [...arguments];
        return thisFn.apply(thisContext,[...arg,...newArg])
    }
}

# instanceof

function myInstanceOf(left,right) {
    // 判断 left 是不是 right 的子类,遍历 left 的原型链,看是否有 right
    if(typeof left !== "object") throw new TypeError("Left-hand side of myInstanceOf is not an object");
    if(typeof right !== "object") throw new TypeError("Right-hand side of myInstanceOf is not an object");
    while (Object.getPrototypeOf(left)) {
        left = Object.getPrototypeOf(left);
        if(left === Object.getPrototypeOf(right)){
            return true;
        }
    }
    return false;
}

# 实现 Object.create

// 参数一:proto 二:属性对象
Object.myCreate = function (proto,propertyObj) {
    if(typeof proto !== "object" && typeof proto !== "function"){
        throw new TypeError("object prototype may not be an object or null")
    }
    if(propertyObj === null){
        new TypeError("Cannot convert undefined or null to object");
    }
    function F() {}
    F.prototype = proto;
    const obj = new F();
    if(propertyObj !== undefined){
        Object.defineProperties(obj,propertyObj)
    }
    // 模拟 Object.create (null)
    if(proto === null){
        obj.__proto__ = null;
    }
    return obj;
}

# 实现 Object.assign

Object.myAssign = function (target,...source) {
    if(target == null){
        throw new TypeError("Cannot convert undefined or null to object")
    }
    // 确保是一个对象类型
    let resObj = Object(target);
    source.forEach(item=>{
        if(item != null){
            // 如果 key 属性是在
            for(let key in item){
                // 如果 key 是原型上的方法
                if(item.hasOwnProperty(key)){
                    resObj[key] = item[key];
                }
            }
        }
    })
    return resObj;
}

# Promise 实现

const PENDING = Symbol.for('pending');
const FULFILLED = Symbol.for('fulfilled');
const REJECTED = Symbol.for('rejected');
const resolvemyPromise = (myPromise2, x, resolve, reject) => {
  if (myPromise2 === x) {
    return reject(
      new TypeError("Chaining cycle detected for myPromise #<myPromise>")
    );
  }
  let called;
  if ((typeof x === "object" && x != null) || typeof x === "function") {
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvemyPromise(myPromise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
};
class myPromise {
  constructor(executor) {
    this.status = PENDING; // 状态
    this.value = undefined; // 值
    this.reason = undefined; // 原因
    this.onResolvedCallbacks = []; // 成功回调数组
    this.onRejectedCallbacks = []; // 失败回调数组
    let resolve = (value) => {
      if (value instanceof myPromise) {
        return value.then(resolve, reject);
      }
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn());
      }
    };
    let reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (err) => {
            throw err;
          };
    return new myPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvemyPromise(myPromise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvemyPromise(myPromise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.status === PENDING) {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvemyPromise(myPromise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvemyPromise(myPromise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
  }
  catch(errCallback) {
    return this.then(null, errCallback);
  }
  finally(callback) {
    return this.then(
      (value) => {
        return myPromise.resolve(callback()).then(() => value);
      },
      (reason) => {
        return myPromise.resolve(callback()).then(() => {
          throw reason;
        });
      }
    );
  }
  static resolve(data) {
    return new myPromise((resolve, reject) => {
      resolve(data);
    });
  }
  static reject(reason) {
    return new myPromise((resolve, reject) => {
      reject(reason);
    });
  }
  static all(values) {
    if (!Array.isArray(values)) {
      const type = typeof values;
      return new TypeError(`TypeError: ${type} ${values} is not iterable`);
    }
    return new myPromise((resolve, reject) => {
      let resultArr = [];
      let orderIndex = 0;
      const processResultByKey = (value, index) => {
        resultArr[index] = value;
        if (++orderIndex === values.length) {
          resolve(resultArr);
        }
      };
      for (let i = 0; i < values.length; i++) {
        let value = values[i];
        if (value && typeof value.then === "function") {
          value.then((value) => {
            processResultByKey(value, i);
          }, reject);
        } else {
          processResultByKey(value, i);
        }
      }
    });
  }
  static race(myPromises) {
    return new myPromise((resolve, reject) => {
      for (let i = 0; i < myPromises.length; i++) {
        let val = myPromises[i];
        if (val && typeof val.then === "function") {
          val.then(resolve, reject);
        } else {
          resolve(val);
        }
      }
    });
  }
}
myPromise.defer = myPromise.deferred = function () {
  let dtd = {};
  dtd.myPromise = new myPromise((resolve, reject) => {
    dtd.resolve = resolve;
    dtd.reject = reject;
  });
  return dtd;
};
export default MyPromise;

# vue3 封装 debounce

// 定义一个返回懒执行响应式数据的函数
function useDebouncedRef(value,delay=200){
    let timeout;
    return customRef((track,trigger)=>{
      return {
        get(){
          track();
          return value;
        },
        set(newValue){
          clearTimeout(timeout);
          timeout = setTimeout(()=>{
            value = newValue
            trigger();
          },delay)
        }
      }
    })
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

dmq 微信支付

微信支付

dmq 支付宝

支付宝