⌈前端工具函数⌋💖第二弹💖

163 阅读3分钟

isFormData

判断是否是FormData 类型

参数名参数类型参数说明
valany需要判断的值

实现

export function isFormData(val: any): val is FormData {
  return typeof val !== 'undefined' && val instanceof FormData;
}

示例

const formData = new FormData();
formData.append('username', 'botaoxy');
formData.append('password', '123456');

isFormData(formData); // true

isEmptyObject

判断是否是空对象

参数名参数类型参数说明
valany需要判断的值

实现

export function isEmptyObject(val: any): boolean {
  for (const key in val) {
    return false;
  }
  return true;
}

示例

const obj = {};
isEmptyObject(obj); // true

const obj1 = {
    userName: 'botaoxy',
    password: '123456'
}

isEmptyObject(obj); // false

isPlainObject

判断是否是普通对象

参数名参数类型参数说明
valany需要判断的值

实现

export function isPlainObject(val: any): val is Object {
  return Object.prototype.toString.call(val) === '[object Object]';
}

示例

const obj = {};
isPlainObject(obj); // true

const obj1 = new Date();
isPlainObject(obj1); // false

debounce

防抖函数
wait 毫秒后在执行该事件,若wait 毫秒内被重复触发,则重新计时

  • 搜索框输入搜索请求
  • 手机号、邮箱等表单验证输入检测
  • 窗口大小resize,只需窗口调整完成后,计算窗口大小。防止频繁渲染。
参数名参数类型参数说明
fnany指定的函数
waitnumber防抖时间(毫秒)
immediateboolean-默认值false是否立即执行

实现

export function debounce(fn: any, wait: number, immediate: boolean = false) {
  let timer: ReturnType<typeof setTimeout> | null;
  const lambda = function (this: any) {
    const args = Array.prototype.slice.call(arguments);
    if (timer) clearTimeout(timer as ReturnType<typeof setTimeout>);

    // 立即执行
    if (immediate) {
      const callNow = !timer;

      timer = setTimeout(() => {
        timer = null;
      }, wait);

      if (callNow) {
        fn.apply(this, args);
      }
    } else {
      timer = setTimeout(() => {
        fn.apply(this, args);
      }, wait);
    }
  };

  // 取消功能
  lambda.cancel = function () {
    clearTimeout(timer as ReturnType<typeof setTimeout>);
    timer = null;
  };

  return lambda;
}

示例

const dom = document.getElementById('container');

function mouseMove(event){
    console.log(this, event);
    dom.innerHTML = `${event.clientX}-${event.clientY}`
}

dom.onmousemove = debounce(mouseMove, 1000);

throttle

节流函数
wait 毫秒内只运行一次,若wait 毫秒内重复触发,只有一次生效

  • 滚动加载
  • 搜索框联想功能
参数名参数类型参数说明
fnany指定的函数
waitnumber节流时间(毫秒)
options{leading?: boolean;trailing?: boolean;}节流配置参数
属性说明默认值
leading是否立即执行false
trailing调用结束后是否再执行一次true

实现

export function throttle(
  fn: any,
  wait: number,
  options: {
    leading?: boolean;
    trailing?: boolean;
  } = {}
) {
  let previous = 0;
  let timer: ReturnType<typeof setTimeout> | null;
  const defaultOpts = Object.assign(
    {
      leading: false,
      trailing: true,
    },
    options
  );
  const lambda = function (this: any) {
    const now = Date.now();
    const args = Array.prototype.slice.call(arguments);
    if (!previous && !defaultOpts.leading) previous = now;
    const remaining = wait - (now - previous);

    if (remaining <= 0 || remaining > wait) {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }

      previous = now;
      fn.apply(this, args);
      if (!timer) args = null;
    } else if (!timer && defaultOpts.trailing) {
      timer = setTimeout(() => {
        previous = defaultOpts.leading === false ? 0 : Date.now();
        timer = null;
        const args = Array.prototype.slice.call(arguments);
        fn.apply(this, args);
        if (!timer) args = null;
      }, remaining);
    }
  };

  // 取消功能
  lambda.cancel = function () {
    clearTimeout(timer as ReturnType<typeof setTimeout>);
    timer = null;
    previous = 0;
  };

  return lambda;
}

示例

function getUserInfo() {
  // 请求接口获取数据
  return axios
    .post('/user', { userName: 'botaoxy', password: '123456' })
    .then(function (response) {
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    });
}

throttle(getUserInfo, 1000);

isURLSearchParams

判断是否是URLSearchParams

参数名参数类型参数说明
valany需要判断的值

实现

export function isURLSearchParams(val: any): val is URLSearchParams {
  return typeof val !== 'undefined' && val instanceof URLSearchParams;
}

示例

const paramsString = "q=URLUtils.searchParams&topic=api";
const searchParams = new URLSearchParams(paramsString);

isURLSearchParams(searchParams); //true

encodeURIC

URI 针对特殊字符编码处理

实现

export function encodeURI(val: string): string {
  return encodeURIComponent(val)
    .replace(/%40/g, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%20/g, '+')
    .replace(/%5B/gi, '[')
    .replace(/%5D/gi, ']');
}

