Code Monkey home page Code Monkey logo

web-studybook's People

Contributors

chunhuigao avatar

Stargazers

 avatar

Watchers

 avatar  avatar

web-studybook's Issues

北冥星眸

  • 异步中间件 redux-thunk
  • 下载 excel 如何获取原文件名
  • 大文件传输
  • promise
  • this.state 是否可以修改

axios中interceptors实现原理

发布订阅者模式

// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
    // 请求发送前的处理
    return config;
  }, function (error) {
    // 请求发送错误的处理
    return Promise.reject(error);
  });

源码

import { RejectedFn, ResolvedFn } from '../types'

interface Interceptor<T> {
  resolved: ResolvedFn<T>
  rejected?: RejectedFn
}

// 拦截管理器类,这里使用 T 类型是因为请求拦截器是 resovle 方法处理配置(AxiosRequestConfig),响应拦截器 resolve 方法处理响应数据( AxiosResponse )
export default class InterceptorManager<T> {
  private interceptors: Interceptor<T>[];

  constructor() {
    this.interceptors = [];
  }

  // 添加拦截器
  use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number {
    this.interceptors.push({
      resolved,
      rejected
    });
    return this.interceptors.length - 1;
  }

  // 遍历拦截器,并执行 fn 方法
  forEach(fn: (interceptor: Interceptor<T>) => void): void {
    this.interceptors.forEach(interceptor => {
      if (interceptor !== null) {
        fn(interceptor);
      }
    });
  }

  // 移除拦截器
  eject(id: number): void {
    if (this.interceptors[id]) {
      this.interceptors[id] = null;
    }
  }
}

银行卡号Luhn校验算法

银行卡号Luhn校验算法

//银行卡号Luhn校验算法
//luhn校验规则:16位银行卡号(19位通用):
//1.将未带校验位的 15(或18)位卡号从右依次编号 1 到 15(18),位于奇数位号上的数字乘以 2。
//2.将奇位乘积的个十位全部相加,再加上所有偶数位上的数字。
//3.将加法和加上校验位能被 10 整除。
// "621 7858 0000 3134 5785",
//  "6225760008219524",
// 5432123456788881


function luhnCheck(bankno) {
  var lastNum = bankno.substr(bankno.length - 1, 1); //取出最后一位(与luhn进行比较)
  var first15Num = bankno.substr(0, bankno.length - 1); //前15或18位
  var newArr = new Array();
  for (var i = first15Num.length - 1; i > -1; i--) {
    //前15或18位倒序存进数组
    newArr.push(first15Num.substr(i, 1));
  }
  var arrJiShu = new Array(); //奇数位*2的积 <9
  var arrJiShu2 = new Array(); //奇数位*2的积 >9
  var arrOuShu = new Array(); //偶数位数组
  for (var j = 0; j < newArr.length; j++) {
    if ((j + 1) % 2 == 1) {
      //奇数位
      if (parseInt(newArr[j]) * 2 < 9) arrJiShu.push(parseInt(newArr[j]) * 2);
      else arrJiShu2.push(parseInt(newArr[j]) * 2);
    } //偶数位
    else arrOuShu.push(newArr[j]);
  }
  var jishu_child1 = new Array(); //奇数位*2 >9 的分割之后的数组个位数
  var jishu_child2 = new Array(); //奇数位*2 >9 的分割之后的数组十位数
  for (var h = 0; h < arrJiShu2.length; h++) {
    jishu_child1.push(parseInt(arrJiShu2[h]) % 10);
    jishu_child2.push(parseInt(arrJiShu2[h]) / 10);
  }
  var sumJiShu = 0; //奇数位*2 < 9 的数组之和
  var sumOuShu = 0; //偶数位数组之和
  var sumJiShuChild1 = 0; //奇数位*2 >9 的分割之后的数组个位数之和
  var sumJiShuChild2 = 0; //奇数位*2 >9 的分割之后的数组十位数之和
  var sumTotal = 0;
  for (var m = 0; m < arrJiShu.length; m++) {
    sumJiShu = sumJiShu + parseInt(arrJiShu[m]);
  }
  for (var n = 0; n < arrOuShu.length; n++) {
    sumOuShu = sumOuShu + parseInt(arrOuShu[n]);
  }
  for (var p = 0; p < jishu_child1.length; p++) {
    sumJiShuChild1 = sumJiShuChild1 + parseInt(jishu_child1[p]);
    sumJiShuChild2 = sumJiShuChild2 + parseInt(jishu_child2[p]);
  }
  //计算总和
  sumTotal =
    parseInt(sumJiShu) +
    parseInt(sumOuShu) +
    parseInt(sumJiShuChild1) +
    parseInt(sumJiShuChild2);
  //计算luhn值
  var k = parseInt(sumTotal) % 10 == 0 ? 10 : parseInt(sumTotal) % 10;
  var luhn = 10 - k;
  if (lastNum == luhn) {
    console.log("luhn验证通过");
    return true;
  } else {
    console.log("银行卡号必须符合luhn校验");
    return false;
  }
}

