Skip to content

202507

INFO

很难维持到月底,太难了,整天提心吊胆的,太无聊了

0701

  • 1483
  • 带孩子比较辛苦,困的要死,工作让我沉醉

0702

  • 49,8 月底结束,顶多也就 50 天左右,这次是真的要结束了
  • 未来出路在哪里

手写真实 DOM 转化成虚拟 dom

js

实现 Object.assign() Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象

js
let aClone = { ...a }
let aClone = Object.assign({}, a)
// 这是个简单的题目,请自行实现Object.assign()

/**
 * @param {any} target
 * @param {any[]} sources
 * @return {object}
 */
function objectAssign(target, ...sources) {
  for (let item of sources) {
    for (let key in item) {
      if (item.hasOwnProperty(key)) {
        target[key] = item[key]
      }
    }
  }
  return target
}
function objectAssign(target, ...sources) {
  if (target == null) {
    throw Error()
  }

  target = Object(target)
  for (let source of sources) {
    if (source == null) continue
    merge(Object.keys(source), source)
    merge(Object.getOwnPropertySymbols(source), source)
  }
  function merge(keys = [], currSource) {
    for (let key of keys) {
      target[key] = currSource[key]
      if (target[key] !== currSource[key]) {
        throw Error()
      }
    }
  }
  return target
}

0703

  • 48,早上流脑付费疫苗 480,真心不便宜,还有 3 针,9 月打一针,另外两三岁还要继续打疫苗

  • 最近两天,凌晨五点就醒了,哄睡艰难,每天都很困

  • 还差 3w 多还完,顶多也就换两个月,还剩 2 万多,这个压力也还好,离职补偿应该没问题,还能有盈余,还一还房贷

  • 不能失去对技术的信心,微前端要熟练使用

  • 每天完成一点手写题

合并有序链表

数组扁平化

js
// wrong
function flatten(arr, dep = 1) {
  let res = []
  let stack = [...arr]
  while (stack.length) {
    const item = stack.pop()
    if (Array.isArray(item) && dep > 0) {
      stack.push(...item)
      dep--
    }
    res.push(stack)
  }
  return res.reverse().slice()
}
// ok
function flatten(arr, dep = 1) {
  let res = []
  let stack = [...arr.map((item) => [item, dep])]
  while (stack.length) {
    let [top, dep] = stack.pop()
    if (Array.isArray(top) && dep > 0) {
      stack.push(...top.map((item) => [item, dep - 1]))
    } else {
      res.push(top)
    }
  }
  return arr.reverse()
}
// ok
function flatten(arr, dep = 1) {
  return dep > 0
    ? arr.reduce((acc, pre) => {
        return [...acc, ...(Array.isArray(pre) ? flatten(pre, dep - 1) : [pre])]
      }, [])
    : arr
}

0704

  • 47
  • 手写 TS 类型
ts
// 请自行实现MyPartial<T>。
type Too = {
  a: string
  b: number
}
type MyPartial<T> = {
  [P in keyof T]?: T[P]
}
type MyRequired<T> = {
  [P in keyof T]-?: T[P]
}
type MyRecord<K extends PropertyKey, T extends unknown> = {
  [P in K]: T
}
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P]
}
type Foo = {
  a: string
  b: number
  c: boolean
}
type A = MyOmit<Foo, "a" | "b"> // {c: boolean}
type B = MyOmit<Foo, "c"> // {a: string, b: number}
type C = MyOmit<Foo, "c" | "d"> // {a: string, b: number}
type MyOmit<T, K extends keyof any> = {
  [P in keyof T as P extends K ? never : P]: T[P]
}

手写题

js
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
function dup(str) {
  let max = 0
  let arr = []
  for(let i=0;i<str.length;i++) {
    let item = arr[i]
    const index = arr.indexOf(item)
    if(index > -1) {
      arr.splice(0, index+1)
    }
    arr.push(item)
    max = Math.max(max, arr.length)
  }
  return max
}

