工具

perkz發表於2024-03-29

typescript型別

工具Readonly

interface A {
    a: string;
    b: number;
    c: number[];
}
type C = Readonly<A>
const c: C = {a: '', b: 18, c: [1, 2]}
c.a = "1" // 報紅

工具Partial

interface A {
    a: string;
    b: number;
    c: number[];
}

type B = Partial<A>
const a: A = {a: '', b: 18, c: [1, 2]};
const b: B = {a: ''};

工具Pick/Omit

interface A {
    a: string;
    b: number;
    c: number[];
}

type B = Pick<A, 'a' | 'b'>;
type C = Omit<A, 'a'>;
const b: B = {a: "", b: 0};
const c: C = {b: 1, c: [0]};

工具Record

type A = Record<'a' | 'b' | 'c', string>
const c: A = {a: "a", b: "b", c: "c"};

class類的屬性名

class A {
    a: number = 1;
    b: string = "";
}

type AFields = keyof InstanceType<typeof A>; // "a" | "b"

反轉

type A = {
    a: "x";
    b: "y";
}

type Reverse<T extends Record<keyof T, keyof any>> = {
    [P in T[keyof T]]: {
        [K in keyof T]: T[K] extends P ? K : never
    }[keyof T]
}

type B = Reverse<A>;

const b: B = {x: "a", y: "b"};

傳入不同的值返回的結果型別不同

interface A {
    a: string;
}

interface B {
    b: string;
}

interface C {
    c: string;
}

interface Types {
    a: A;
    b: B;
    c: C;
}

function fun<T extends keyof Types> (type: T): Types[T] {
    return ;
}

功能

全屏

  // 進入全屏
  function enter(ele) {
    if (ele.requestFullScreen) {
      ele.requestFullScreen();
    } else if (ele.mozRequestFullScreen) {
      ele.mozRequestFullScreen();
    } else if (ele.webkitRequestFullScreen) {
      ele.webkitRequestFullScreen();
    } else if (ele.msRequestFullScreen) {
      ele.msRequestFullScreen();
    }
  }

  // 退出全屏
  function exit() {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    } else if (document.mozCancelFullScreen) {
      document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen();
    } else if (document.msExitFullscreen) {
      document.msExitFullscreen();
    }
  }

  // 是否全屏
  function isFullscreen() {
    return Boolean(
      document.fullscreenElement ||
      document.mozFullscreenElement ||
      document.webkitFullscreenElement ||
      document.msFullscreenElement ||
      null
    );
  }

下載

<a href="https://wx3.sinaimg.cn/mw2000/eb7b830aly1hmarcfijnhj20kg0kgadg.jpg">下載</a>
<a href="https://wx3.sinaimg.cn/mw2000/eb7b830aly1hmarcfijnhj20kg0kgadg.jpg" xld="true">迅雷下載</a>
<script>
      const links = document.querySelectorAll("a[xld]");
      links.forEach((link) => {
            link.href = `thunder://${btoa(`AA${link.href}ZZ`)}`;
      });
</script>
<a href="thunder://QUFodHRwczovL3d4My5zaW5haW1nLmNuL213MjAwMC9lYjdiODMwYWx5MWhtYXJjZmlqbmhqMjBrZzBrZ2FkZy5qcGdaWg==" xld="true">迅雷下載</a>

解決文字框中文輸入導致高頻觸發

let composition = false;
input.addEventListener("input", function () {
    if (!composition) {
        search();
    }
});
// 開始輸入中文拼音了
input.addEventListener("compositionstart", function () {
    composition = true;
});
// 結束輸入中文拼音了
input.addEventListener("compositionend", function () {
    composition = false;
    search();
});

公共函式

型別判斷

      function determineType(target) {
            const type = typeof target;
            switch (type) {
                  case "bigint":
                  case "boolean":
                  case "function":
                  case "number":
                  case "string":
                  case "symbol":
                  case "undefined":
                        return type;
                  case "object":
                        if (target instanceof Array) {
                              return 'array';
                        }
                        if (target instanceof Object) {
                              return 'object';
                        }
                        return 'null';
                  default:
                        return "undefined";

            }
      }

陣列分組

function groupBy (arr, generateKey) {
  if (typeof generateKey === "string") {
    const propName = generateKey;
    generateKey = (item) => item[propName];
  }
  const result = {};
  for (let i = 0; i < arr.length; i++) {
    const key = generateKey(arr[i], i, arr);
    if (result[key]) {
      result[key].push(arr[i]);
    } else {
      result[key] = [arr[i]];
    }
  }
  return result;
}

複製

export function copyText (value) {
    const oInput = document.createElement('input');
    oInput.value = value;
    document.body.appendChild(oInput);
    oInput.select();
    document.execCommand('Copy');
    oInput.className = 'oInput';
    oInput.style.display = 'none';
}

請求重試

function request (url, maxCount) {
    return fetch(url).catch(err => maxCount <= 0 ? Promise.reject(err) : request(url, maxCount - 1));
}

併發請求

// 請求陣列,最大併發
function concurRequest (requestList, max) {
    if (!requestList.length) {
        return Promise.resolve([]);
    }
    return new Promise((resolve) => {
        let index = 0;
        let count = 0;
        let result = [];
        
        async function _request () {
            const i = index;
            const request = requestList[index];
            index++;
            try {
                result[i] = await request();
            } catch (e) {
                result[i] = e;
            } finally {
                count++;
                if (count === requestList.length) {
                    resolve(result);
                }
                if (index < requestList.length) {
                    _request();
                }
            }
        }
        
        for (let i = 0; i < Math.min(requestList.length, max); i++) {
            _request();
        }
    });
}

class轉function

"use strict";


class B {
    constructor (name) {
        this.name = name;
    }
    