//检查银行卡号
function CheckBankNo(bankno) {
  if (typeof bankno === "number") bankno = String(bankno);

  var bankno = bankno.replace(/\s/g, "");
  if (bankno == "") {
    return "请填写银行卡号";
    return false;
  }
  if (bankno.length < 16 || bankno.length > 19) {
    console.log("银行卡号长度必须在16到19之间");
    return false;
  }
  var num = /^\d*$/; //全数字
  if (!num.exec(bankno)) {
    console.log("银行卡号必须全为数字");
    return false;
  }
  //开头6位
  var strBin =
    "10,18,30,35,37,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,60,62,65,68,69,84,87,88,94,95,98,99";
  if (strBin.indexOf(bankno.substring(0, 2)) == -1) {
    console.log("银行卡号开头6位不符合规范");
    return false;
  }

  return luhnCheck(bankno);
}
const list = [
  "5432123456788881",
  "6225881414207430",
  "6227007200120897790",
  "6259650871772098",
  "6217858000031345785",
];
let result = [];
for (let i = 0; i < list.length; i++) {
  const c = CheckBankNo(list[i]);
  result.push(c);
}
console.log(result);

一段正则表达式

匹配a-b字符串中间最多有5个非空字符正则表达式

const reg = new RegExp(/a([\S]{0,5})b/g);

为什么删除WillMount、WillUpdate?

新的Fiber架构能在scheduler的调度下实现暂停继续,排列优先级,Lane模型能使Fiber节点具有优先级,在高优先级的任务打断低优先级的任务时,低优先级的更新可能会被跳过,所有以上生命周期可能会被执行多次,和之前版本的行为不一致。

宏任务与微任务

宏任务

  • setTimeout
  • setInterval
  • script
  • ajax
  • DOM事件
  • messageChannel

微任务

  • Promise
  • async/await
  • MutationObserver
  • Node 环境下的 process.nextTick

AMD、CMD、UMD、ES6

模块化之前

最初 js 是这样写的

<script>
  function main(){' '}
  {
    // doing
  }
  main();
</script>

这样写的 js 随着代码增加会带来几个问题:

  • main 函数变量在全局作用域
  • 代码复用
  • 代码可维护性

解决上述问题

命名空间

var namespace = {
  main: function () {
    //doing
  },
};
namespace.main();

闭包 IIFE

var utils = function () {
  var namespace = {
    main: function () {
      //doing
    },
  };
  return namespace;
};
utils.main();

缺点

需要开发人员知道引用顺序,在使用命名空间或者闭包中的方法时要提前引用

服务端模块化

2009 年 node 中实现了 Common.js

// tool.js

function main() {
  console.log('main');
}
module.exports = main;

// index.js
var tool = require('./tool.js');
tool.main();

同步读取硬盘中资源,服务端读取硬盘中资源几乎没什么延时;但是浏览器如果同步读取资源。创建 http -> 加载 -> 返回资源。这个延时就比较长了。可能会引起浏览器假死。所以浏览器中中使用异步模块加载

浏览器模块化

浏览器中中使用异步模块加载

AMD

  • AMD 是异步模块定义;
  • AMD 采用异步方式加载模块。模块加载不影响后面语句执行。
  • AMD 所有依赖这个模块的语句都定义在这个回调函数中,等模块加载完成之后再回调这个函数。
  • AMD 通过 define 函数定义模块,通过 require 函数引用模块
    • define 函数第一个参数是数组,数组中是依赖模块,第二个参数是模块的返回值
    • require 函数第一个参数是数组,数组中是依赖模块,第二个参数是个回调,回调的参数是依赖的输出
  • 被依赖的文件需要早于依赖文件的加载就可以通过 require 解决
  • 在使用 require 的时候需要提前加载所有依赖
  • 所以被称为依赖前置
// tool.js

define([], function (require, factory) {
  'use strict';
  return {
    main: function () {
      console.log(111);
    },
  };
});

// index.js
require(['./tool.js'], function (tool) {
  tool.main();
});

CMD

  • 就近依赖
  • 在需要的时候 require
// tool.js
function main() {
  console.log('main');
}
module.exports = main;

