Skip to content

coding

检测模块循环引用

js
let obj = {
  a: { dependencies: ['b'] },
  b: { dependencies: ['c'] },
  c: { dependencies: ['d'] },
  d: { dependencies: ['a'] },
}
// 检查模块循环引用
function findCycle(obj) {
  if (!obj) return false
  let dfs = (key, set) => {
    if (set.has(key)) {
      return true
    }
    set.add(key)
    for (k of obj[key].dependencies) {
      if (dfs(k, set)) {
        return true
      }
    }
    set.delete(key)
    return false
  }

  for (key in obj) {
    if (dfs(key, new Set())) {
      return true
    }
  }
  return false
}

console.log(findCycle(obj))

斐波那契数列 for循环版

js
function fib(n) {
    if (n <= 1) return n;
    let fibpre = 0;
    let fibcur = 1;
    for (let i = 2; i <= n; i++) {
        let temp = fibcur
        fibcur = fibpre + fibcur
        fibpre = temp
    }
    return fibcur
}

function fib(n) {
    if (n <= 1) return n;
    let fibArr = [1, 1];
    for (let i = 2; i <= n; i++) {
        fibArr.push(fibArr[i - 1] + fibArr[i - 2]);
    }
    return fibArr[n - 1];
}
console.log(fib(10));
js
// 斐波那契数列 递归版(性能差)
function fib(n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}
console.log(fib(10));

取最大值

js
var arr = [2, 34, 54, 34, 2, 345];
var max = arr[0];
for (let index = 1; index < arr.length; index++) {
  if (arr[index] > max) {
    max = arr[index];
  }
}
console.log("最大值", max);
console.log("最大值", Math.max.apply(null, arr));
console.log("最大值", Math.max(...arr));

取最小值

js
var min = arr[0];
for (let index = 1; index < arr.length; index++) {
  if (arr[index] < min) {
    min = arr[index];
  }
}
console.log("最小值", min);
console.log("最小值", Math.min.apply(null, arr));
console.log("最小值", Math.min(...arr));

去重复

js
let newArr = arr.reduce((temp, item) => {
  if (temp.includes(item)) {
    return temp;
  }
  return temp.concat(item);
}, []);
console.log("去重复", newArr);

let resultArr = [...new Set(arr)];
console.log("去重复", resultArr);

数组展平

js
let arr = [1, 2, 3, [4, 5], 6, [7, 8, 9]];
console.log("数组展平", arr.toString().split(","));

let newArr = arr.reduce((tempArr, y) => {
  return tempArr.concat(y);
}, []);
console.log("数组展平", newArr);

var arr = [11, [22, [33, [44]]]];

console.log("数组展平", arr.flat(3));

转换树形菜单

js
const list = [
  { id: 1, name: "电子商品", parentId: 0 },
  { id: 2, name: "衣服", parentId: 0 },
  { id: 3, name: "手表", parentId: 1 },
  { id: 4, name: "手机", parentId: 1 },
  { id: 5, name: "耐克", parentId: 2 },
];
function listToTree(list) {
  if (!Array.isArray(list)) return list;
  let treeList = [];
  list.forEach((item) => {
    // 根节点
    if (+item.parentId === 0) {
      treeList.push(item);
    } else {
      // 找父级节点
      let parent = list.find((p) => p.id === item.parentId);
      // 把自己添加到父级节点下
      (parent.children || (parent.children = [])).push(item);
    }
  });
  return treeList;
}

console.log(listToTree(list));

树转列表

js
function treeTolist(tree, list = []) {
  tree.forEach((item) => {
    if (Array.isArray(item.children) && item.children.length > 0) {
      let { children, ...data } = item;
      list.push(data);
      treeTolist(item.children, list);
    } else {
      list.push(item);
    }
  });
  return list;
}

console.log(treeTolist(treeList));

并发请求

实现一个函数, 可以间隔输出,每4秒输出一次helloWorld, 输出3次

