Функции высшего порядка реализуют АОП (аспектно-ориентированное программирование).
Что такое аспектно-ориентированное программирование?
Function.prototype.before = function (beforefn) {
let _self = this; // 缓存原函数的引用
return function () { // 代理函数
beforefn.apply(this, arguments); // 执行前置函数
return _self.apply(this, arguments); // 执行原函数
}
}
Function.prototype.after = function (afterfn) {
let _self = this;
return function () {
let set = _self.apply(this, arguments);
afterfn.apply(this, arguments);
return set;
}
}
let func = () => console.log('func');
func = func.before(() => {
console.log('===before===');
}).after(() => {
console.log('===after===');
});
func();
Выходной результат:
===before===
func
===after===
Объединить объекты
const merge = (obj, target = {}) => {
Object.keys(obj).forEach(key => {
if (isObject(obj[key])) {
if (isObject(target[key])) { // 都是对象
Object.keys(obj[key]).forEach(prop => {
target[key][prop] = obj[key][prop]
})
} else { // target不是对象 直接重写
if (target[key]) {
target[key] = {
[key]: target[key],
...obj[key]
}
} else {
target[key] = obj[key]
}
}
} else {
if (isObject(target[key])) {
target[key] = {
...target[key],
[key]: obj[key]
}
} else {
target[key] = obj[key]
}
}
})
return target
}
const obj1 = {
"pid": 1,
"signup": "注册",
"menu": "菜单",
"headers": {
"common": "common"
}
}
const obj2 = {
"pid": 2,
"signup": {
"sin": 2
},
"menu": {
"id": 1
},
"headers": {
"test": 123
}
}
const result = merge(obj1, obj2)
// {
// pid: 2,
// signup: { signup: '注册', sin: 2 },
// menu: { menu: '菜单', id: 1 },
// headers: { common: 'common', test: 123 }
// }
console.log(result)
факториал
const factorial1 = n => {
if (n <= 1) return 1
return n * factorial1(n - 1)
}
// 尾递归优化
const factorial2 = (n, total = 1) => {
if (n <= 1) return total
return factorial2(n - 1, total * n)
}
console.log(factorial1(3)) // 6
console.log(factorial2(3)) // 6
console.log(factorial1(5)) // 120
console.log(factorial2(5)) // 120
бинарный поиск
//循环不变式 guess 等于l r中间位置
const bsearch = (A, x) => {
let l = 0
let r = A.length - 1
let guess
while (l <= r) {
console.log('find')
guess = Math.floor((l + r) / 2)
if (A[guess] === x) return guess
if (A[guess] > x) r = guess - 1
else l = guess + 1
}
return -1
}
let arr = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(bsearch(arr, 6)) // 5
Преобразование структуры двоичного дерева в связанный список
// 将一个树型结构,变成链表
class LinkNode {
constructor(val) {
this.val = val
this.next = null
}
}
// const flatten = function(root) {
// const head = new LinkNode(null)
// let linkNode = head
// const midOrder = (node) => {
// if (node == null) return
// linkNode.next = new LinkNode(node.val)
// linkNode = linkNode.next
// midOrder(node.left)
// midOrder(node.right)
// }
// midOrder(root)
// return head.next
// }
// 直接修改root
const flatten = function(root) {
let head = new LinkNode(null)
const linkHead = head
const midOrder = (node) => {
if (node == null) return
head.next = node
head = node
midOrder(node.left)
midOrder(node.right)
delete node.left
delete node.right
}
midOrder(root)
return linkHead.next
}
function TreeNode(val) {
this.val = val
this.left = this.right = null
}
const root = new TreeNode(1)
root.left = new TreeNode(2)
root.right = new TreeNode(5)
root.left.left = new TreeNode(3)
root.left.right = new TreeNode(4)
root.right.right = new TreeNode(6)
console.log(JSON.stringify(flatten(root), null, 2))
// {
// "val": 1,
// "next": {
// "val": 2,
// "next": {
// "val": 3,
// "next": {
// "val": 4,
// "next": {
// "val": 5,
// "next": {
// "val": 6
// }
// }
// }
// }
// }
// }
Последовательность Фибоначчи
Последовательность Фибоначчи начинается с третьего члена, и каждый член равен сумме двух предыдущих. Относится к такой последовательности: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144…
Получить значение, на которое указывает n-й элемент в последовательности
1. Рекурсия
function fib(n) {
if (n === 1 || n === 2) return n - 1;
return fib(n - 1) + fib(n - 2)
}
console.log(fib(10)); // 34
Временная сложность O (2 ^ n)
2. Нерекурсивный
function fib(n) {
let a = 0;
let b = 1;
let c = a + b;
for (let i = 3; i < n; i++) {
a = b;
b = c;
c = a + b;
}
return c;
}
console.log(fib(10)); // 34
Временная сложность O (n)
Реализовать структуру стека
const Stack = (() => {
const wm = new WeakMap()
class Stack {
constructor() {
wm.set(this, [])
this.top = 0
}
push(...nums) {
let list = wm.get(this)
nums.forEach(item => {
list[this.top++] = item
})
}
pop() {
let list = wm.get(this)
let last = list[--this.top]
list.length = this.top
return last
}
peek() {
let list = wm.get(this)
return list[this.top - 1]
}
clear() {
let list = wm.get(this)
list.length = 0
}
size() {
return this.top
}
output() {
return wm.get(this)
}
isEmpty() {
return wm.get(this).length === 0
}
}
return Stack
})()
let s = new Stack()
s.push(1, 2, 3, 4, 5)
console.log(s.output()) // [ 1, 2, 3, 4, 5 ]
Преобразовать десятичную систему в другие базы
function binary(num, base = 2) {
const stack = []
const digits = '0123456789ABCDEF'
while (num > base - 1) {
stack.push(digits[num % base])
num = ~~(num / 2)
}
stack.push(digits[num])
return stack.reverse().join('')
}
console.log(binary(10)) // '1010'
Преобразование десятичного числа в другие основания (используя стек)
function divideBy2(decNumber, base = 2) {
let remStack = new Stack()
let rem
let binaryString = ''
let digits = '0123456789ABCDEF'
while (decNumber > 0) {
rem = Math.floor(decNumber % base)
remStack.push(rem)
decNumber = Math.floor(decNumber / base)
}
while (!remStack.isEmpty()) {
binaryString += digits[remStack.pop()].toString()
}
return binaryString
}
// 将十进制转换成其他进制
let num = 100345
num.toString(2) // "11000011111111001"
num.toString(8) // "303771"
console.log(divideBy2(num, 2)) // "11000011111111001"
console.log(divideBy2(num, 8)) // "303771"
Вопрос JS о массиве push
// 类数组
let obj = {
'1': 'a',
'2': 'b',
length: 2,
push: Array.prototype.push
};
// Array.prototype.push.call(obj, 'c');
obj.push('c')
console.log(obj); // { '1': 'a', '2': 'c', length: 3 }
реализация push и pop
Базовая реализация массива push зависит от свойства длины массива.
Array.prototype.push2 = function(...rest){
this.splice(this.length, 0, ...rest)
return this.length;
}
То же самое касается поп
Array.prototype.pop2 = function(){
return this.splice(this.length - 1, 1)[0];
}
проблема алгоритма
1. В массиве выясните, что сумма двух элементов в нем NUM, если она существует, верните позицию индекса двух чисел, в противном случае ложь
function fn(num = 0, ary = []) {
for (let i = 0; i < ary.length; i++) {
let diff = num - ary[i];
let diffIndex = ary.indexOf(diff);
if (diffIndex !== -1 && diffIndex !== i) {
return [i, diffIndex];
}
}
return false;
}
let num = 3;
let arr = [-1, 4, 6, 2];
console.log(fn(num, arr)); // [0, 1]
2. Поставьте два упорядоченных числа и большие числа в ряд
function mergeAry(left = [], right = []) {
const result = [];
while (left.length && right.length) {
result.push(left[0] <= right[0] ? left.shift() : right.shift());
}
return result.concat(left, right);
}
console.log(mergeAry([1, 2, 3], [1, 4, 8, 9])); // [ 1, 1, 2, 3, 4, 8, 9 ]
3. Найдите три разных элемента в массиве, где сумма двух элементов равна третьему элементу arr[x] + arr[y] = arr[z] Возвращает true, если он существует в массиве, иначе возвращает false
Такие как:
[1, 18, 3, 2] => 1 + 2 = 3 => true;
[3, 11, 2, 7] => false
let a1 = [2, 99, 3, 5]
let a2 = [1, 2, 10, 5]
function find(arr) {
arr.sort((a, b) => a - b)
for (let i = 0; i < arr.length - 1; i++) {
let cur = arr[i]
for (let k = i + 1; k < arr.length; k++) {
let next = arr[k]
let diff = next - cur
if (![cur, next].includes(diff) && arr.includes(diff)) {
return true
}
}
}
return false
}
console.log(find(a1)) // true
console.log(find(a2)) // false
Удалите специальные символы и вопросительные знаки, оставьте только буквы и одинарные кавычки для специальных символов, за которыми следуют вопросительные знаки, если буквы преобразованы в верхний регистр «Я?�…за рулем�??�в�?Пекин�?� после завтрака»
=> 'I'm driving to Beijing after breakfast'
let str = "I'm?���driving�??�to�?beijing�?��after�breakfast"
const reg1 = /�+\?([a-z])/ig
const reg2 = /[^a-z']+/ig
str = str.replace(reg1, (a, g1) => {
return ' ' + g1.toUpperCase()
}).replace(reg2, ' ')
console.log(str) // 'I'm driving to Beijing after breakfast'
Компиляция шаблона
const template = `
<div class="play" name="{{name}}">{{ value }}</div>
`
const data = {
name: 'Brolly',
value: 'FE'
}
const compiler = (str, data) => {
const reg = /\{\{(.*?)\}\}/g
return str.replace(reg, (patten, g1) => {
const key = g1.trim()
return data[key] ? data[key] : ''
})
}
const content = compiler(template, data)
// <div class="play" name="Brolly">FE</div>
console.log(content)
Реализация повтора строки
// 原生repeat
'ni'.repeat(3); // 'ninini'
// 实现一
String.prototype.repeatString1 = function (n) {
return Array(n + 1).join(this);
}
console.log('ni'.repeatString1(3));
// 实现二
String.prototype.repeatString2 = function (n) {
return Array(n).fill(this).join('');
}
console.log('ni'.repeatString2(3));
Таймер реализует планирование задач.Единица дня цикла 0-23 часа, и определяется один раз в час.
class Cron {
constructor() {
this.map = new Map()
this.timer = null
this.interval = 60 * 60 * 1000
this._initCron()
this._runCron()
}
addSub (time, fn) {
if (this.map.has(time)) {
this.map.get(time).push(fn)
}
}
_run (time) {
if (this.map.has(time)) {
this.map.get(time).forEach(fn => fn())
}
}
_initCron() {
for (let i = 0; i <= 23; i++) {
this.map.set(i, [])
}
}
resetCron () {
for (let i = 0; i <= 23; i++) {
this.map.set(0, [])
}
}
_runCron () {
this.timer = setInterval(() => {
const hour = (new Date()).getHours()
this._run(hour)
}, this.interval)
}
stopCron () {
clearInterval(this.timer)
}
runCron () {
this._runCron()
}
}
const cron = new Cron()
cron.addSub(22, () => {
console.log('我要吃饭')
})
cron.addSub(22, () => {
console.log('我要工作')
})
Массив, который каждый раз добавляет три, например [3, 6, 9, ...]
const addThree = (start, target, arr = []) => {
if (start === target) {
arr.push(start)
return arr
}
if (start > target) {
return arr
}
arr.push(start)
return addThree(start += 3, target, arr)
}
console.log(addThree(3, 40))
что происходит, когда мы новый класс
/**
* new2 new关键字的代码实现演示
* @param {function} func 被new的类 (构造函数)
*/
function new2(func) {
// 创建了一个实例对象 o,并且这个对象__proto__指向func这个类的原型对象
let o = Object.create(func.prototype);
// (在构造函数中this指向当前实例)让这个类作为普通函数值行 并且里面this为实例对象
let k = func.call(o);
// 最后再将实例对象返回 如果你在类中显示指定返回值k,
// 注意如果返回的是引用类型则将默认返回的实例对象o替代掉
return typeof k === 'object' ? k : o;
}
// 实验
function M() { // 即将被new的类
this.name = 'liwenli';
}
let m = new2(M); // 等价于 new M 这里只是模拟
console.log(m instanceof M); // instanceof 检测实例
console.log(m instanceof Object);
console.log(m.__proto__.constructor === M);
this/bind
let obj = { a: 1};
function fn() {
this.b = 100;
return this.a;
}
let fe = fn.bind(obj);
console.log(fe()); // 1 里面this是obj
console.log(obj); // { a: 1, b: 100 }
console.log(new fe()); // 里面this是当前创建实例对象 { b: 100 }
Object.create совместимая реализация
let obj1 = {id: 1};
Object._create = (o) => {
let Fn = function() {}; // 临时的构造函数
Fn.prototype = o;
return new Fn;
}
let obj2 = Object._create(obj1);
console.log(obj2.__proto__ === obj1); // true
console.log(obj2.id); // 1
// 原生的Object.create
let obj3 = Object.create(obj1);
console.log(obj3.__proto__ === obj1); // true
console.log(obj3.id); // 1
вопрос интервью
Решение первое
function CodingMan(name) { // 主要考察的是 面向对象以及JS运行机制(同步 异步 任务队列 事件循环)
function Man(name) {
setTimeout(() => { // 异步
console.log(`Hi! This is ${name}`);
}, 0);
}
Man.prototype.sleep = function(time) {
let curTime = new Date();
let delay = time * 1000;
setTimeout(() => { // 异步
while (new Date() - curTime < delay) {} // 阻塞当前主线程
console.log(`Wake up after ${time}`);
}, 0);
return this;
}
Man.prototype.sleepFirst = function(time) {
let curTime = new Date();
let delay = time * 1000;
while (new Date() - curTime < delay) {} // 阻塞当前主线程
console.log(`Wake up after ${time}`);
return this;
}
Man.prototype.eat = function(food) {
setTimeout(() => { // 异步
console.log(`Eat ${food}~~`);
}, 0)
return this;
}
return new Man(name);
}
// CodingMan('Peter');
// CodingMan('Peter').sleep(3).eat('dinner');
// CodingMan('Peter').eat('dinner').eat('supper');
// CodingMan('Peter').sleepFirst(5).eat('supper');
Решение второе
function CodingMan(name) {
function fe() {
fe.flag = true;
console.log(`Hi! This is ${name}`);
}
fe.flag = false;
fe.timer = setTimeout(() => {
clearTimeout(fe.timer);
if (!fe.flag) fe();
}, 0);
return fe;
}
Function.prototype.sleep = function (delay) {
this()
this.await(delay);
return this;
}
Function.prototype.sleepFirst = function (delay) {
this.await(delay);
this();
return this;
}
Function.prototype.eat = function (dinner) {
setTimeout(() => {
console.log(`Eat ${dinner}~`);
});
return this;
};
Function.prototype.await = function (delay) {
delay = isNaN(delay) ? 0 : delay;
let startTime = new Date();
let delayTime = delay * 1000;
while (new Date() - startTime <= delayTime) {
}
console.log(`Wake up after ${delayTime}ms`);
}
// CodingMan('peter')
// CodingMan('peter').sleep(2).eat('hanbao');
// CodingMan('peter').sleepFirst(2).eat('hanbao');
CodingMan('peter').eat('haha').eat('hanbao');
функция каррирования
Физическая и химическая связка
function add(a, b, c) {
return a + b + c;
}
let f1 = add.bind(undefined, 100);
console.log(f1(2, 3)); // 105 = 100 + 2 + 3
let f2 = f1.bind(undefined, 200);
console.log(f2(3)); // 303 = 100 + 200 + 3
Карри реализация карри (рекурсивный вызов + valueOf)
Точка знаний: когда valueOf объекта неявно преобразуется в базовый тип данных (унарный оператор +объект/конкатенация строк ''+object) в среде браузера, он вызывает свой собственный метод valueOf для получения значения. Если он также имеет метод toString, сначала вызовите valueOf Если возвращаемое значение valueOf не является базовым типом данных, вызовите toString и сообщите об ошибке, если возвращаемое значение toString не является базовым типом данных.
значение вызова сцены
let obj = { x: 1, y: 2 };
obj.toString = function() {
return this.x + this.y;
}
obj.valueOf = function() {
return this.x + this.y + 100;
}
// 以下情况下自身valueOf被调用
console.log('' + obj); // 103
console.log(+obj); // 103
function fn() {};
fn.valueOf = () => console.log('valueof');
console.log(fn); // valueof
const mul = x => {
const result = y => mul(x * y); // 递归调用mul
result.valueOf = () => x;
return result;
}
console.log(mul(2)(3)); // 6
// 在上面mul每执行一次,就会返回一个valueOf被改写后的新函数result 并且result执行会在里面调用mul(x * y)
// 在result函数的valueOf里保存着 由上一次x * y 传进来的结果x, 也就是上一次x*y 会作为这一次的输出 依然叫x
// 第一次mul(2) 此时 x为2 return result
result 为 result = y => mul(2 * y);
// 第二次 mul(2)(3) 等价于 第一个mul返回的result(3), result执行 => mul(2 * 3) 再次调用mul 将2*3 = 6 的结果作为mul参数
// 最后mul(6) x = 6 在返回一个新函数result 此时result的valueOf = () => 6
// log(mul(2)(3)) 相当于log的最后返回的result 隐式调用valueOf 返回 6
curry преобразует функцию с несколькими аргументами в функцию, которая принимает один аргумент
function fe(a, b, c) {
return a + b + c;
}
function curry(fe) {
let args = []; // 参数集合
let len = args.length;
return function bar() {
args = [...args, ...arguments]; // 收集参数
if (args.length >= fe.length) {
return fe.apply(this, args);
}
return bar;
}
}
console.log(curry(fe)(1)(2)(3)); // 6
каррирование частичной оценки
// currying 函数柯理化
let currying = function(fn) {
let args = [];
return function fe() {
if (arguments.length === 0) {
return fn.apply(this, args);
}
[].push.apply(args, arguments);
return fe;
}
}
let count = currying(function (...rest) {
return rest.reduce((prev, cur) => prev + cur, 0);
});
console.log(count(100)(200)(10)()); // 310
Сбор параметров Задержка выполнения до указанного количества раз для выполнения
// 参数收集 指定次数后执行
function fn(...rest) {console.log(rest);};
function after(fn, time = 1) {
let params = [];
return function(...rest) {
params = [...params, ...rest];
if (--time === 0) {
fn.apply(this, params);
}
}
}
let newFn = after(fn, 3); // 执行3次 内部fn才会执行
newFn(2);
newFn(3);
newFn(4);
регулирование функции
Лифт для стратегии газа. Гарантируется, что если первый человек в лифте войдет, он будет доставлен вовремя через 50 миллисекунд без ожидания. В режиме ожидания, если никого нет.
let throttle = (fn, delay = 50) => { // 节流 控制执行间隔时间 防止频繁触发 scroll resize mousemove
let stattime = 0;
return function (...args) {
let curTime = new Date();
if (curTime - stattime >= delay) {
fn.apply(this, args);
stattime = curTime;
}
}
}
Обычная проверка должна содержать цифры, прописные и строчные буквы
// 同时包含 数字 字母大小写
// let reg = /^(?!([a-zA-Z]+|\d+)$)[a-zA-Z\d]{8,15}$/
// ^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]
let reg = /^(?!([a-zA-Z]+|[a-z\d]+|[A-Z\d]+)$)[a-zA-Z\d]{8,15}$/
console.log(reg.test('lolABC123')) // true
console.log(reg.test('lol12313123')) // false
console.log(reg.test('ADF12313123')) // false
console.log(reg.test('12312313123')) // false
console.log(reg.test('LLLLLLLLLL')) // false
console.log(reg.test('aaaaaaass')) // fals
Функция защиты от тряски полная версия
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
var timeout;
return function () {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
Стабилизатор
Лифт стратегии устранения дребезга. Если кто-то входит в лифт, подождите 50 мс. Если войдет другой человек, подождите 50 миллисекунд, чтобы перенастроить время до истечения 50-миллисекундного тайм-аута, и начните доставку.
let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间 用户输入频繁
let timer;
return function (...args) {
let that = this;
clearTimeout(timer);
timer = setTimeout(fn.bind(that, ...args), time);
}
}
Написание, совместимое с глубоким копированием (за исключением свойств прототипа)
function deepCopy(obj) {
if (typeof obj !== 'object') return obj;
if (typeof window !== 'undefined' && window.JSON) { // 浏览器环境下 并支持window.JSON 则使用 JSON
return JSON.parse(JSON.stringify(obj));
} else {
let newObj = obj.constructor === Array ? [] : {};
for(let key in obj) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
return newObj;
}
}
let obj = {a: 1, b: [12]};
let newObj = deepCopy(obj);
newObj.b[1] = 100;
console.log(obj);
console.log(newObj);
Глубокий клон плюс
function cloneDeep(obj) {
let type = isType(obj)
if (type === 'Array' || type === 'Object') {
return cloneObj(obj)
} else if (type === 'Date') {
return obj.constructor(obj)
} else {
return obj
}
}
function cloneObj(obj) {
let newObj = obj instanceof Array ? [] : {};
for (let key in obj) {
newObj[key] = typeof obj[key] === 'object' ? cloneObj(obj[key]) : obj[key]
}
return newObj;
}
function isType(o) {
return /\[object\s(.*?)\]/.exec(Object.prototype.toString.call(o))[1]
}
let fn = function () {
return 123
}
var a = [[1, 2, 3], [4, 5, 6, 7, fn]];
// let c = new Date();
// var b = cloneDeep(c);
var b = cloneDeep(a);
console.log(b[0], a[0]);
console.log(b[0] === a[0]);
Простая инкапсуляция определения собственного типа данных
Object.prototype.isType = function (type) {
return function (params) {
return Object.prototype.toString.call(params) === `[object ${type}]`
}
}
let isString = Object.isType('String')
let isArray = Object.isType('Array')
console.log(isString(1)) // false
console.log(isString('hello')) // true
console.log(isArray(2)) // false
console.log(isArray(['hello'])) // true
Реализация сокращения массива
Array.prototype._reduce = function (callback, initVal) {
let i = 0
let result = initVal
if (typeof initVal === 'undefined') {
result = this[0]
i++
}
for (i; i < this.length; i++) {
result = callback(result, this[i])
}
return result
}
const arr = [1, 2, 3]
let result = arr._reduce((a, b) => {
return a + b
}, 0)
console.log(result) // 6
Реализация привязки функции
1.es5
Function.prototype._bind = function(context) {
let func = this;
let params = [].slice.call(arguments, 1);
let Fnop = function() {};
let fbound = function() {
params = params.concat([].slice.call(arguments, 0));
return func.apply(this instanceof Fnop ?
this : context, params);
}
Fnop.prototype = this.prototype;
fbound.prototype = new Fnop();
return fbound;
}
function foo() {
this.b = 100;
return this.a;
}
let fe = foo._bind({ a: 1 });
console.log(fe()); // 1
console.log(new fe()); // 实例 {b: 100}
2.es6
Function.prototype.mybind = function(context, ...rest) {
return (...params) => this.call(context, ...rest, ...params);
}
Составление серии композиций функций (уменьшение промежуточного программного обеспечения)
// 组合串联
let fn1 = (a) => a + 1;
let fn2 = (b) => b + 2;
let fn3 = (c) => c + 3;
let funs = [fn1, fn2, fn3];
let compose = (func) => {
return arg => func.reduceRight((composed, fn) => fn(composed), arg);
}
console.log(compose(funs)(100)); // 相当于fn1(fn2(fn3(100)))
Реализация компоновки в исходном коде редукции (GitHub.com/Горячее цинкование/Горячее…)
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
реализация koa-compose
function compose(middleware) {
return function(ctx, next) {
let index = -1;
return dispatch(0)
function dispatch(i) {
if(i <= index) return Promise.reject(new Error('next() called multiple times'));
index = i;
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))
} catch(e) {
return Promise.reject(e)
}
}
}
}
let mid1 = (ctx, next) => {
console.log('ctx1', ctx);
next()
}
let mid2 = (ctx, next) => {
console.log('ctx2', ctx);
next()
}
let mid3 = (ctx, next) => {
console.log('ctx3', ctx);
}
let co = compose([mid1, mid2, mid3])
co('ctx')
со-функция
function *fn(a = 0) {
console.log('a', a)
const b = yield 2
console.log('b', b)
const c = yield Promise.resolve(3)
console.log('c', c)
return a + b + c
}
// const it = fn(1)
// it.next()
// it.next(2)
// it.next(3)
// co(fn, 1)
function fe() {
return 100
}
run(fn, 10).then(res => {
console.log(res)
})
function run(gen) {
const slice = [].slice
const args = slice.call(arguments, 1)
return new Promise((resolve, reject) => {
const ite = (typeof gen === 'function') && gen.apply(this, args)
if (!ite || typeof ite.next !== 'function') return resolve(ite)
function next(res) {
const { value, done } = ite.next(res)
if (done) {
resolve(value)
} else if (value instanceof Promise) {
value.then(next)
} else {
next(value)
}
}
next()
})
}
Обещание короткой версии es6
class Promise {
constructor(fn) {
this.status = 'Pending'
setTimeout(() => {
fn((data) => {
this.resolve(data)
}, (error) => {
this.reject(error)
})
})
}
resolve(data) {
if (this.status === 'Pending') {
this.success(data)
this.status = 'Fulfilled'
}
}
reject(error) {
if (this.status === 'Pending') {
this.error(error)
this.status = 'Rejected'
}
}
then(success, error) {
this.success = success
this.error = error
}
}
let p1 = new Promise((resolve, reject) => {
// reject('hello error');
setTimeout(() => {
resolve('hello promise')
}, 1000)
})
p1.then((data) => console.log(data), (err) => console.log(err))
Как активно прервать цепочку вызовов Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { // 异步操作
resolve('start')
}, 1000);
});
p1.then((result) => {
console.log('a', result);
return Promise.reject('中断后续调用'); // 此时rejected的状态将直接跳到catch里,剩下的调用不会再继续
}).then(result => {
console.log('b', result);
}).then(result => {
console.log('c', result);
}).catch(err => {
console.log(err);
});
// a start
// 中断后续调用
реализация bluebird.promisify (преобразование API асинхронной функции обратного вызова в форму обещания)
// promisify.js
module.exports = {
promisify(fn){
return function () {
var args = Array.from(arguments);
return new Promise(function (resolve, reject) {
fn.apply(null, args.concat(function (err) {
if (err) {
reject(err);
} else {
resolve(arguments[1])
}
}));
})
}
}
}
// main.js
const fs = require('fs');
const {promisify} = require('./promisify.js');
const readFile = promisify('fs.readFile'); // 转换异步读取
// 异步文件 由回调函数形式变成promise形式
readFile('./1.txt', 'utf8').then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
Обработка совместимости с window.requestAnimationFrame
window._requestAnimationFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
Соответствует ли строка правилу палиндрома
let str = 'My age is 0, 0 si ega ym.';
方法一
function palindrome(params) {
params = params.replace(/[\W\s_]/ig, '');
return params.toLowerCase() === params.split('').reverse().join('').toLowerCase();
}
console.log(palindrome(str));
方法二
function palindrome(params) {
params = params.replace(/[\W\s_]/ig, '').toLowerCase();
for (var i = 0, j = params.length-1; i<j; i++, j--) {
if (params[i] !== params[j]) {
return false;
}
}
return true;
}
разрушать
// 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4}
const targetArray = [1, [2, 3], 4];
const formater = "[a, [b], c]";
const destructuringArray = (values, keys) => {
try {
const obj = {};
if (typeof keys === 'string') {
keys = JSON.parse(keys.replace(/\w+/g, '"$&"'));
}
const iterate = (values, keys) =>
keys.forEach((key, i) => {
if(Array.isArray(key)) iterate(values[i], key)
else obj[key] = values[i]
})
iterate(values, keys)
return obj;
} catch (e) {
console.error(e.message);
}
}
выравнивание массива
Свести [[1, 2], 3, [[[4], 5]]] до [1, 2, 3, 4, 5]
let arr = [[1, 2], 3, [[[4], 5]]]; // 数组展平
function flatten(arr) {
return [].concat(
...arr.map(x => Array.isArray(x) ? flatten(x) : x)
)
}
бинарный поиск
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
// 二分查找 递归 由中间开始往两边查找 前提是有序的数组 返回对应的索引位置
function binarySearch1(arr, dest, start = 0, end = data.length) {
if (start > end) {
return -1
}
let midIndex = Math.floor((start + end) / 2); // 中间位置索引
let mid = arr[midIndex]; // 中间值
if (mid == dest) {
return midIndex;
}
if (dest < mid) { // 要找的比中间值小 就从中间往开头找 一直到0
return binarySearch1(arr, dest, 0, midIndex - 1);
}
if (dest > mid) { // 要找的比中间值大 就从中间往后找 一直到end结束
return binarySearch1(arr, dest, midIndex + 1, end);
}
return -1; // 找不到返回-1
}
console.log(binarySearch1(arr, 7, 3, 6)); // 6
// 非递归 arr前提有序数组 (从小到大)返回对应的索引位置
function binarySearch2(arr, dest) {
let max = arr.length - 1;
let min = 0;
while (min <= max) {
let mid = Math.floor((max + min) / 2); // mid中间位置索引
if (dest < arr[mid]) { // 如果要找的这项比中间项还要小 说明应该在mid中间位置前面 修改最大边界值max=mid-1
max = mid - 1;
} else if (dest > arr[mid]) { // 如果要找的这项比中间项还要大 说明应该在mid中间位置的后面 修改最小边界值min=mid+1
min = mid + 1;
} else {
return mid;
}
}
return -1; // 找不到返回-1
}
console.log(binarySearch2(arr, 3)); // 2
вопросы бинарного поиска
В двумерном массиве каждая строка сортируется в порядке возрастания слева направо, а каждый столбец сортируется в порядке возрастания сверху вниз, завершают функцию, вводят двумерный массив и целое число и определяют, является ли массив содержит целое число
Идея та же самая, но от одномерного к двухмерному мы можем перейти к этой идее следующим образом:
- Выберите последний из первой строки для суждения (это самая большая в первой строке)
- Если цель больше этого значения, добавьте 1 к количеству строк и выполните итерацию по второй строке (поскольку каждый столбец увеличивается).
- Если цель меньше этого значения, то смотрите в этой строке
Повторите вышеуказанные шаги
function findTarget(arr,target) {
let i = 0; // i代表行
let j = arr[i].length -1; // j每行中每项索引位置 从最后项开始比较
while(i < arr.length && j>=0) {
if(target < arr[i][j]) {
j--;
} else if (target > arr[i][j]) {
i++;
} else {
return `找到了,位置在${i},${j}`
}
}
return `(${i},${j})`
}
let arr = [
[1,2,3,4],
[5,9,10,11],
[13,20,21,23]
] //测试
Найти повторяющиеся элементы в массиве
// 例如:[1,2,4,4,3,3,1,5,3]
// 输出:[1,3,4]
let arr = [1, 2, 4, 4, 3, 3, 1, 5, 3];
// 方法一
function repeat1(arr){
var result = [], map = {};
arr.map(function(num){
if(map[num] === 1) result.push(num); // 等于1说明之前出现过一次 这次重复出现了
map[num] = (map[num] || 0) + 1; // 微妙之处 开始第一次出现无值 记为 0 + 1 = 1 下一次从1开始累加
});
return result;
}
console.log(repeat1(arr));
// 方法二
function repeat(arr) {
let result = arr.filter((x, i, self) => {
return self.indexOf(x) === i && self.lastIndexOf(x) !== i
}); //
return result;
}
console.log(repeat(arr));
Сортировка по количеству повторений чисел в массиве
// 如果次数相同 则按照值排序 比如 2, 2, 2和 1, 1, 1 应排序为 [1, 1, 1, 2, 2, 2]
// 比如 [1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2] => [3, 4, 4, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2]
const repeatTimeSort = arr => {
arr.sort((a, b) => a - b)
let ary = []
while (arr.length > 0) {
let a = arr[0]
let start = arr.indexOf(a)
let end = arr.lastIndexOf(a) + 1
ary.push(arr.splice(start, end - start))
}
ary.sort((a, b) => a.length - b.length)
return ary.reduce((prev, cur) => prev.concat(cur), [])
}
// [ 12, 13, 13, 11, 11, 11 ]
console.log(repeatTimeSort([11, 12, 13, 11, 11, 13]))
// [ 3, 4, 4, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2 ]
console.log(repeatTimeSort([1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2]))
Не зацикливается, создавая массив длиной 100, а значение каждого элемента равно его индексу.
// 方法一 递归写法
function createArray(len, arr = []) {
if (len > 0) {
arr[--len] = len;
createArray(len, arr);
}
return arr;
}
console.log(createArray(100));
// 方法二
// 下面评论中@MaDivH 提供的实现方法 长度为 100 的数组
Array(100).fill().map((_,i)=>i+1);
// 方法三
[...Array(100).keys()]
Преобразование массива в ассоциативное дерево
const roles = [
{ id: 1, name: 'a', parentId: 0},
{ id: 2, name: 'b', parentId: 0},
{ id: 3, name: 'c', parentId: 1},
{ id: 4, name: 'd', parentId: 1},
{ id: 5, name: 'e', parentId: 2},
{ id: 6, name: 'f', parentId: 2}
]
// const output = [{
// id: 1,
// name: 'a',
// parentId: 0,
// children: [
// { id: 3, name: 'c', parentId: 1, children: [] },
// { id: 4, name: 'd', parentId: 1, children: [] }
// ]
// },
// {
// id: 2,
// name: 'b',
// parentId: 0,
// children: [
// { id: 5, name: 'e', parentId: 2 },
// { id: 6, name: 'f', parentId: 2 }
// ]
// }
// ]
function convert(roles) {
const root = []
const dict = {}
roles.forEach(item => {
if (item.parentId === 0) {
root.push(item)
}
item.children = []
dict[item.id] = item
})
roles.forEach(item => {
if (item.parentId !== 0) {
dict[item.parentId].children.push(item)
}
})
return root
}
console.log(convert(roles))
Преобразование сглаженных данных JSON в JSON с древовидной структурой (json -> дерево, дерево -> json)
const json = [{
id: 1,
name: '1',
parentId: 0
}, {
id: 3,
name: '3',
parentId: 0
}, {
id: 11,
name: '11',
parentId: 1
}, {
id: 12,
name: '12',
parentId: 1
}, {
id: 13,
name: '13',
parentId: 1
}, {
id: 111,
name: '111',
parentId: 11
}, {
id: 112,
name: '112',
parentId: 2
}, {
id: 21,
name: '21',
parentId: 2
}, {
id: 211,
name: '211',
parentId: 21
}, {
id: 1111,
name: '1111',
parentId: 111
}, {
id: 2,
name: '2',
parentId: 0
}]
// json -> tree JSON扁平数据转换为Tree形数据
const jsonToTree = (jsonData, option) => {
const _defaultOption = {
id: 'id',
pid: 'pid',
children: 'children',
rid: 0
}
const {
id,
pid,
children,
rid
} = Object.assign({}, _defaultOption, option)
const map = {}
const tree = []
jsonData.reduce((map, item) => {
map[item[id]] = item
if (item[pid] === rid) {
tree.push(item)
}
return map
}, map)
json.forEach(item => {
if (map[item[pid]]) {
(map[item[pid]][children] || (map[item[pid]][children] = [])).push(item)
}
})
return tree
}
const treeData = jsonToTree(json, {
id: 'id',
pid: 'parentId',
children: 'children'
})
// console.log('tree', JSON.stringify(treeData, null, 2))
// tree -> json 树结构转换为JSON扁平数据
const treeToJson = (tree, option) => {
const _defaultOption = {
pid: 'pid',
children: 'children',
}
const {
children
} = Object.assign(_defaultOption, option)
const json = []
const map = (data) => {
const queue = []
data.forEach(item => {
queue.push(item)
})
while (queue.length) {
const item = queue.shift()
const children = item.children
item.children = null
delete item.children
json.push({
...item
})
if (children) {
children.forEach(child => queue.push(child))
}
}
}
map(tree)
console.log('json', json)
}
treeToJson(treeData, {
pid: 'parent',
children: 'kids'
})
Найдите идентификатор объекта на основе ключевого слова
var docs = [
{
id: 1,
words: ['hello', "world"]
}, {
id: 2,
words: ['hello', "hihi"]
}, {
id: 3,
words: ['haha', "hello"]
}, {
id: 4,
words: ['world', "nihao"]
}
];
findDocList(docs, ['hello']) // 文档id1,文档id2,文档id3
findDocList(docs, ['hello', 'world']) // 文档id1
function findDocList(docs, word = []) {
if (word.constructor !== Array) return;
let ids = [];
for (let i = 0; i < docs.length; i++) {
let {id, words} = docs[i];
let flag = word.every((item) => {
return words.indexOf(item) > -1;
});
flag && ids.push(id);
}
return ids;
}
findDocList(docs, ['hello', 'world']);
полный массив
const permute = function(nums) {
if (nums.length <= 1) return [nums]
const permutes = []
for (let i = 0; i < nums.length; i++) {
const num = nums[i]
const others = nums.slice(0, i).concat(nums.slice(i + 1))
const list = permute(others)
list.forEach(item => {
permutes.push([num].concat(item))
})
}
return permutes
};
const arr = [1, 2, 3]
console.log(permute(arr))
getElementsByClassName совместимое написание
function getByClass(cName) {
if ('getElementsByClassName' in this) {
return this.getElementsByClassName(cName);
}
cName = cName.replace(/(^\s+|\s+$)/g, '').split(/\s+/g);
let eles = this.getElementsByTagName('*');
for (let i = 0; i < cName.length; i++) {
let reg = new RegExp(`(^| )${cName[i]}( |$)`);
let temp = [];
for (let j = 0; j < eles.length; j++) {
let cur = eles[j];
let {className} = cur;
if (reg.test(className)) {
temp.push(cur);
}
}
eles = temp;
}
return eles;
}
console.log(content.getByClass('c1 c2 '));
Сортировка вставками
Сортировка вставками сравнивается сзади наперед, пока не встретится предыдущий элемент, который меньше текущего элемента, вставляя этот элемент после предыдущего элемента.
function insertSort(arr) {
let len = arr.length;
let preIndex, current;
for (let i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i]; // 当前项
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex]; // 如果前一项大于当前项 则把前一项往后挪一位
preIndex-- // 用当前项继续和前面值进行比较
}
arr[preIndex + 1] = current; // 如果前一项小于当前项则 循环结束 则将当前项放到 前一项的后面
}
return arr;
}
function insert(arr, i, x) {
let prev = i - 1;
while(prev >= 0 && arr[prev] > x) {
arr[prev + 1] = arr[prev];
prev--;
}
arr[prev + 1] = x;
}
function insert_sort(arr) {
for (let i = 1; i < arr.length; i++) {
insert(arr, i, arr[i]);
}
return arr;
}
console.log(insert_sort([1, 10, 3, 0]));
сортировка выбором
Сортировка выбором Каждый раз, когда текущий элемент сравнивается с другими элементами после него, получается индексная позиция минимального значения, а затем минимальное значение и текущий элемент меняются местами.
function selectSort(arr) {
let len = arr.length;
let temp = null;
let minIndex = null;
for (let i = 0; i < len - 1; i++) { // 把当前值的索引作为最小值的索引一次去比较
minIndex = i; // 假设当前项索引 为最小值索引
for (let j = i + 1; j < len; j++) { // 当前项后面向一次比小
if (arr[j] < arr[minIndex]) { // 比假设的值还要小 则保留最小值索引
minIndex = j; // 找到最小值的索引位置
}
}
// 将当前值和比较出的最小值交换位置
if (i !== minIndex) {
temp = arr[i]
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
return arr;
}
Пузырьковая сортировка
Пузырьковая сортировка сравнивает два соседних элемента, если текущее значение больше, чем следующий элемент, то меняются местами.
пузырится 1
function swap(arr, i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
function bubleSort(arr) {
let length = arr.length;
let temp = null;
for (let i = 0; i < length - 1; i++) { // 控制轮数
let flag = false; // 当前这轮是否交换过标识
for (let l = 0; l < length - i - 1; l++) { // 控制每轮比较次数
if (arr[l] > arr[l + 1]) {
// temp = arr[l];
// arr[l] = arr[l + 1];
// arr[l + 1] = temp;
swap(arr, l, l + 1);
flag = true; // 如果发生过交换flag则为true
}
}
if (!flag) { // 优化 如果从头到尾比较一轮后 flag依然为false说明 已经排好序了 没必要在继续下去
temp = null;
return arr;
}
}
return arr;
}
пузырятся 2
function swap(arr, i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
function bubble_sort(arr) {
for (let i = arr.length - 1; i >= 1; i--) {
for (let j = 1; j <= i; j++) {
arr[j - 1] > arr[j] && swap(arr, j - 1, j)
}
}
return arr;
}
console.log(bubble_sort([1, 10, 3, 0]));
Быстрая сортировка (издание Жуань Ифэн)
function quickSort(arr) {
if (arr.length <= 1) return arr;
let midIndex = Math.floor(arr.length / 2);
let midNum = arr.splice(midIndex, 1)[0];
let left = [];
let right = [];
for(let i = 0; i < arr.length; i++) {
let cur = arr[i];
if (cur <= midNum) {
left.push(cur);
} else {
right.push(cur);
}
}
return quickSort(left).concat(midNum, quickSort(right));
}
let arr = [2, 4, 12, 9, 22, 10, 18, 6];
quickSort(arr);
Быстрая сортировка, второе издание
let array = [9, 6, 20, 3, 2];
// let array = [15, 13, 20, 21, 29];
function quickSort(arr, left = 0, right = arr.length - 1) {
let len = arr.length;
let partitionIndex;
// left = typeof left != 'number' ? 0 : left;
// right = typeof right != 'number' ? len - 1 : right;
if (left < right) {
partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
return arr;
}
function partition(arr, left, right) {
let pivot = left;
let index = pivot + 1;
for (let i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index - 1;
}
function swap(arr, i, index) {
[arr[i], arr[index]] = [arr[index], arr[i]];
}
console.log(quickSort(array));
Сортировка слиянием
let array = [5, 13, 20, 3, 2];
// let array = [15, 13, 20, 21, 29];
function mergeSort(array) {
let arr = array.slice(0);
let len = arr.length;
if (len < 2) {
return arr;
}
let midIndex = Math.floor(len / 2);
let left = arr.slice(0, midIndex);
let right = arr.slice(midIndex);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let result = [];
while(left.length && right.length) {
result.push(left[0] < right[0] ? left.shift() : right.shift());
}
if (left.length && !right.length) {
result = result.concat(left);
}
if (right.length && !left.length) {
result = result.concat(right);
}
return result;
}
console.log(mergeSort(array));
Несколько методов дедупликации массивов
const arr = [1, 2, 1, 2, 3, 4, 2, 1, 3];
// 1 ES6
let newArr = [...new Set(arr)];
// 2
const arr = [1, 2, 1, 2, 3, 4, 'l', 2, 1, 3, 'l'];
const newArr = arr.filter(function(ele, index, array) {
return index === array.indexOf(ele)
});
console.log(newArr); // [ 1, 2, 3, 4, 'l' ]
// 3
Array.prototype.unique2 = function() {
let newArr = [];
let len = this.length;
for(let i = 0; i < len; i++) {
let cur = this[i];
if(newArr.indexOf(cur) === -1) {
newArr[newArr.length] = cur;
}
}
return newArr;
}
console.log(arr.unique1());
// 4
Array.prototype.unique3 = function() {
let newArr = this.slice(0);
let len = this.length;
let obj = {};
for(let i = 0; i < len; i++) {
let cur = newArr[i];
if(obj[cur]) {
newArr[i] = newArr[newArr.length - 1];
newArr.length--;
i--;
continue;
}
obj[cur] = cur;
}
return newArr;
}
console.log(arr.unique3());
// 5
Array.prototype.unique4 = function() {
let json = {}, newArr = [], len = this.length;
for(var i = 0; i < len; i++) {
let cur = this[i];
if (typeof json[cur] == "undefined") {
json[cur] = true;
newArr.push(cur)
}
}
return newArr;
}
console.log(arr.unique4());
Тысячи
метод первый
// 处理数字
let str1 = 2123456789;
let str2 = 2123456789.12;
console.log(str1.toLocaleString()); // 2,123,456,789
console.log(str2.toLocaleString()); // 2,123,456,789.12
Способ второй
// 处理字符串
let str1 = '2123456789';
let str2 = '2123456789.12';
// 利用正向预查 匹配 开头一个数字\d 后面匹配这个数字后面必须是三个数字为一组为结尾或小数为结尾
function thousandth(str) {
let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g;
return str.replace(reg, '$&,');
}
console.log(thousandth(str1)); // 2,123,456,789
console.log(thousandth(str2)); // 2,123,456,789.12
Найдите значение a, при каких условиях выполняются условия, если (a == 1 & a == 2 & a == 3)
var a = {
a: 1,
valueOf() {
return this.a++
}
}
if (a == 1 & a == 2 & a == 3) {
console.log(1)
}
Макс приводит к массиву, такому как A, B два, чтобы убедиться, что разница между суммой A и B разница между двумя с двумя и B является максимальным индексом массива в соответствии с двумя другими Найдите максимальные два условия A, B (не отсортированы или изменить положение массива) как:
пусть max = (a - b) + (индекс a - индекс b); найти б
Отвечать:
// 思路:其实也就是找出数组中当前的每一项与自身索引相加后的和的最大值以及与索引相加后的最小值的和 找出符合条件的两项即可 如 let result = (maxItem-minItem) + (maxIndex-minIndex) 等价于 (maxItem+maxIndex) - (minItem+minIndex)
// let arr = [1, 2, 3, 4, 5, 6]; // 最简单的测试数组 最小项1 最大项6
// 很显然这个数组中最大值6与索引相加(6+5)是当中最大值11 1与索引相加(1+0)为当中的最小值1(6 + 5)-(1+0)= 10
// 假设法
let arr = [2, 10, 9, 1, 8, 3, 4];
let minItem = arr[0]; // 假设第一项与自身索引的和是最小值 索引为0因此省略
let maxItem = arr[0]; // 假设第一项与自身索引的和是最大值 索引为0因此省略
let min = minItem; // 最小项
let max = maxItem; // 最大项
let minIndex = 0; // 最小项索引
let maxIndex = 0; // 最大项索引
for(let i = 1; i < arr.length; i++) {
let cur = arr[i] + i; // 当前项和自身索引的和
cur < minItem ? (minItem = cur, min = arr[i], minIndex = i) : null;
cur > maxItem ? (maxItem = cur, max = arr[i], maxIndex = i) : null;
}
console.log(maxItem, minItem); // 最大项与索引的和 最小项与索引的和
console.log(max, min); // 最大项 最小项
console.log(maxIndex, minIndex); // 最大项的索引 最小项的索引
Проверьте, сбалансировано ли выражение скобок в строке
// 如 balance('[()') = false; balance('[()()()]') = true
// 一
function match(a, b) {
return (a === '(' && b === ')') || (a === ')' && b === '(') || (a === '[' && b === ']') || (a === ']' && b === '[');
}
function balance(str) {
if (str.length % 2 === 0) {
let len = str.length;
for (let i = 0, j = len - 1; i < len / 2; i++, j--) {
if (!match(str[i], str[j])) {
return false;
}
}
return true;
}
return false;
}
console.log(balance('[()()()]')); // true
console.log(balance('[()')); // false
console.log(balance('[]()')); // false
// 二
function is_balance(str) {
return [...str].reduce((stack, c) => {
match(stack[stack.length - 1], c) ?
stack.pop() : stack.push(c);
return stack;
}, []).length === 0;
}
console.log(is_balance('[()()()]')); // true
console.log(is_balance('[()')); // false
console.log(is_balance('[]()')); // false
сумма трех
// 三数之和
const threeSum = (nums) => {
nums.sort((a, b) => a - b)
const result = []
for (let i = 0, len = nums.length; i < len; i++) {
if (nums[i] > 0) break
// 重复值略过
if (i > 0 && nums[i] === nums[i - 1]) continue
let l = i + 1 // 左指针
let r = len - 1 // 右指针
while (l < r) {
const sum = nums[i] + nums[l] + nums[r]
if (sum > 0) {
r--
} else if (sum < 0) {
l++
} else { // === 0
result.push([nums[i], nums[l], nums[r]])
// 下一项是重复值略过
while (l < r && (nums[l] === nums[l + 1])) l++
// 下一项是重复值略过
while (l < r && (nums[r] === nums[r - 1])) r--
l++
r--
}
}
}
return result
}
Найдите максимальную сумму двух соседних элементов
// 一
let arr1 = [-1, 3, 1, -5, 2]; // 如 [2, 4, -4, -3] => 4
function sum(arr) {
let prev = arr[0];
let sumArr = [];
let len = arr.length;
for(let i = 1; i < len; i++) {
let cur = arr[i];
sumArr.push(cur + prev);
prev = cur;
}
return Math.max(...sumArr);
}
console.log(sum(arr1));
// 二
function maxsum(arr) {
const M = [arr[0]];
let max = M[0];
for(let i = 1; i < arr.length; i++) {
M[i] = Math.max(arr[i], M[i - 1] + arr[i]);
max = Math.max(M[i], max);
}
return max;
}
Строка для удаления соседних дубликатов, например: 'aabbcddeexxxxaa' => 'abcdexa'
// 正则表达式
let str = 'aabbccddeexxxxaa';
function uniq1(str) {
// return str.replace(/([a-z])(\1){1,}/g, '$1');
return str.replace(/(.)(?=\1)/g, '');
}
console.log(uniq1(str));
// 数组方式
function uniq2(str) {
let arr = str.split('');
let newArr = [arr[0]];
for(let i = 1; i < arr.length; i++) {
let cur = arr[i];
if (cur !== newArr[newArr.length - 1]) {
newArr.push(cur);
}
}
return newArr.join('');
}
console.log(uniq2(str));
комбинация свойств
const permutation = (attr) => {
const ans = [], keys = Object.keys(attr)
function dfs(tmp, cur) {
if (keys.length === cur) return ans.push(tmp.slice());
const key = keys[cur], arr = attr[key];
for (let i = 0; i < arr.length; i++) {
tmp.push(`${key}:${arr[i]}`);
dfs(tmp, cur + 1);
tmp.pop();
}
}
dfs([], 0);
return ans;
}
console.log(permutation(attr))
// [
// [ 'color:white', 'size:large', 'type:oversize' ],
// [ 'color:white', 'size:large', 'type:suit' ],
// [ 'color:white', 'size:large', 'type:tight' ],
// [ 'color:white', 'size:medium', 'type:oversize' ],
// [ 'color:white', 'size:medium', 'type:suit' ],
// [ 'color:white', 'size:medium', 'type:tight' ],
// [ 'color:white', 'size:small', 'type:oversize' ],
// [ 'color:white', 'size:small', 'type:suit' ],
// [ 'color:white', 'size:small', 'type:tight' ],
// [ 'color:red', 'size:large', 'type:oversize' ],
// [ 'color:red', 'size:large', 'type:suit' ],
// [ 'color:red', 'size:large', 'type:tight' ],
// [ 'color:red', 'size:medium', 'type:oversize' ],
// [ 'color:red', 'size:medium', 'type:suit' ],
// [ 'color:red', 'size:medium', 'type:tight' ],
// [ 'color:red', 'size:small', 'type:oversize' ],
// [ 'color:red', 'size:small', 'type:suit' ],
// [ 'color:red', 'size:small', 'type:tight' ],
// [ 'color:blue', 'size:large', 'type:oversize' ],
// [ 'color:blue', 'size:large', 'type:suit' ],
// [ 'color:blue', 'size:large', 'type:tight' ],
// [ 'color:blue', 'size:medium', 'type:oversize' ],
// [ 'color:blue', 'size:medium', 'type:suit' ],
// [ 'color:blue', 'size:medium', 'type:tight' ],
// [ 'color:blue', 'size:small', 'type:oversize' ],
// [ 'color:blue', 'size:small', 'type:suit' ],
// [ 'color:blue', 'size:small', 'type:tight' ]
// ]
Обмен ресурсами
Онлайн-учебник по основам JavaScript Документация
С нуля — создайте полный онлайн-учебник по JavaScript
Github некоторая принципиальная реализация
- Бинарное дерево поиска Inorder, preorder, postorder traversal Поиск значений в дереве
- Простая реализация принципов дизайна vue: перехват данных, сбор зависимостей, компиляция шаблонов, двусторонняя привязка, вычисляемые свойства.
- Простая реализация дизайна одностраничной маршрутизации spa
- Реализация взаимодействия с кешем браузера
- npm выпускает статическую запись сервера li-server
- Модуль событий узла реализует публикацию и подписку
Ресурс PDF по структурам данных и алгоритмам JavaScript
Сетевой диск BaiduПароль: ll8d
Страх перед рукописным кодом 😨 укусить только пулю
Все желающие могут присоединиться ко мне, чтобы дополнить.Многое из вышеперечисленного также можно оптимизировать.Я все еще начинающий новичок, просто делюсь и записываю проблемы, с которыми столкнулся.Я продолжу обновлять его позже...