// index.js
define(function (require, exports) {
  const tool = require('./tool.js');
  tool.main;
});

UMD

  • 通用模块定义
  • 写了一段代码,但是想在浏览器中和服务端中同时使用
  • UMD 就是帮助判断环境是使用 AMD 还是使用 Common.js 的方式定义模块,以上都不是,挂载到全局

ES6

  • import 导入 export 导出
  • Common.js 输出的是值的拷贝,ES6 输出的是值的引用
  • Common.js 是运行时加载,ES6 模块是编译事输出接口

ECMA和Web的关系

ECMA Script与Web没有依赖关系,Web浏览器是ECMA Script得宿主环境之一;

hooks不能写在条件判断中

hooks依赖执行顺序,hooks在执行时会按顺序存储在链表中,如果写在条件判断中,就没法保持链表的顺序

纯css实现点击波纹效果

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .box {
        width: 100px;
        height: 100px;
        margin: 0 auto;
        border: 1px solid #3f3;
        transition: all 0.5s;// 我控制点击后放开的效果
      }
      .box:active {
        transform: scale(0.5);
        transition: all 0.1s cubic-bezier(0, 0.25, 0.9, 1);// 我控制鼠标点击时的效果
      }
  
    </style>
  </head>
  <body>
    <div class="box" id="box">点击我,操作动画</div>
  </body>

</html>

BFC

  • 块级格式化上下文
  • 是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域

作用

  • 包含内部浮动
  • 排除外部浮动
  • 阻止外边距重叠

如何创建BFC

  • 根元素html
  • 浮动元素
  • 定位元素
  • 行内元素
  • 表格元素
  • 弹性元素
  • 网格元素

一个简单的深拷贝函数

常用的方式,递归处理对象

function deepCopy(o) {
  if (typeof o === 'object') {
    const type = Object.prototype.toString.call(o);
    switch (type) {
      case '[object Object]':
        const object = {};
        Object.keys(o).forEach((key) => {
          object[key] = deepCopy(o[key]);
        });
        return object;
      case '[object Array]':
        const list = [];
        o.forEach((v, i) => {
          list[i] = deepCopy(v);
        });
        return list;
      case '[object Function]':
        const fn = function () {};
        fn.call(o);
        return fn;
      case '[object Null]':
        return null;
      case '[object Date]':
        return new Date(o);
      default:
        break;
    }
  } else {
    return o;
  }
}

一道简单的面试题获取URL参数

题目要求

输入URL参数,返回URL参数的对象

function start(url) {
  if (url) {
    const [_, p] = url.split('?');
    if (p) {
      const list = p.split('&');
      const obj = {};
      for (let i = 0; i < list.length; i++) {
        const [k, v] = list[i].split('=');
        if (obj[k]) {
          obj[k].push(v);
        } else {
          obj[k] = [v];
        }
      }
      Object.keys(obj).forEach((k) => {
        if (obj[k].length === 1) obj[k] = obj[k][0];
      });
      return obj;
    } else {
      return {};
    }
  } else {
    return {};
  }
}

js链式调用

问题

const boy = new PlayBoy('Tom') 
boy.sayHi().sleep(1000).play('王者').sleep(2000).play('跳一跳') 
// 输出 
// Tom 
// 1s 之后 
// 王者 
// 2s 之后 
// 跳一跳

代码

function PlayBoy(name) {
      this.val = [];
      this.idx = 0;
      this.sayHi = () => {
        console.log(`大家好,我是${name}`);
        return this;
      };
      this.sleep = (time) => {
        setTimeout(() => {
          console.log(this.val[this.idx++]);
        }, time);
        return this;
      };
      this.play = (val) => {
        this.val.push(val);
        return this;
      };
      return this;
    }
    const boy = new PlayBoy('Tom');
    boy.sayHi().sleep(1000).play('王者').sleep(2000).play('跳一跳');

React的fiber

  • fiber 是 react 为践行 concurrent 模式提出的一种全新数据结构
  • fiber 作为静态数据结构,包含 ReactElement 阶段全部信息和与其他 fiber 节点关系
  • fiber 作为动态单元,包含节点更新的状态和节点需要执行的副作用

new操作符

  • 在内存中创建一个新对象
  • 新对象内部的[[prototype]]被赋值为构造函数的prototype
  • 构造函数的this被赋值为当前新对象
  • 执行构造函数代码
  • 构造函数返回非空对象,返回这个对象;否则返回新创建的对象

摘自:《JavaScript高级程序设计(第四版)》

React 函数组件与类组件区别

相同点

  • 都可以接收 props
  • 都会返回 React Element