js
// 实现一个函数, 可以间隔输出,每4秒输出一次helloWorld, 输出3次
function createRepeat(fn, repeat, interval) {
  return (params)=>{
    let beginTime = Date.now()
    let endTime = beginTime+(1000*interval)
    let c = 0
    while(beginTime<=endTime && c<repeat){
      beginTime= Date.now()
      if(beginTime===endTime){
        fn(params)
        c++
        endTime = beginTime+(1000*interval)
      }
    }
  }
}

const fn = createRepeat(console.log, 3, 4);
fn('helloWorld'); // 
console.log('end')

引用地址指向问题

js
function changeObjProperty(o) {
  o.siteUrl = "http://www.baidu.com"; 
  o = new Object(); // 指向新的引用地址
  o.siteUrl = "http://www.google.com"; 
}
let webSite = new Object();
changeObjProperty(webSite);
console.log(webSite.siteUrl); // http://www.baidu.com

this指向问题

js
function Parent () {
  this.a = 1;
  this.b = [ 1, 2, 1 ];
  this.c = { dome: 5 };
  this.show = function () {
    console.log( this.a, this.b, this.c.dome );
  };
}

function Chind () {
  this.a = 2;
  this.change = function () {
    this.b.push( this.a ); 
    this.a = this.b.length; 
    this.c.dome = this.a++; 
  };
}

Chind.prototype = new Parent(); // 不是一个实例
var parent = new Parent();  // 不是一个实例
var chind1 = new Chind();
var chind2 = new Chind();
chind1.a = 11;
chind2.a = 12;
parent.show(); // 1 [1,2,1] 5
chind1.show(); // 11 [1,2,1] 5
chind2.show(); // 12 [1,2,1] 5
chind1.change();
chind2.change();
parent.show(); // 1 [ 1,2,1] 5
chind1.show(); // 5 [ 1,2,1,11,12] 5
chind2.show(); // 6 [ 1,2,1,11,12] 5

如何让同时满足a==1、a==2、a==3

  • 1、创建一个对象,重写toString方法
  • 2、对象在和基本类型比较时,会进行隐式转换
  • 3、会先调用toString,让n累加
js
let a = {
  n: 1,
  toString () {
    return this.n++;
  },
};

if ( a == 1 && a == 2 && a == 3 ) {
  console.log( "ok" );
}

parseInt

  • parseInt 把操作数转位十进制整数
  • parseInt 接受第二个参数,如果不传默认或者参数是 0,都是当做 10 进制处理,范围是(2-36),如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN
js
["1", "2", "3"].map((val, index) => parseInt(val, index));
parseInt(1, 0); // 1
parseInt(2, 1); // NaN
parseInt(3, 2); // NaN 将二进制转位10进制,因为二进制只有0和1

闭包作用域案例

js
let a = 10;
let b = 20;

function A ( a ) {
  // var a = 100
  A = function ( y ) {
    console.log( y + b + a++ ); // 200 + 20 + 101
  };
  // 先复制在a+1,所以打印100
  console.log( a++ ); // 100
  console.log( a ); // 101
}
A(100)
A(200) // 结果`200 + 20 + 101= 321`

运算符赋值优先级

赋值优先级等级

  • 解析
    • 1、在堆内存中声明一个变量a,在栈内存开辟一个空间存储对应的引用,a的地址执行对象的引用

    • 2、堆内存中声明一个变量b,直接指向a的引用地址

    • 3、在连等赋值的时候,由于a.x的优先级比较高优先计算,让引用地址的x属性,指向一个新的引用地址

    • 4、在计算a也指向一个新的引用地址

    • 因为a已经指向了新的引用地址,新的对象没有x属性,导致undefined

    • b始终指向一个引用地址,并且加了一个x属性指向一个新的引用

js
var a = {
  n: 1,
};
var b = a;
a.x = a = {
  n: 2,
};
console.log( a.x ); // --> undefined
console.log( b ); // --> {n:1,x:{n:2}}

函数颗粒化

  • 把一个函数进行分解成 N 个执行单元,每一个执行单元执行时去收集参数,当前收集的参数个数达到执行条件时,执行原有的函数