二叉树的层序遍历

js
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
  if (!root) return []
    let res = []
    let node = [root]
    while(node.length) {
      let len = node.length
      let arr = []
      if(let i = 0;i<len;i++) {
        let item = node.shift()
        arr.push(node.val)
        if(item.left) {
          node.push(item.left)
        }
        if(item.right) {
          node.push(item.right)
        }
      }
      res.push(arr)
    }
    return res
};

0710

  • 1492
  • 数组扁平化
js
function flatten(arr, dep = 1) {
  let stack = [...arr.map((item) => [item, dep])]
  let res = []
  while (stack.length) {
    let [top, dep] = stack.pop()
    if (Array.isArray(top) && dep > 0) {
      stack.push(...top.map((item) => [item, dep - 1]))
    }
    res.push(top)
  }
  return res.reverse()
}

0711

  • 1493
  • 手写题 有效的括号
js
/**
 * 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
输入:s = "([])"
输出:true
 * @param {string} s
 * @return {boolean}
 * ()
 */
var isValid = function (s) {
  const map = new Map([
    [")", "("],
    ["}", "{"],
    ["]", "["],
  ])
  var arr = []
  for (let item of s) {
    const lastone = arr[arr.length - 1]
    if (map.has(item) && map.get(item) == lastone) {
      arr.pop()
    } else {
      arr.push(item)
    }
  }
  return arr.length === 0
}
isValid("()")

二叉树的层序遍历

js
// 输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
function levelOrder(node) {
  if (!node) return []
  let stack = [node]
  let ans = []
  while(stack.length) {
    let len = stack.length
    let res = []
    for(let i=0;i<len;i++) {
      let cur = stack.shift()
      cur && res.push(cur.val)
      if(cur.left) {
        stack.push(cur.left)
      }
      if (cur.right) {
        stack.push(cur.right)
      }
    }
    ans.push(res)
  }
  reurn ans
}

手写实现 Promise.allSettled

js
/**
 * @param {Array<any>} promises - notice that input might contains non-promises
 * @return {Promise<Array<{status: 'fulfilled', value: any} | {status: 'rejected', reason: any}>>}
 */
function allSettled(promises) {
  // your code here
  return new Promise((resolve, reject) => {
    let len = promises.length
    let ans = []
    for (let i = 0; i < len; i++) {
      return Promise.resolve(promises[i]).then(
        (res) => {
          ans.push({
            value: res,
            status: "fifulled",
          })
          if (i == len - 1) {
            resolve(ans)
          }
          re
        },
        (err) => {
          ans[i] = err
          ans.push({
            value: res,
            status: "rejected",
          })
          if (i === len - 1) {
            resolve(ans)
          }
        }
      )
    }
  })
}
// second
function allSettled(arr) {
  var allP = [...arr]
  return Promise.all(allP.map((item) => {
    return Promise.resolve(item).then((res) => {
      status: 'fulfilled',
      value: res
    }, err => {
      status: 'rejected',
      reason: err
    })
  }))
}
// third
function allSettled(arr) {
  return arr.reduce((acc, item) => {
    return acc.then((pre) => {
      return Promise.resolve(item).then((ret) => {
        return [...pre, {status: 'fulfilled', value: ret}]
      }).then((err) => {
        return [...pre, {status: 'rejected', reason: err}]
      })
    })
  }, Promise.resolve([]))
}

0715

  • 1497
  • 继续手写代码找一个公司先上着,总不能一直干这种不稳定的活,像是临时工
  • 手写最大子数组和
js
示例 1

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6
function big(arr) {
  let sum = 0
  let max = arr[0]
  for(let item of arr) {
    if (sum > 0) {
      sum = sum+item
    } else {
      sum = item
    }
    max = Math.max(max, sum)
  }
  return max
}
big([-2,1,-3,4,-1,2,1,-5,4])