    logName () {
        console.log(this.name);
    }
}

function A (name) {
    if (!new.target) {
        throw new TypeError("是類不是函式");
    }
    this.name = name;
    
}

Object.defineProperty(A.prototype, 'logName', {
    value: function () {
        if (new.target) {
            throw new TypeError("是函式不是類");
        }
        console.log(this.name);
    },
    enumerable: false, // 是否可被遍歷
    // writable: false, // 是否可寫
    // configurable: false // 屬性描述符本身能否被再次修改
});

訪問器

function A (x, y) {
  this.x = x;
  this.y = y;
}

Object.defineProperty(A.prototype, "add", {
  get: function () {
    return this.x + this.y;
  }
});

const a = new A(1, 2);
console.log(a.add); // 3
a.x++
console.log(a.add); // 4

修改必包內的私有變數

const o = (function () {
    const a = {
        x: 1,
        y: 2
    };
    // Object.setPrototypeOf(a, null); // 防禦
    return {
        get: function (key) {
            // 防禦:
            // if(Object.hasOwnProperty(key)){
            //       return a[key];
            // }
            return a[key];
        }
    };
}());

// 攻擊:不改變上面程式碼,修改必包內a物件的屬性值
Object.defineProperty(Object.prototype, "hack", {
    get() {
        return this;
    }
});
const a = o.get("hack");
a["z"] = 3;
console.log(o.get("z"));

CSS

立體陰影

<h1>立體陰影</h1>
<style>
    h1 {
        font-weight: 800;
        position: relative;
        color: #FFFFFF;
        font-size: 120px;
    }

    h1::after {
        content: "立體陰影";
        position: absolute;
        left: 0;
        color: #000000;
        transform: translate(-69px, 24px) scaleY(0.5) skew(50deg);
        z-index: -1;
        filter: blur(2px);
        -webkit-mask: linear-gradient(transparent, #000000);
    }
</style>

玻璃磨砂和黑白

    .glass {
        background: rgba(255, 255, 255, 0.4);
        /*背後的東西模糊*/
        backdrop-filter: blur(3px);
        /*背後的東西變黑白*/
        /*backdrop-filter: grayscale(1);*/
    }

彈幕避開人像

    .mask {
         mask-image: url("./image.svg");
         mask-size: cover;
    }

條紋狀

    .colorBorder {
         background: repeating-linear-gradient(-45deg, #0b5eef 0px 10px, #fff 10px 20px, #f60707 20px 30px, #fff 30px 40px);
    }

聚焦子元素父元素樣式發生變化

  <div class="container">
    <input class="input">
  </div>
  <style>
    <!-- focus-within表示當前元素以及後代元素有沒有聚焦 -->
    .container:focus-within {
      background-color: #999999;
    }
    .input:focus {
      border: 1px solid #18AEFF;
    }
  </style>

必選

  <label class="label">
    <span class="title">Name</span>
    <input class="input" data-required>
  </label>
  <style>
    .label .title:has(+ .input[data-required])::after {
      content: "*";
      color: #f62323;
      display: inline-block;
    }
  </style>

首字母

    .content::first-letter {

    }

文字選擇

    .content::selection {

    }

動態規劃

揹包放入的最大價值

const maxWeight = 6;
// [v價值, w重量]
const goodsList = [{v: 5, w: 2}, {v: 10, w: 5}, {v: 3, w: 1}, {v: 6, w: 4}, {v: 3, w: 3}];

// 求放入揹包的最大價值

function maxPackageWorth (maxWeight, goodsList) {
  let line = [];
  
  for (let i = 0; i <= maxWeight; i++) {
    const goods = goodsList[0];
    line[i] = i >= goods.w ? goods.v : 0;
  }

  for (let i = 1; i < goodsList.length; i++) {
    const next = [];
    const goods = goodsList[i];
    for (let j = 0; j <= maxWeight; j++) {
      if (j < goods.w) {
        next[j] = line[j];
      } else {
        next[j] = Math.max(
          goods.v + line[j - goods.w],
          line[j]
        );
      }
    }
    line = next;
  }
  return line[maxWeight];
}

maxPackageWorth(maxWeight, goodsList);

模型

洋蔥任務模型

  // 洋蔥模型
  class TaskPro {
    // 任務列表
    _taskList = [];
    // 正在執行
    _isRunning = false;
    // 正在執行的任務下標
    _currentIndex = 0;

    // 取出一個任務執行
    async _runTask() {
      // 任務執行完畢
      if (this._currentIndex >= this._taskList.length) {
        this._isRunning = false;
        this._currentIndex = 0;
        this._taskList = [];
        return;
      }
      const b = this._currentIndex;
      const task = this._taskList[this._currentIndex];
      await task(this._next.bind(this));
      const a = this._currentIndex;
      // 判讀task內有沒有手動執行next
      if (b === a) {
        await this._next();
      }
    }

    // 執行下一個任務
    async _next() {
      this._currentIndex++;
      await this._runTask();
    }

    // 新增任務
    addTask(task) {
      if (typeof task === "function") {
        this._taskList.push(task);
      }
    }

    // 開始執行任務
    async run() {
      if (this._isRunning) {
        return;
      }
      this._isRunning = true;
      await this._runTask();
    }
  }

  const taskPro = new TaskPro();
  taskPro.addTask(async (next) => {
    console.log(1);
    await next();
  });
  taskPro.addTask(() => {
    console.log(2);
  });

  taskPro.run();

Proxy累加

      function createAddProxy(value = 0) {
            return new Proxy({}, {
                  get(target, key) {
                        if (key === Symbol.toPrimitive) {
                              return () => value;
                        }
                        return createAddProxy(value + Number(key));

                  }
            });
      }

      const add = createAddProxy();
      console.log(add[1][3][1000] + 1); // 1005

相關文章