js
function curry(fn) {
  let params = [];
  let inner = (...args) => {
    params.push(...args);
    return params.length >= fn.length ? fn(...params) : inner;
  };
  return inner;
}

function sum(a, b, c, d) {
  return a + b + c + d;
}

let fn = curry(sum);

console.log(fn(1)(2)(3)(4)); // 10
console.log(fn(1, 2)(3, 4)); // 10
console.log(fn(1, 2)(3)(4)); // 10
console.log(fn(1, 2)(3)(4)); // 10

反颗粒化

  • 反柯里化主要是借用别人的函数,比如类数组没有 push 函数,但是可以借用 push 函数
js
Function.prototype.unCurry = function () {
  let self = this;
  return (content) => {
    return self.call(content);
  };
};

Function.prototype.unCurry = function () {
  var self = this;
  return function () {
    return Function.prototype.call.apply(self, arguments);
  };
};

// es6版本
Function.prototype.unCurry = function () {
  return this.call.bind(this);
};
Function.prototype.unCurry = function () {
  return (...args) => this.call(...args);
};

let isType = Object.prototype.toString.unCurry();
console.log(isType([])); // [object Array]

// 数组复制
const clone = Array.prototype.slice.unCurry();
var a = [1, 2, 3];
var b = clone(a);
console.log("a==b:", a === b); // false
console.log(a, b); // [1, 2, 3] [1, 2, 3]

// 类数组
let push = Array.prototype.push.unCurry();
let o = { a: 1 };
push(o, 2);
console.log(o); // { '0': 2, a: 1, length: 1 }

函数执行上下文

  • 函数执行的上级,上下文和函数在哪执行的没关系,只和它的作用域有关系「作用域由创建函数时候的上下文来决定」
js
function fn1(){
  let a = 10
  return function(){
    console.log(a);
  }
}

let f = fn1()

function fn2(){ 
  let a = 20
  f()
}
fn2() // 10

作用域案例

js
var x =3;
var obj = {x:5};
obj.fn =(function(){
  this.x *= ++x // => this.x * (++x)
  return function(y){
    this.x *= (++x)+y // => this.x * (++x+y)
    console.log(x) 
  }
})()

var fn = obj.fn
obj.fn(6) // 13
fn(4) // 234
console.log(obj.x,x) // 95 234

函数执行,小括号表达式对this的影响

  • 小括号中包含“多项”,这样也只取最后一项,但是this受到影响
js
function fn () {
  console.log( this )
}
let obj = {
  name: 'hl',
  fn
}
(obj.fn)(); // obj
('10',obj.fn)(); // Window

var、作用域变量提升

  • 在函数作用域中用var声明的会变量提升,优先找函数内部的
  • 此时var声明的变量a声明未定义是undefined,undefined取反为true,赋值a=10
js
var a = 1
function f1(){
  if(!a){
    var a = 10
  }
  console.log(a)
}
f1() // 10

var变量提升和函数提升案例

  • var只会提前提示声明,function声明定义一起完成
  • 这里function同一个函数多次声明,后面的会覆盖前面的
  • 当代码执行到var时,会覆盖函数的定义
js
fn(); // 5
function fn () { console.log( 1 ); }
fn(); // 5
function fn () { console.log( 2 ); }
fn(); // 5
var fn = function () { console.log( 3 ); }
fn(); // 3
function fn () { console.log( 4 ); } // 执行到这里,因为函数已经提前声明定义了,这里并不会有操作
fn(); // 3
function fn () { console.log( 5 ); }
fn(); // 3

函数调用变量提升(形参)

js
console.log(a, b, c);  // undefined  undefined undefined
var a = 12,
  b = 13,
  c = 14;
function fn(a) {
  // 形参相当于var a = 10(私有)
  console.log(a, b, c); // 10  13 14
  a = 100; // 私有
  c = 200; // 全局
  console.log(a, b, c); // 100  13 200
}
b = fn(10);
console.log(a, b, c); // 12  undefined 200

函数调用变量提升(形参,函数)

  • 函数声明和定义都是一起的,并且优先级比var声明的要高