不同点

  • 编程**不同
    • 函数组件是函数式编程,相同输入可以得到相同输出
    • 类组件是面向对象编程,需要创建实例
  • 内存占用不用
    • 类组件需要创建实例,更占内存一些
  • 组件状态
    • 类组件有自己的状态
    • 函数组件没有自己的状态,
  • 生命周期
    • 类组件有完整的生命周期
    • 函数组件没有生命周期,只有 useEffect 类似生命周期
  • 逻辑复用
    • 类组件逻辑复用较难,可以通过 HOC 复用组件逻辑,但是会带来嵌套地狱
    • 函数组件使用函数编程,逻辑通过 hooks 复用;组合优于继承,显然函数组件更有优势
  • 更新优化
    • 类组件使用 shouldComponentUpdate 和 pureComponent
    • 函数组件使用 React.memo

react-scheduler

scheduler 调度器
react 为了践行 concurrent 模式,使用 scheduler 调度任务

两个作用

  • 时间切片
  • 任务调度

合并链表疑问

代码如下,不知道为什么不对

const s1 = readline()
const s2 = readline()
const list1 = JSON.parse(s1 || '[]')
const list2 = JSON.parse(s2 || '[]')

let node1 = arrayToNodeList(list1)
let node2 = arrayToNodeList(list2)

const result = []
while (node1 || node2) {
  if (node1 && node2) {
    if (node1.val > node2.val) {
      result.push(node2.val)
      node2 = node2.next
    } else {
      result.push(node1.val)
      node1 = node1.next
    }
  } else {
    if (node1) {
      result.push(node1.val)
      node1 = node1.next
    }
    if (node2) {
      result.push(node2.val)
      node2 = node2.next
    }
  }
}

const res = arrayToNodeList(result)

console.log(s1, s2, res)

// 链表构造函数
function ListNode(val) {
  this.val = val
  this.next = null
}

//数组转链表
function arrayToNodeList(list) {
  let header = new ListNode(0)
  let current = header
  for (let i = 0; i < list.length; i++) {
    current.next = { val: Number(list[i]), next: null }
    current = current.next
  }
  return header.next
}

// 链表转数组
function nodeListToArray(node) {
  const list = []
  let header = node
  while (header) {
    list.push(header.val)
    header = header.next
  }
  return list
}

设计模式-单例模式

单例模式

var ProxySingleton = (function () {
  var instance;
  return function (html) {
    if (!instance) {
      instance = new CreateDiv(html);
    }
    return instance;
  };
})();
var a = new ProxySingleton('test1');
var b = new ProxySingleton('test2');

懒汉模式与恶汉模式

performance和Date

  • performance.now()精确点高,不依靠系统时间,但是兼容性有问题。
    • React源码中使用 performance 获取时间精度。
  • Date.now()会受系统时间影响,且以Unix时间为基准,不易看懂,无兼容性问题。

函数式编程

函数式编程特点

  • 就是利用计算机的计算能力将输入转化成对应的输出
  • 函数式编程中的函数指的不是编程语言里的函数,而是数学意义上的映射关系。比如 y=sin(x) 中 x 和 y 值的映射关系
  • 纯函数:相同的输入获得相同的输出(无副作用)
  • 函数式编程就是对**数据(函数)**映射关系的抽象。

个人技术前景预览

个人技术前景规划: 技术深度方向

graph TD
两个方向 --> 深度
两个方向 --> 广度
深度 --> 技术深度
深度 --> 行业深度
技术深度 --> 干活速度
技术深度 --> 攻坚难度
技术深度 --> 掌握深度
行业深度 --> 产品感受深
行业深度 --> 运营思考深
行业深度 --> 商业理解深
广度 --> 技术覆盖半径
广度 --> 领域覆盖半径
广度 --> 管理覆盖半径
技术覆盖半径 --> 移动端
技术覆盖半径 --> PC端
技术覆盖半径 --> 客户端
技术覆盖半径 --> 服务端
领域覆盖半径 --> 消费侧
领域覆盖半径 --> 供给侧
领域覆盖半径 --> 金融侧
管理覆盖半径 --> 管人
管理覆盖半径 --> 管事
管理覆盖半径 --> 管财

事件委托

事件委托

利用事件冒泡,指定一个事件处理管理某一类型的所有事件。

解决什么问题?
JavaScript添加的页面的事件处理程序的数量直接影响页面整体运行性能,因为函数是对象,是对象就会占用内存,内存中对象越多,性能越差。所以可以使用时间委托,将多个统一类型的事件委托给单一的事件处理程序

出自:JavaScript高级程序设计第三版第402页

偶遇算法-字符串的解压缩

