# JS 中常用代码片段

# 判断用户浏览器

const inBrowser = typeof window !== 'undefined';
const userAgent = inBrowser ? window.navigator.userAgent.toLowerCase() : '';
export const isIE = /\b(msie|trident)\b/i.test(userAgent);
export const isIE9 = /\bmsie 9\.0\b/.test(userAgent);
export const isEdge = /\bedge\/\d+\b/.test(userAgent);
export const isAndroid = /(android)/i.test(userAgent) || weexPlatform === 'android';
export const isIOS = /(?:iphone|ipad|ipod|ios)/i.test(userAgent) || weexPlatform === 'ios';
export const isChrome = /\bchrome\/\d+\b/.test(userAgent) && !isEdge;

# 两个对象取交集

// 两个对象取交集 后向前覆盖 符合直观
function merge (target, source) {
    for (const key in source) {
      if (source.hasOwnProperty(key)) {
        target[key] = source[key];
      }
    }
    return target;
  }

# 秒数转时分秒

function padZero(val: number, length = 2): string {
  return val.toString().padStart(length, '0');
}

export const sec2hms = (seconds: number): string => {
  const day = Math.floor(seconds / (60 * 60 * 24));
  const hour = Math.floor((seconds % (60 * 60 * 24)) / (60 * 60));
  const min = Math.floor((seconds % (60 * 60)) / 60);
  const sec = seconds % 60;
  const ms = padZero(Math.floor((seconds * 10) % 1000), 3);

  return `${padZero(day)}:${padZero(hour)}:${padZero(min)}:${padZero(sec)}.${ms}`;
};

# 进制转换

export const convertBase = (params: any, unit: string = "", fix: number = 2): string => {
  const num = Number(params);
  
  if (isNaN(num)) return "unknown";
  if (num === 0) return `${num.toFixed(fix)}${unit}`;

  const arr = ["", "K", "M", "G", "T"];
  let index = arr.findIndex((item) => item === unit);

  if (index === -1) {
    for (let i = 1; i < arr.length; i++) {
      if (num / Math.pow(2, 10 * i) > 1) {
        num /= Math.pow(2, 10 * i);
        index = i;
        break;
      }
    }
  }

  return `${num.toFixed(fix)}${arr[index]}`;
};

# 获取 URL 参数

export const getURLParams = (): { [key: string]: string } | false => {
  const search = window.location.search;
  if (!search) return false;

  const params = new URLSearchParams(search);
  const obj: { [key: string]: string } = {};

  for (const [key, value] of params.entries()) {
    obj[key] = value;
  }

  return obj;
};

# 多个请求的进度条

function dosomething(tasks: Array<() => Promise<any>> = []): 
Promise<{ results: any[], successes: number, failures: number }> 
{
  const successCount = 0;
  const failCount = 0;

  return Promise.all(
    tasks.map((func) => {
      return func()
        .then((res) => ({ result: res, success: true }))
        .catch((err) => ({ error: err, success: false }));
    })
  ).then(results => {
    results.forEach(result => {
      if (result.success) {
        successCount++;
      } else {
        failCount++;
      }
    });
    return { results: results.map(r => r.result), successes: successCount, failures: failCount };
  });
}

# 深度拷贝

写一个深度拷贝的工具方法

function deepCopy<T>(oldObj: T): T {
  // 如果是null 返回null
  if (oldObj === null) return null;
  // 如果不是对象,是简单类型或者方法,那么直接返回
  if (typeof oldObj !== "object") return oldObj as any;
  
  // 处理正则和时间对象
  if (oldObj instanceof RegExp) return new RegExp(oldObj);
  if (oldObj instanceof Date) return new Date(oldObj);

  // 数组拷贝
  if (Array.isArray(oldObj)) {
    return Array.from(oldObj, item => deepCopy(item)) as any;
  }

  // 对象拷贝
  const newObj = Object.create(oldObj.constructor.prototype);
  for (const key in oldObj) {
    if (Object.hasOwnProperty.call(oldObj, key)) {
      newObj[key] = typeof oldObj[key] === "object" ? deepCopy(oldObj[key]) : oldObj[key];
    }
  }

  return newObj as any;
}

测试用例

// 定义一个构造函数,定义静态属性和方法
function Person(name, age) {
  this.name = name;
  this.age = function () {
    console.log(age);
  };
}
// 定义实例方法
Person.prototype.song = (music) => {
  console.log(music);
};
// 生成实例对象
let person1 = new Person("刘德华", 20);
// 动态创建对象属性
person1.a = { b: 1, c: { d: [1, 2, 3] } };
// 深度拷贝
let person2 = deepCopy(person1);
// 测试
console.log("person1", person1);
// person1 Person { name: '刘德华', age: [Function], a: { b: 1, c: { d: [Array]; } } }
console.log("person2", person2);
// person2 Person { name: '刘德华', age: [Function], a: { b: 1, c: { d: [Array]; } } }
console.log(person1.constructor == person2.constructor); // true
console.log(person1.__proto__ == person2.__proto__); // true
console.log(person1.age === person2.age); // true
console.log(person1.song === person2.song); // true
console.log(person1 == person2); // false
console.log(person1.a === person2.a); // false

# 拷贝剪贴板

export async function copyToClipboard(text: string) {
    if (navigator.clipboard?.writeText) {
        return await navigator.clipboard.writeText(text);
    } else {
        return new Promise((resolve, reject) => {
            const textarea = document.createElement("textarea");
            textarea.value = text;
            textarea.style.position = "fixed";
            document.body.appendChild(textarea);
            textarea.select();

            try {
                const successful = document.execCommand("copy");
                document.body.removeChild(textarea);
                if (successful) {
                    resolve({});
                } else {
                    reject(new Error("复制命令失败"));
                }
            } catch (err) {
                document.body.removeChild(textarea);
                reject(err);
            }
        });
    }
}