js
var a = 1
function fn(a) {
  console.log(a);
  // var a = 1
  var a = 2; // 私有
  function a(){}
}
fn(a); // [Function: a]

函数参数为函数

js
var x =100
function func(x,y=function(){x=10}){
  x= 3; // 私有
  y() // 找上级作用域,修改x=10
  console.log(x) // 10
}
func()

自执行函数

  • 自执行函数是无法被修改的
js
var b = 10
;(function b(){
  b= 20
  console.log(b) // [Function: b]
})()
console.log(b) // 10

对象深度对比

js
function isObject ( obj ) {
  return typeof obj === 'object' && obj !== null
}
function isEqual ( obj1, obj2 ) {
  if ( !isObject( obj1 ) || !isObject( obj2 ) ) {
    return obj1 === obj2
  }
  if ( obj1 === obj2 ) {
    return true
  }
  const obj1Keys = Object.keys( obj1 )
  const obj2Keys = Object.keys( obj2 )
  if ( obj1Keys.length !== obj2Keys.length ) {
    return false
  }
  for ( let key in obj1 ) {
    const res = isEqual( obj1[ key ], obj2[ key ] )
    if ( !res ) {
      return false
    }
  }
  return true
}

数组的中的函数this

js
let a = [1]
a.push(function(){
  console.log(this)
})
a[1]() // [1, ƒ]
// => a[1] => a.1 => 1.call(a)

bind实现

  • bind是一个闭包函数,它会返回一个函数,最终通过call执行函数并且改变this指向
js
Function.prototype.myBind = function () {
  const [ content, ...params ] = arguments;
  const target = this;
  return ( ...arg ) => {
    return target.call( content, ...params, ...arg );
  };
};

function f3 () {
  console.log( "f3", this, arguments );
}

var o3 = {
  name: "10",
};

f3.myBind( o3, 10 )( 1, 2 )

call 简单实现

js
Function.prototype.call = function () {
  let [self, ...args] = arguments;

  self = self ? Object(self) : window; // 防止空数据
  self.fn = this; // 当前需要执行的函数,利用函数特性改变this
  self.fn(...args); // 执行函数
};
function a(a, b) {
  console.log(a, b);
  console.log(this.a);
}
let obj = {
  a: 20,
};
a.call(null, 100, 200);

函数 call 多次

  • 解析,多次cell
    • 1、a.call.call.call.call(b) 因为call在原型上多次call都是等价,这里其实可以简写成:call.call(b)
    • 2、call内部实现:会把第一个参数作为this,因为需要改变this的指向,并且还需要指向当前的函数
    • 3、此时可以简化为b.fn = call=> b.call() // b
js
function a() {
  console.log("a");
}
function b() {
  console.log("b");
}

a.call(b); // a
a.call.call(b); // b
a.call.call.call.call(b); // b



console.log(a.call === Function.prototype.call); // true
console.log(a.call === a.call.call); // true
console.log(a.call === a.call.call.call); // true

原生ajax请求

js
var xhr;
//创建一个异步对象
xhr = new XMLHttpRequest();
//发送请求的方式 2. 样请求的页面 3.是否异步
xhr.open( "post", "test.json", true );
//Post 方式发送数据
xhr.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
//设置浏览器不使用缓存
xhr.setRequestHeader( "If-Modified-Since", "0" );

xhr.onreadystatechange = function () {
  if ( xhr.readystate == 4 ) {
    //readyState 属性指出了 XMLHttpRequest 对象在发送/接收数据过程中所处的几个状态。 XMLHttpRequest 对象会经历 5 种不同的状态。
    //0:未初始化。对象已经创建,但还未初始化,即还没调用 open 方法;
    //1:已打开。对象已经创建并初始化,但还未调用 send 方法;
    //2:已发送。已经调用 send 方法,但该对象正在等待状态码和头的返回;
    //3:正在接收。已经接收了部分数据,但还不能使用该对象的属性和方法,因为状态和响应头不完整;
    //4:已加载。所有数据接收完毕
    if ( xhr.status == 200 ) {
      alert( xhr.responseText ); //服务器返回的 Response 数据 //解析服务器返回的 jason 格式的数据
      var s = xhr.responseText;
      var json = eval( "(" + s + ")" );
      alert( json.data );
    }
  }
};
xhr.send( null ); //异步对象发送请求
//xhr.send("txtName=roger&txtPwd=123"); 以post方式发送数据 ajax 中 get 和 post 方式请求数据都是明文的。