题目

有一种简易压缩算法:针对全部为小写英文字母组成的字符串, 将其中连续超过两个相同字母的部分压缩为连续个数加该字母 其他部分保持原样不变. 例如字符串 aaabbccccd 经过压缩变成字符串 3abb4cd
请您编写解压函数,根据输入的字符串,判断其是否为合法压缩过的字符串。
若输入合法则输出解压缩后的字符串,否则输出字符串"!error"来报告错误。

输入描述:

输入一行,为一个ASCII字符串
长度不超过100字符
用例保证输出的字符串长度也不会超过100字符

输出描述:

若判断输入为合法的经过压缩后的字符串
则输出压缩前的字符串
若输入不合法 则输出字符串"!error"

示例 1:

输入:4dff
输出: ddddff
解释:4d扩展为4个d ,故解压后的字符串为ddddff

示例 2:

输入:2dff
输出: !error
解释:2个d不需要压缩 故输入不合法

示例 3:

输入:4d@A
输出: !error
解释:全部由小写英文字母组成的字符串,压缩后不会出现特殊字符@和大写字母A 故输入不合法

代码

function decode(s) {
  const reg = new RegExp(/(\w)\1{2}/g);

  if (reg.test(s)) {
    console.log('!error');
  } else {
    const len = s.length;
    let num = 0;
    let string = '';
    const list = [];
    let result = null;
    for (let i = 0; i < len; i++) {
      const c = s[i];

      if (isDigit(c) || isAlp(c)) {
        if (isDigit(c)) {
          if (string) {
            list.push([1, string]);
          }
          num = num * 10 + Number(c);
          string = '';
        } else {
          string += c;
          if (num === 0) {
          } else if (num < 3) {
            result = '!error';
            break;
          } else {
            if (i < len - 1) {
              if (c === s[i + 1]) {
                result = '!error';
                break;
              }
            }
            list.push([num, string]);
            string = '';
          }

          num = 0;
        }
      } else {
        result = '!error';
        break;
      }
    }

    if (result) {
      console.log(result);
    } else {
      if (num > 0) {
        console.log('!error');
      } else {
        if (string) {
          list.push([1, string]);
        }
        let r = '';
        list.forEach((v) => {
          const [n, s] = v;
          r += s.repeat(n);
        });
        console.log(r);
      }
    }
  }
  function isAlp(s) {
    const n = s.charCodeAt() - 'a'.charCodeAt();
    return n >= 0 && n <= 26;
  }
  function isDigit(s) {
    const n = s.charCodeAt() - '0'.charCodeAt();
    return n >= 0 && n <= 9;
  }
}

const testList = ['4dff', '2dff', '4d@A', '5a', '3a4b'];
testList.forEach((v) => {
  decode(v);
});

js使用工具-金钱分转元

简单明了

const fenToyuan = (n) => {
  const s = String(n);
  const len = s.length;
  if (len === 1) {
    return '0.0' + s;
  } else if (len === 2) {
    return '0.' + s;
  } else {
    return s.substring(0, len - 2) + '.' + s.substring(len - 2);
  }
};

比较复杂的方案

const toDecimal2 = (x) => {
  var f = parseFloat(x);
  if (isNaN(f)) {
    return false;
  }
  var f = Math.round(x * 100) / 100;
  var s = f.toString();
  var rs = s.indexOf('.');
  if (rs < 0) {
    rs = s.length;
    s += '.';
  }
  while (s.length <= rs + 2) {
    s += '0';
  }
  return s;
};

const FenToYuan = (fen) => {
  var num = fen;
  num = fen * 0.01;
  num += '';
  var reg =
    num.indexOf('.') > -1
      ? /(\d{1,3})(?=(?:\d{3})+\.)/g
      : /(\d{1,3})(?=(?:\d{3})+$)/g;
  num = num.replace(reg, '$1');
  num = toDecimal2(num);
  return num;
};

// 验证100 - 10000000 没问题
for (let i = 100; i < 10000000; i++) {
  const n = FenToYuan(i);
  const s = String(i);
  const t = n.replace(/\./g, '');
  if (s !== t) {
    console.log(i, n);
  }
}
console.log('验证结束');

重排(reflow)和重绘(repaint)

重排

无论通过什么方式影响了元素的几何信息(元素在视口内的位置和尺寸大小),浏览器需要重新计算元素在视口内的几何属性,这个过程叫做重排。

重绘

通过构造渲染树和重排(回流)阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(元素在视口内的位置和尺寸大小),接下来就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘。

何时重排

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
  • 页面一开始渲染的时候(这肯定避免不了)
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

手写Promise.all