买卖股票的最佳时机

js
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
function maxBenift(arr) {
 let len = arr.length
 let dep = new Array(len).fill([0,0])
 dep[0] = [-arr[0], 0]
 for(let i = 1;i<len;i++) {
  dp[i][0]=Math.max(dp[i-1][0], -arr[i])
  dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0], arr[i])
 }
 return dep[len-1][1]
}
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  let min = prices[0]
  let max = 0
  for(let item of prices) {
    if (item>min && item != min) {
      max = Math.max(max, max-min)
    } else {
      min = item
    }
  }
  return max
}
/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let low = prices[0];
    let max = 0
    for(let i = 0; i < prices.length; i++) {
        let cur = prices[i]
        low = Math.min(low, cur)
        max = Math.max(max, cur - low)
    }
    return max
};

手写数组去重

js
function removeDup(arr) {
  let m = new Map()
  let i = 0
  while (i < arr.length) {
    if (m.has(arr[i])) {
      arr.splice(i, 1)
    } else {
      m.set(arr[i], i)
      i++
    }
  }
  return arr
}

手写 async/await

js
function mockAsync(fn) {
  return (...rest) => {
    let pFn = fn(...rest)
    return new Promise((resolve, reject) => {
      function step(key, ...name) {
        let obj
        try {
          obj = pFn[key](...name)
        } catch (err) {
          reject(err)
        }
        const { value, done } = obj
        if (done) {
          resolve(value)
        } else {
          return Promise.resolve(value).then(
            (res) => {
              return step("next", res)
            },
            (err) => {
              return step("throw", err)
            }
          )
        }
      }
      return step("next")
    })
  }
}

手写 jsonp 函数

js
function mockJsonp(url) {
  return new Promise((resolve, reject) => {
    let cb = "callback" + Math.random().toString().slice(2)
    let script = document.createElement("script")
    script.url = url + "?callback=" + cb
    docuemnt.appendChild(script)
    window[cb] = function (res) {
      resolve(res)
      delete window[cb]
      document.body.removeChild(script)
    }
  })
}

nextjs 如何选择性进行注水

  • getInitialProps 统一数据获取入口,自动区分服务端/客户端执行环境
  • *NEXT_DATA 嵌入 服务端将数据“脱水”至 HTML,客户端直接“注水”复用
  • SSR/CSR 自动路由判断 直接访问 → SSR;前端跳转 → CSR,无需额外配置
  • 注水一致性策略 避免环境差异操作,显式统一数据格式(如语言、时区)
  • 与 react18 的渐进式注水结合 Next.js 12+ 基于 React 18 的 并发特性(Concurrent Features) 实现渐进式注水: 页面分块加载,优先注水可视区域组件。 非关键组件延迟注水,提升首屏响应速度 1。

useImperativeHandle 是 React 中的一个 Hook,它能让你自定义由 ref 暴露出来的句柄。

  • 向父组件暴露一个自定义的 ref 句柄
js
// Input.js
import { useImperativeHandle,useRef } from 'react';
function MyInpt({ref,...props }) {
  const inputRef = useRef(null)
  useImperativeHandle(ref, () => {
    focus() {
        inputRef.current.focus();
      },
      scrollIntoView() {
        inputRef.current.scrollIntoView();
      },
  })
  return <input ref={inputRef} {...props}/>
}

// APP.js
import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
    // 下方代码不起作用,因为 DOM 节点并未被暴露出来:
    // ref.current.style.opacity = 0.5;
  }

  return (
    <form>
      <MyInput placeholder="Enter your name" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}

0716

  • 1498
  • 表单提交为啥不会跨域? 同源策略主要限制 JavaScript 发起的请求(如 XMLHttpRequest、Fetch 等),防止恶意脚本通过浏览器获取其他域的敏感数据,而表单提交(form 标签)是浏览器原生行为,非 JavaScript 发起的请求,因此不受同源策略限制,类似于 script 标签一样,不受跨域影响