节流throttle

  • 节流(throttle):每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景: 滚动条事件 或者 resize 事件
  • 反抖 (debounce): 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。
js
function throttle ( callback, delay ) {
  let timer = null;
  let starTime = Date.now()
  return function () {
    let curTime = Date.now()
    clearInterval( timer );
    // 规定的时间触发,不然用户一直操作就一直不会触发
    if ( curTime - starTime >= delay ) {
      starTime = curTime;
      callback();
    } else {
      timer = setTimeout( callback, delay );
    }
  };
}

发布订阅模式

  • 发布订阅模式:通过一个队列还耦合,订阅者、发布者,2 者本身没有关系
  • 发布和订阅之间没有依赖关系、只是收集 统一触发
js
let pubSub = {
  subCallbacks: [],
  on(subCallback) {
    // 订阅
    console.log("订阅了");
    this.subCallbacks.push(subCallback);
  },
  emit(data) {
    //发布
    this.subCallbacks.forEach((subCallback) => subCallback(data));
  },
};
pubSub.on((data) => {
  console.log("接收发布的信息:" + data);
});
pubSub.on((data) => {
  console.log("接收发布的信息:" + data);
});
pubSub.emit("群发");

观察者模式

  • 观察者模式:一个被观察者,一个观察者,把(观察者)的实例,存在被观察者队列中,被观察者状态发生变化,会通知每一个观察者
  • 观察者与被观察者有依赖关系,被观察者会收集观察者,被观察者状态发生变化,会通知每一个观察者
js
// 被观察者
class Subscribe {
  constructor(name) {
    this.name = name;
    this.observables = [];
    this.state = "";
  }

  push(observable) {
    this.observables.push(observable);
  }

  setState(state) {
    console.log(`${this.name}:通知`);
    this.state = state;
    this.observables.forEach((observable) => observable.update(state));
  }
}

// 观察者
class Observable {
  constructor(name) {
    this.name = name;
  }
  update(state) {
    console.log(`${this.name}收到了:${state}`);
  }
}
// 实例被观察者
let subscribe = new Subscribe("联通");
// 实例观察者
let observable1 = new Observable("小红");
let observable2 = new Observable("小白");
// 把观察者实例绑定在观察者上
subscribe.push(observable1);
subscribe.push(observable2);
// 更新通知观察者
subscribe.setState("发1G流量");

对象克隆

  • 直接把一个对象赋值给一个变量,它们指向同一个内存地址,当对象的值发生改变时,另外一个对象的值也会改变(浅拷贝)
  • 在赋值时,可以把对象先转成字符串,在转成对象在赋值,当对象的值发生改变,不会影响另外一个(深拷贝), 缺点如果属性值有函数、undefined 会被过滤掉
js
function cloneDeep(data, weakMap = new WeakMap()) {
  if (typeof data != null && typeof data === "object") {
    let cloneData = new data.constructor();
    let circularData = weakMap.get(data);
    if (circularData) {
      return circularData;
    }
    weakMap.set(data, data);
    for (const key in data) {
      if (Object.hasOwnProperty.call(data, key)) {
        cloneData[key] = cloneDeep(data[key], weakMap);
      }
    }
    return cloneData;
  } else {
    return data;
  }
}

let a = { a: 10, b: { a: 20, c: { c: 20 } } };
a.h = a;
console.log(cloneDeep(a));

Web 复制文本