示例

console.log(`?x=${encodeURI('botaoxy?')}`); // ?x=botaoxy%3F
console.log(`?x=${encodeURI('шеллы')}`); // "?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"

buildURL

构建url

参数名参数类型参数说明
urlstringurl地址
paramsanyurl参数
paramsSerializer(params: any) => string自定义参数序列化

实现

依赖函数
⌈前端工具函数⌋❤️‍🔥第一弹❤️‍🔥 - 掘金 (juejin.cn)-typeOf
isURLSearchParams - 判断是否是 **URLSearchParams**类型
encodeURIC - encodeURIComponent 针对一些特殊字符编码处理

export function buildURL(url: string, params?: any, paramsSerializer?: (params: any) => string) {
  if (!params) return url;
  let serializerParams;
  if (paramsSerializer) {
    serializerParams = paramsSerializer(params);
  } else if (isURLSearchParams(params)) {
    serializerParams = params.toString();
  } else {
    const parts: string[] = [];
    Object.getOwnPropertyNames(params).forEach((key) => {
      const paramsVal = params[key];
      if (paramsVal === null || typeof paramsVal === 'undefined') return;
      let values = [];
      if (typeOf(paramsVal) === 'array') {
        values = paramsVal;
        key += '[]';
      } else {
        values = [paramsVal];
      }

      values.forEach((val: any) => {
        if (typeOf(val) === 'date') {
          val = val.toISOString();
        } else if (typeOf(val) === 'object') {
          val = JSON.stringify(val);
        }
        parts.push(`${encodeURIC(key)}=${encodeURIC(val)}`);
      });
    });
    serializerParams = parts.join('&');
  }

  if (serializerParams) {
    const markIndex = url.indexOf('#');
    if (markIndex !== -1) {
      url = url.slice(0, markIndex);
    }

    url += (url.indexOf('?') === -1 ? '?' : '&') + serializerParams;
  }

  return url;
}

示例

// 传入 url 和 对象参数
const url = 'https://127.0.0.1/search';
const params = {
    userName: 'botaoxy',
    password: '123456'
}
buildURL(url, params); // https://127.0.0.1/search?userName=botaoxy&password=123456

// 传入的 URLSearchParams 类型的参数
const paramsString = "userName=botaoxy&password=123456";
const searchParams = new URLSearchParams(paramsString);
buildURL(url, searchParams); // https://127.0.0.1/search?userName=botaoxy&password=123456

// url已携带部分参数来做组合
const url1 = 'https://127.0.0.1/search?userName=botaoxy';
const params1 = {
    password: '123456'
}
buildURL(url1, params1); // https://127.0.0.1/search?userName=botaoxy&password=123456

parseURL

解析 url 参数

参数名参数类型参数说明
urlstringurl地址

实现

export function parseURL(url: string) {
  const instanceURL = new URL(url);
  const URLParams = instanceURL.search.slice(1);
  if (!URLParams) return null;
  const splitURLParams = URLParams.split('&');
  const params = Object.create(null);
  splitURLParams.forEach((param) => {
    if (param.includes('=')) {
      const [key, val] = param.split('=');
      params[key] = decodeURIComponent(val);
    } else {
      params[param] = true;
    }
  });
  return params;
}

示例

const url = 'https://127.0.0.1/search?serName=botaoxy&password=123456';

parseURL(url); 
// {
//    userName: 'botaoxy',
//    password: '123456'
// }

jsonp

使用scriptsrc属性实现跨域

参数名参数类型参数说明
urlstringurl地址
callbackNamestring-默认值callback回调函数名
paramsanyurl参数
paramsSerializer(params: any) => string自定义参数序列化

实现

依赖函数
buildURL - 构建URL

interface JsonpOpts {
  url: string;
  callbackName: string;
  params?: any;
  paramsSerializer?: (params: any) => string;
}

export function jsonp(options: JsonpOpts) {
  const { url, callbackKey='callback', callbackName, params, paramsSerializer } = options;
  return new Promise((resolve, reject) => {
    const scriptEl = document.createElement('script');
    scriptEl.src = `${buildURL(url, params, paramsSerializer)}&${callbackKey}=${callbackName}`;
    document.body.appendChild(scriptEl);
    (<any>window)[callbackName] = (data: any) => {
      resolve(data);
      document.removeChild(scriptEl);
    };
  });
}

示例

jsonp({
    url: 'http://127.0.0.1/search?wd=botaoxy',
    callbackKey: 'cb',
    callbackName: customFun
}).then(res=>{
    console.log(res)
})

// async await
async function searchUser(){
    const userInfo = await jsonp({
        url: 'http://127.0.0.1/search?wd=botaoxy',
        callbackKey: 'cb',
        callbackName: customFun
    })
} 

后记

个人博客 | Botaoxy (chengbotao.github.io)
chengbotao (Chengbotao) (github.com)
billows - npm
chengbotao/billows: 使用 TypeScript 收集总结常用的工具函数

感谢阅读,敬请斧正!


我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