0717

  • 1499
  • 数组去重
js
function removeDup(arr) {
  let m = new Map()
  for (let i = 0; i < arr.length; i++) {
    let item = arr[i]
    if (m.has(item)) {
      arr.splice(i, 1)
    } else {
      m.set(item, i)
    }
  }
  return arr
}
removeDup([9, 22, 22, 1, 3, 44, 5, 22])

买卖股票的最佳时候

js
function maxBenift(prices) {
  let max = 0
  let min = prices[0]
  for (let i = 0; i < prices.length; i++) {
    let cur = prices[i]
    min = Math.min(cur, min)
    max = Math.max(max, cur - min)
  }
  return max
}

手写代码题 合并两个有序数组

js
// 合并两个有序数组

// 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

// 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

// 注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

// 示例 1:

// 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
// 输出:[1,2,2,3,5,6]
// 解释:需要合并 [1,2,3] 和 [2,5,6] 。
// 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
var merge = function (nums1, m, nums2, n) {
  for (let i = m; i < m + n; i++) {
    nums1[i] = nums2[i - m]
  }
  return nums1.sort((a, b) => a - b)
}

0718

  • 1500
  • 无聊至极的一天,安心躺着心有不甘
  • 手写 TS IsEqual / TS 实现内置函数 Parameters 和 ReturnTypes
ts
type MyEqual<A, B> = (<T>(arg: A) => T extends A ? 1 : 2) extends <T>(
  arg: B
) => T extends B ? 1 : 2
  ? true
  : false

function callName(name: string, age: Number) {
  return name
}
type Test1 = typeof callName
type TT3 = ReturnType<Test1>
type MyParameters<F extends (...arg: any) => any> = F extends (
  ...arg: infer P
) => any
  ? P
  : never
type TT2 = MyParameters<Test1>
type MockReturnType<T extends (...arg: any) => any> = T extends (
  ...arg: any
) => infer P
  ? P
  : any
type TT4 = MockReturnType<Test1>

0722

  • 1504
  • 如果设置和管理多个 gitlab 账号

INFO

删除旧 SSH 密钥(本地+远程)​

js
# 进入SSH目录
cd ~/.ssh
# 删除默认密钥(若存在)
rm id_rsa id_rsa.pub
# 删除其他自定义密钥(如gitlab_old等)
rm your_old_key your_old_key.pub

为两个 GitLab 生成独立密钥对 ​

js
1. ​生成密钥对(区分账户)
# 为第一个GitLab账户生成
ssh-keygen -t ed25519 -C "account1@email.com" -f ~/.ssh/gitlab_account1
# 为第二个GitLab账户生成
ssh-keygen -t ed25519 -C "account2@email.com" -f ~/.ssh/gitlab_account2

2.添加密钥到SSH代理
ssh-add ~/.ssh/gitlab_account1
ssh-add ~/.ssh/gitlab_account2
验证加载状态:ssh-add -l 应显示两条记录

3.将公钥添加到GitLab

配置 SSH 自动切换(核心步骤)​

在 ~/.ssh/config 文件中定义规则(无此文件则创建)

js
// 第一个账户
Host gitlab.xmly.com # 自定义别名(用于克隆命令)
HostName gitlab.xmly.com # 实际域名
User git
IdentityFile ~/.ssh/xmly
IdentitiesOnly yes # 强制使用指定密钥

// 第二个 GitLab 账户

Host gitlab.qz.com
HostName gitlab.qz.com # 若为自建 GitLab 需修改
User git
IdentityFile ~/.ssh/qz
IdentitiesOnly yes

cd project1 git config user.name "chenpengpeng" git config user.email "pengpeng.chen@xmly.com"

cd project2 git config user.name "chenpengpeng" git config user.email "pengpeng.chen@qz.com"