js
// 需要人为的触发,需要https
function copyToClipboard(textToCopy) {
  if (navigator.clipboard) {
    return navigator.clipboard.writeText(textToCopy);
  } else {
    console.log("其他方式复制");
  }
}
btnCopy.onclick = function () {
  copyToClipboard("需要拷贝的内容")
    .then(() => console.log("拷贝成功"))
    .catch(() => console.log("拷贝失败"));
};

设备媒体网络状态

js
window.getSelection().toString();
console.log(navigator.onLine); // true 在线
window.addEventListener("online", function () {
  console.log("在线");
});
window.addEventListener("offline", function () {
  console.log("离线");
});

toString 怪异现象

  • 1、.toString()方法,返回对象的字符串表现
  • 2、Array、function 等类型作为 Object 实例,重写了 toString 函数
  • 3、想要得到对象具体的类型,需要调用 Object 原型的 toString 函数
  • 4、所以我们需要通过 Object.prototype.toString.call([]) 来的到具体的类型
js
let arr = [1, 2, 3];
// 被重写过的
console.log(arr.toString()); // 1,2,3
// 本身有toString属性
console.log(Array.prototype.hasOwnProperty("toString")); // true
// 删除重写的toString属性
delete Array.prototype.toString;
console.log(Array.prototype.hasOwnProperty("toString")); // false
// 调用未被重写过的 Object.prototype.toString
console.log(arr.toString()); // [object Array]

JSON.parse 和 JSON.stringify

js
// JSON.parse(二个参数)
const jsonStr = `
	{ 
  	"name": "帅哥", 
  	"age":  18, 
    "isFans": true,
    "IDCard": "xxxxxxxxxxxxxxxxxx"
   }
`;
// 第二次参数是一个函数,如果返回undefined属性会被过滤掉
var obj = JSON.parse(jsonStr, function (key, value) {
  if (key == "IDCard") {
    return undefined;
  } else {
    return value;
  }
});

console.log(obj);

// JSON.stringify(三个参数)

//replacer 方法
var person = {
  name: "帅哥",
  age: 45,
  birth: "1990-01-01",
};

var jsonString = JSON.stringify(person, function (key, value) {
  if (typeof value === "string") {
    return undefined;
  }
  return value;
});

// 只保留值是数字的
console.log(jsonString); // {"age":45}

var person = {
  name: "帅哥",
  age: 45,
  birth: "1990-01-01",
};

//replacer 只保留name、age
console.log(JSON.stringify(person, ["name", "age"])); //  {"name":"帅哥","age":45}

//space 美化格式
var person = {
  name: "帅哥",
  age: 45,
  birth: "1990-01-01",
};
const a = JSON.stringify(person);
console.log(a);

var person = {
  name: "帅哥",
  age: 45,
  birth: "1990-01-01",
};
const c = JSON.stringify(person, null, 10); // 上线10个空格
console.log(c);

运算符的诡异现象

  • let、const 不会在 window 上
js
let name = "let的name";
const person = {
  name: "person的Name",
  getName() {
    return this.name;
  },
};

const getName = person.getName;

console.log("getName", getName()); // undefined window.getName()
console.log("person.getName", person.getName()); // person的Name
console.log("(person.getName)", (person.getName)()); // person.getName()
/**
 * (0, person.getName)() 会转成
 *
 * let getName = person.getName;
 * getName() => window.getName()
 */
console.log("(0, person.getName)", (0, person.getName)());

实例属性

js
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  // 箭头函数是实例函数
  getName = () => {
    return this.name;
  };

  // 原型函数
  getAge() {
    return this.age;
  }
}
js
const proto = {
  name: "原型",
  arr: [1, 2],
};
const person = Object.create(proto);
// 自身加一个属性
person.name = "实例";
// 原型上的
person.arr.push(3);

console.log(person.name);
console.log(proto.name);

console.log(person.arr);
console.log(proto.arr);

encodeURI

imgimg

beforeunload

  • 表单的要焦点之后才会生效
js
window.addEventListener("beforeunload", (event) => {
  // Cancel the event as stated by the standard.
  event.preventDefault();
  // Chrome requires returnValue to be set.
  event.returnValue = "";
});