Promise.all = function (promises) {
  let count = 0
  let len = promises.length
  let result = []
  return new Promise((resolve, reject) => {
    for (let i = 0; i < len; i++) {
      Promise.resolve(promises[i])
        .then((value) => {
          result[i] = value
          count++
          if (count === len) resolve(result)
        })
        .catch((e) => {
          reject(e)
        })
    }
  })
}

script 标签 defer 和 async 区别

  • script 标签默认属性会阻塞 html 解析,知道 js 加载完成并执行结束后 html 才能继续执行
  • script 标签设置 async 属性,js 加载不会阻塞 html 解析,加载完成开始执行会阻塞 html 解析
  • script 标签设置 defer 属性,异步加载 js 文件,等待 html 解析完成后在执行 js

Map和Object的区别

用法上

  • Map不会覆盖同名属性
  • Map可以获取大小
  • Map可以使用任意值作为key
  • Map的key是按照顺序添加的
  • Map可迭代

性能上

  • Map在添加无需key值是性能优于Object;
  • Map在删除数据是,性能优于Object
  • Map更节省内存

其他

Map是Object的子集

手写Promise(node版)

const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
class Promise {
  constructor(executor) {
    if (typeof executor !== "function") {
      return new TypeError(`Promise resolver ${executor} is not a function`);
    }
    this.state = PENDING;
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (e) {
      this.reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== "function") {
      onFulfilled = (value) => value;
    }
    if (typeof onRejected !== "function") {
      onRejected = (err) => {
        throw err;
      };
    }
    let promise2 = new Promise((resolve, reject) => {
      if (this.state === FULFILLED) {
        process.nextTick(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.state === REJECTED) {
        process.nextTick(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          process.nextTick(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          process.nextTick(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });
    return promise2;
  }
}

const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x)
    return reject(
      new TypeError("Chaining cycle detected for promise #<Promise>")
    );

  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let called;
    try {
      const then = x.then;
      if (typeof then !== "function") resolve(x);
      else {
        then.call(
          x,
          (value) => {
            if (called) return;
            called = true;

            resolvePromise(promise2, value, resolve, reject);
          },
          (reason) => {
            if (called) return;
            called = true;
            reject(reason);
          }
        );
      }
    } catch (err) {
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    resolve(x);
  }
};

React 优化

前言

react 优化从减少渲染真实 DOM 的频率,减少虚拟 DOM 的对比频率两个方面

事件清理

在组件上绑定的定时器,监听事件需要在组件卸载的时候删除

class 组件

pureComponent 和 shouldComponentUpdate

react.memo

将函数组件变成纯组件,将当前 props 与上一次 props 对比,如果不发生变化,回阻止组件重新渲染

组件懒加载

使用 lazy 包裹一下 import 引用组件

使用 fragment

占位标记符,用于标记额外无意义标签

减少内联函数定义

添加事件时,如果使用内联函数,每次 render 会生成新的函数实例,在 diff 对比时,新旧函数实例不同会导致 react 总是绑定新的函数实例,而旧的函数实例又需要垃圾回收器处理

避免内联样式

内联样式会被编译成 js 代码,通过 js 将样式映射到元素上,需要 js 花更多的时间执行脚本,增加组件负担

错误边界

避免数据结构突变

hooks 优化

使用 useMemo 缓存,监测值不发生变化,不会重新计算
使用 useCallback 缓存函数,使重新渲染总能获得相同函数

JavaScript与ECMA的关系

完整的JavaScript由三部分组成

  • 核心是ECMA
  • 文档对象模型(DOM)
  • 浏览器对象模型(BOM)

偶遇算法

1、数字反转打印

function start(n) {
  const paths = [];
  for (let i = 1; i <= n; i++) {
    let c = firstNum(i);
    paths.forEach((x) => {
      x.unshift('    ');
    });
    const list = [];

    for (let j = 0; j < i; j++) {
      const s = `${c++}***`;
      list.push(s.substring(0, 4));
      if (j != i - 1) {
        list.push('    ');
      }
    }
    if (i % 2 === 0) {
      list.reverse();
    }
    paths.push(list);
  }
  paths.forEach((v) => {
    const s = v.join('');
    console.log(s);
  });
}

const n = readline();
start(n);

function firstNum(n) {
  if (n === 1) return 1;
  return firstNum(n - 1) + (n - 1);
}

function readline() {
  return 4;
}

2、最大子矩阵

function maxSubmatrix(matrix) {
  const n = matrix.length;

  if (n == 0) return 0;

  const m = matrix[0].length;

  if (m == 0) return 0;

  let result = matrix[0][0];
  const dp = [];
  for (let i = 0; i <= n; i++) {
    dp[i] = [];
    for (let j = 0; j <= m; j++) {
      dp[i][j] = 0;
    }
  }
  dp[1][1] = matrix[0][0];
  for (let i = 2; i <= n; i++) {
    dp[i][1] = dp[i - 1][1] + matrix[i - 1][0];
  }
  for (let i = 2; i <= m; i++) {
    dp[1][i] = dp[1][i - 1] + matrix[0][i - 1];
  }

  for (let i = 2; i <= n; i++) {
    for (let j = 2; j <= m; j++) {
      dp[i][j] =
        dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1];
    }
  }

  for (let x1 = 1; x1 <= n; x1++) {
    for (let y1 = 1; y1 <= m; y1++) {
      //枚举右下角

      for (let x2 = x1; x2 <= n; x2++) {
        for (let y2 = y1; y2 <= m; y2++) {
          //记录最大值

          result = Math.max(
            result,
            dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]
          );
        }
      }
    }
  }
  console.log('result', result);
}

var matrix = [
  [951, 589, 39],
  [-583, -710, 473],
  [-229, 501, -594],
];
var aa = maxSubmatrix(matrix);

3、矩阵最大值

function maxMatrix(matrix) {
  const m = matrix.length;
  let result = 0;
  for (let i = 0; i < m; i++) {
    const list = matrix[i];
    const s = list.join('');
    const ss = s + s;
    let max = 0;
    for (let i = 0; i < ss.length / 2; i++) {
      const c = ss.substring(i, i + s.length);
      max = Math.max(max, parseInt(c, 2));
    }
    result += max;
  }
  return result;
}

var matrix = [
  [1, 0, 0, 0, 1],
  [0, 0, 0, 1, 1],
  [0, 1, 0, 1, 0],
  [1, 0, 0, 1, 1],
  [1, 0, 1, 0, 1],
];
var aa = maxMatrix(matrix);

console.log(aa);

4、仿 LISP 运算

function lisp(s) {
  let t = s.trim();
  t = t.substring(1, t.length - 1);
  t = t.trim();
  const list = [];
  let num = 0;
  let flag = 0;
  for (let i = 3; i < t.length; i++) {
    const c = t[i];
    if (isDigit(c)) {
      while (i < t.length && isDigit(t[i])) {
        num = num * 10 + Number(c);
        i++;
      }
      i--;

      list.push(flag ? -num : num);
      num = 0;
      flag = 0;
    } else if (c === '(') {
      let j = i;
      let count = 0;
      for (; i < t.length; i++) {
        if (t[i] === '(') count++;
        if (t[i] === ')') count--;
        if (count === 0) break;
      }
      num = lisp(t.substring(j - 1, i + 1));
      list.push(flag ? -num : num);
      num = 0;
      flag = 0;
    } else {
      if (c === '-') {
        flag = 1;
      }
    }
  }
  const op = t.substring(0, 3);

  const [a, b] = list;

  switch (op) {
    case 'add':
      return a + b;
    case 'mul':
      return a * b;
    case 'sub':
      return a - b;
    case 'div':
      if (b === 0) {
        console.log('error');
      } else {
        return a / b;
      }

    default:
      console.log(error);
  }
}

function isDigit(s) {
  const n = s.charCodeAt() - '0'.charCodeAt();
  return Number(s) >= 0 && Number(s) <= 9 && n >= 0 && n <= 9;
}
var list = [
  '(mul 3 -7)',
  '(add 1 2)',
  '(sub (mul 2 4) (div 9 3))',
  '(div 1 0)',
];

list.forEach((s) => {
  var aa = lisp(s);
  console.log(aa);
});

5、最小传输时延

var networkDelayTime = function (times, n, k) {
  const INF = Number.MAX_SAFE_INTEGER;
  const g = new Array(n).fill(INF).map(() => new Array(n).fill(INF));
  for (const t of times) {
    const x = t[0] - 1,
      y = t[1] - 1;
    g[x][y] = t[2];
  }

  const dist = new Array(n).fill(INF);
  dist[k - 1] = 0;
  const used = new Array(n).fill(false);
  for (let i = 0; i < n; ++i) {
    let x = -1;
    for (let y = 0; y < n; ++y) {
      if (!used[y] && (x === -1 || dist[y] < dist[x])) {
        x = y;
      }
    }
    used[x] = true;
    for (let y = 0; y < n; ++y) {
      dist[y] = Math.min(dist[y], dist[x] + g[x][y]);
    }
  }

  let ans = Math.max(...dist);
  return ans === INF ? -1 : ans;
};

6、拼接 URL

function URLPre(s) {
  const list = s.split(',');
  if (list.length === 0) {
    console.log('/');
  } else {
    const path = [];
    for (let i = 0; i < list.length; i++) {
      path.push('/');
      path.push(list[i]);
    }
    const r = path.join('');
    console.log(r.replace(/\/+/g, '/'));
  }
}

var list = ['/acm,/bb', '/acm/bb', '/abc/,/bcd'];

list.forEach((s) => {
  var aa = URLPre(s);
  // console.log(aa);
});

7、二叉树存储数组

function treeList(list) {
  let map = {};
  let min = Math.max(...list);
  list.unshift(-1);
  const len = list.length;

  dfs(1, []);
  let index = map[min];
  const result = [];

  while (index > 0) {
    result.unshift(list[index]);
    index = parent(index);
  }
  console.log(result.join(' '));

  function dfs(i) {
    if (i >= len) return;
    const l = left(i);
    const r = right(i);
    if ((l >= len && r >= len) || (list[l] === '-1' && list[r] === '-1')) {
      const c = Number(list[i]);
      if (c <= min) {
        min = c;
        map[min] = i;
      }
    } else {
      list[l] !== '-1' && dfs(l);
      list[r] !== '-1' && dfs(r);
    }
  }

  function left(x) {
    return 2 * x;
  }
  function right(x) {
    return 2 * x + 1;
  }
  function parent(x) {
    return Math.floor(x / 2);
  }
}

var list = ['3 5 7 -1 -1 2 4', '5 9 8 -1 -1 7 -1 -1 -1 -1 -1 6'];

list.forEach((s) => {
  var aa = treeList(s.split(' '));
  // console.log(aa);
});

8、服务器广播

function ServiceBroadcast(input) {
  const arr = input;
  const len = arr.length;
  const res = [];
  for (let i = 0; i < len; i++) {
    let flag = false;
    let temp = null;
    for (const x of res) {
      if (x.has(i)) {
        temp = x;
        flag = true;
        break;
      }
    }
    if (!flag) {
      const set = new Set();
      set.add(i);
      res.push(set);
      temp = set;
    }
    for (let j = i + 1; j < len; j++) {
      if (arr[i][j] === 1) {
        temp.add(j);
      }
    }
  }

  console.log(res.length);
}

var list = [
  [
    [1, 1, 0],
    [1, 1, 0],
    [0, 0, 1],
  ],
];

list.forEach((s) => {
  var aa = ServiceBroadcast(s);
  // console.log(aa);
});

9、最长广播响应

function start(list, p) {
  const map = {};
  const set = new Set();
  for (let i = 0; i < list.length; i++) {
    const [a, b] = list[i];
    if (map[a]) {
      map[a].push(b);
    } else {
      map[a] = [b];
    }

    set.add(a);
    set.add(b);
  }
  const queue = [];
  queue.push(p);
  let result = -1;
  while (queue.length) {
    result++;
    const len = queue.length;
    let end = false;
    for (let i = 0; i < len; i++) {
      const f = queue.shift();
      set.delete(f);

      if (set.size === 0) {
        console.log(result * 2);
        end = true;
        break;
      }
      const array = map[f];

      if (array) {
        queue.push(...array);
      }
    }
    if (end) break;
  }
}

var input = `1 4 2 1 2 3 2 4 3 4 3 5 4 5 2`;
const list = input.split(' ');
const path = [];
for (let i = 0; i < list.length - 1; i += 2) {
  path.push([list[i], list[i + 1]]);
}
const p = list[list.length - 1];
var aa = start(path, p);
console.log(aa);

10、TLV 解码

function TLVAnalyize(tlv, tag) {
  let tlv1 = tlv.split(' ');
  for (let i = 0; i < tlv1.length; ) {
    let len = parseInt(tlv1[i + 2] + tlv1[i + 1], 16);

    if (tag == tlv1[i]) {
      var res = [];

      for (let j = i + 3; j < i + 3 + len; j++) {
        res.push(tlv1[j]);
      }

      return res.join(' ');
    } else {
      i += len + 3;
    }
  }
}
let str =
  '32 01 00 AE 90 02 00 01 02 30 03 00 AB 32 31 31 02 00 32 33 33 01 00 CC';
console.log(TLVAnalyize(str, 31));

CommonJS与ES6区别

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

  • CommonJs 是单个值导出,ES6 Module可以导出多个

  • CommonJs 是动态语法可以写在判断里,ES6 Module 静态语法只能写在顶层

  • CommonJs 的 this 是当前模块,ES6 Module的 this 是 undefined

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.