手写 LazyMan ,实现 sleepeat

  • 1、支持链式调用
  • 2、支持等待
js
class LazyMan {
  constructor(name) {
    this.name = name
    this.qeues = []
    setTimeout(() => {
      this.next()
    });
  }

  next() {
    const task = this.qeues.shift();
    if (task) {
      task();
    }
  }

  eat(product) {
    this.qeues.push(() => {
      console.log(`${this.name}在吃${product}`)
      this.next()
    })
    return this;
  }

  sleep(time) {
    this.qeues.push(() => {
      console.log(`${this.name}在睡觉`)
      setTimeout(() => {
        this.next()
      }, time * 1000);
    })
    return this;
  }

}
const me = new LazyMan('hl')
me.eat('苹果').eat('香蕉').sleep(5).eat('葡萄').eat('栗子').sleep(5).eat('菠萝')

旋转数组

  • 定义一个函数,实现数组的旋转。如输入 [1, 2, 3, 4, 5, 6, 7]key = 3, 输出 [5, 6, 7, 1, 2, 3, 4]
js
let arr = [1,2,3,4,5,6,7]
function rotate(arr,key){
  let arr1 = arr.slice(0,arr.length-key)
  let arr2 = arr.slice(-key)
  return arr2.concat(arr1)
}

console.log(rotate(arr,3))

1-10000 之间的对称数(回文)

  • 如:1,11,121,232...
js
function palindrome(n) {
  let arr = []
  for (let i = 1; i <= n; i++) {
    let str = i.toString();
    let startIndex = 0;
    let endIndex = str.length - 1
    while (startIndex <= endIndex) {
      if (str[startIndex] != str[endIndex]) {
        break
      }
      arr.push(i)
      startIndex++;
      endIndex--;
    }
  }
  return arr

}

console.log(palindrome(11)) // [1, 2, 3, 4,  5,6, 7, 8, 9, 11]

连续最多的字符

  • 给一个字符串,找出连续最多的字符,以及次数。
  • 例如字符串 'aabbcccddeeee11223' 连续最多的是 e ,4 次。
js
var maxPower = function (s) {
  if (!s) return 0;
  let obj = {
    str: '',
    n: 0
  }
  let i = 0;
  let j = 0;
  let tempIndex = 0;
  for (; i <= s.length - 1; i++) {
    if (s[i] === s[j]) {
      tempIndex++;
    }
    if (s[i] !== s[j]) {
      if (tempIndex > obj.n) {
        obj.str = s[j];
        obj.n = tempIndex
      }
      tempIndex = 0;
      if (i < s.length - 1) {
        j = i;
        i--;
      }
    }


  }

  return obj.n
};

console.log(maxPower('j'))

控制台请求并发数

js
(async () => {
  function delay(ms, simulateError = false) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (simulateError) {
          reject();
        } else {
          console.log("执行任务", ms / 1000);
          resolve();
        }
      }, ms);
    });
  }

  let tasks = [
    delay(1000 * 10),
    delay(1000 * 20, true),
    delay(1000 * 11),
    delay(1000 * 30),
    delay(1000 * 40),
    delay(1000 * 41),
    delay(1000 * 21),
    delay(1000 * 42),
    delay(1000 * 22),
  ];

  async function httpPool(tasks = [], poolMax = 6) {
    let i = 0;
    let tasksLength = tasks.length;
    let taskPool = [];
    let failTaskPool = [];
    while (i < tasksLength) {
      let task = tasks[i];
      taskPool.push(task);
      task.catch(() => {
        failTaskPool.push(task);
        console.log('任务发生错误');
      }).finally(() => { taskPool.splice(taskPool.findIndex((_) => _ === task), 1) });

      if (taskPool.length >= poolMax) {
        try {
          await Promise.race(taskPool);
        } catch (error) {

        }

      }
      i++;
    }
    await Promise.all(taskPool);
    console.log('所有任务执行完毕');
    console.log('成功任务', taskPool);
    // TODO:重试机制
    console.log('失败任务', failTaskPool);
  }

  await httpPool(tasks);
  console.log("合并")
})()