- JavaScript数据结构与算法pdf资源
- 高阶函数实现AOP(面向切面编程)
- 斐波那契数列
- 一道关于Array push的JS题
- 算法题
- 字符串repeat实现
- 当我们 new 一个类的时候 都发生了什么
- this/bind
- Object.create 兼容实现
- 一道面试题
- currying 函数柯理化
- 函数节流
- 函数节流完全版
- 防抖动
- 深度拷贝兼容写法(不包括原型属性)
- 深度克隆加强版
- 原生数据类型检测简易封装
- Array的reduce实现
- Function的bind实现
- 函数组合串联compose(reduce中间件)
- co函数
- es6简版 promise
- 如何主动中止Promise调用链
- bluebird.promisify实现(将异步回调函数api 转换为promise形式)
- window.requestAnimationFrame兼容性处理
- 字符串是否符合回文规则
- 解构
- 数组展平
- 二分查找
- 二分查找题
- 找出数组中重复出现过的元素
- 数组中按照数字重复出现的次数进行排序
- 不用循环,创建一个长度为 100 的数组,并且每个元素的值等于它的下标。
- 根据关键词找出 所在对象id
- getElementsByClassName 兼容写法
- 插入排序
- 选择排序
- 冒泡排序
- 快速排序(阮一峰版)
- 快速排序 第二版
- 归并排序
- 数组去重几种方法
- 千分符
- 在一个数组中 如a、b两项, 要保证a和b两项的差 与 a和b两项索引的差 的相加后的结果max 是数组中其他两项max 中的最大值 找出符合条件两项a, b的值 (不可以排序 或改变数组位置) 如:
- 检测 字符串中括号表达式是否平衡
- 求相邻两项最大和
- 字符串去除相邻的重复项 如:’aabbccddeexxxxaa’ => ‘abcdexa’
- 害怕手写代码 ? 只能硬着头皮
Github 代码实现案例
- 二叉搜索树 中序、先序、后序遍历 搜索树中的值
- vue设计原理简单实现:数据劫持、依赖收集、模板编译、双向绑定、计算属性
- spa单页路由设计简单实现
- 浏览器缓存交互实现
- npm发布li-server静态服务器编写
- node events模块实现 发布订阅
JavaScript数据结构与算法pdf资源
百度网盘 密码:ll8d
如果不喜欢看pdf可以看下面在网上发现一个博客讲解
数据结构与算法讲解.html)高阶函数实现AOP(面向切面编程)
什么是面向切面编程? ```javascript 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===
- 复制代码
```
斐波那契数列
斐波那契数列从第三项开始,每一项都等于前两项之和。指的是这样一个数列: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.非递归
1. function fib(n) {2. let a = 0;3. let b = 1;4. let c = a + b;5. for (let i = 3; i < n; i++) {6. a = b;7. b = c;8. c = a + b;9. }10. return c;11. }12. console.log(fib(10)); // 3413. 复制代码
一道关于Array push的JS题
1. // 类数组2. let obj = {3. '1': 'a',4. '2': 'b',5. length: 26. };7.8. Array.prototype.push.call(obj, 'c');9.10. console.log(obj); // { '1': 'a', '2': 'c', length: 3 }11.12. 复制代码
push和pop实现
Array的push底层实现是依赖于 数组的length属性的
1. Array.prototype.push2 = function(){2. this.splice.apply(this, [this.length, 0].concat(Array.prototype.slice.apply(arguments)));3. return this.length;4. }5. 复制代码
对于 pop也是一样
1. Array.prototype.pop2 = function(){2. return this.splice(this.length - 1, 1)[0];3. }4. 复制代码
算法题
1.在一个数组中 找出里面其中两项相加后的和为num,如果存在就返回两个数的索引位置,否则false
1. function fn(num = 0, ary = []) {2. for (let i = 0; i < ary.length; i++) {3. let diff = num - ary[i];4. let diffIndex = ary.indexOf(diff);5. if (diffIndex !== -1) {6. return [i, diffIndex];7. }8. }9. return false;10. }11.12. let num = 3;13. let arr = [-1, 4, 6, 2];14.15. console.log(fn(num, arr)); // [0, 1]16. 复制代码
2. 将两个有序数组合并为一个排好序的大数组
1. function mergeAry(left = [], right = []) {2. const result = [];3. while (left.length && right.length) {4. result.push(left[0] <= right[0] ? left.shift() : right.shift());5. }6. return result.concat(left, right);7. }8.9. console.log(mergeAry([1, 2, 3], [1, 4, 8, 9])); // [ 1, 1, 2, 3, 4, 8, 9 ]10. 复制代码
字符串repeat实现
1. // 原生repeat2. 'ni'.repeat(3); // 'ninini'3.4. // 实现一5. String.prototype.repeatString1 = function (n) {6. return Array(n + 1).join(this);7. }8. console.log('ni'.repeatString1(3));9.10. // 实现二11. String.prototype.repeatString2 = function (n) {12. return Array(n).fill(this).join('');13. }14. console.log('ni'.repeatString2(3));15. 复制代码
当我们 new 一个类的时候 都发生了什么
1. /**2. * new2 new关键字的代码实现演示3. * @param {function} func 被new的类 (构造函数)4. */5. function new2(func) {6. // 创建了一个实例对象 o,并且这个对象__proto__指向func这个类的原型对象7. let o = Object.create(func.prototype);8. // (在构造函数中this指向当前实例)让这个类作为普通函数值行 并且里面this为实例对象9. let k = func.call(o);10. // 最后再将实例对象返回 如果你在类中显示指定返回值k,11. // 注意如果返回的是引用类型则将默认返回的实例对象o替代掉12. return typeof k === 'object' ? k : o;13. }14.15. // 实验16. function M() { // 即将被new的类17. this.name = 'liwenli';18. }19.20. let m = new2(M); // 等价于 new M 这里只是模拟21. console.log(m instanceof M); // instanceof 检测实例22. console.log(m instanceof Object);23. console.log(m.__proto__.constructor === M);24. 复制代码
this/bind
1. let obj = { a: 1};2. function fn() {3. this.b = 100;4. return this.a;5. }6. let fe = fn.bind(obj);7. console.log(fe()); // 1 里面this是obj8. console.log(obj); // { a: 1, b: 100 }9. console.log(new fe()); // 里面this是当前创建实例对象 { b: 100 }10.11. 复制代码
Object.create 兼容实现
1. let obj1 = {id: 1};2. Object._create = (o) => {3. let Fn = function() {}; // 临时的构造函数4. Fn.prototype = o;5. return new Fn;6. }7.8. let obj2 = Object._create(obj1);9. console.log(obj2.__proto__ === obj1); // true10. console.log(obj2.id); // 111.12. // 原生的Object.create13. let obj3 = Object.create(obj1);14. console.log(obj3.__proto__ === obj1); // true15. console.log(obj3.id); // 116. 复制代码
一道面试题
解法一
1. function CodingMan(name) { // 主要考察的是 面向对象以及JS运行机制(同步 异步 任务队列 事件循环)2. function Man(name) {3. setTimeout(() => { // 异步4. console.log(`Hi! This is ${name}`);5. }, 0);6. }7.8. Man.prototype.sleep = function(time) {9. let curTime = new Date();10. let delay = time * 1000;11. setTimeout(() => { // 异步12. while (new Date() - curTime < delay) {} // 阻塞当前主线程13. console.log(`Wake up after ${time}`);14. }, 0);15. return this;16. }17.18. Man.prototype.sleepFirst = function(time) {19. let curTime = new Date();20. let delay = time * 1000;21. while (new Date() - curTime < delay) {} // 阻塞当前主线程22. console.log(`Wake up after ${time}`);23. return this;24. }25.26. Man.prototype.eat = function(food) {27. setTimeout(() => { // 异步28. console.log(`Eat ${food}~~`);29. }, 0)30. return this;31. }32.33. return new Man(name);34. }35.36. // CodingMan('Peter');37. // CodingMan('Peter').sleep(3).eat('dinner');38. // CodingMan('Peter').eat('dinner').eat('supper');39. // CodingMan('Peter').sleepFirst(5).eat('supper');40. 复制代码
解法二
1. function CodingMan(name) {2. function fe() {3. fe.flag = true;4. console.log(`Hi! This is ${name}`);5. }6. fe.flag = false;7. fe.timer = setTimeout(() => {8. clearTimeout(fe.timer);9. if (!fe.flag) fe();10. }, 0);11. return fe;12. }13.14. Function.prototype.sleep = function (delay) {15. this()16. this.await(delay);17. return this;18. }19.20. Function.prototype.sleepFirst = function (delay) {21. this.await(delay);22. this();23. return this;24. }25.26. Function.prototype.eat = function (dinner) {27. setTimeout(() => {28. console.log(`Eat ${dinner}~`);29. });30. return this;31. };32.33. Function.prototype.await = function (delay) {34. delay = isNaN(delay) ? 0 : delay;35. let startTime = new Date();36. let delayTime = delay * 1000;37. while (new Date() - startTime <= delayTime) {38. }39. console.log(`Wake up after ${delayTime}ms`);40. }41. // CodingMan('peter')42. // CodingMan('peter').sleep(2).eat('hanbao');43. // CodingMan('peter').sleepFirst(2).eat('hanbao');44. CodingMan('peter').eat('haha').eat('hanbao');45. 复制代码
currying 函数柯理化
bind 柯理化
1. function add(a, b, c) {2. return a + b + c;3. }4. let f1 = add.bind(undefined, 100);5. console.log(f1(2, 3)); // 105 = 100 + 2 + 36. let f2 = f1.bind(undefined, 200);7. console.log(f2(3)); // 303 = 100 + 200 + 38.9. 复制代码
curry 柯理化的实现(递归调用 + valueOf)
知识点:对象的valueOf浏览器环境下 隐式转化为基本数据类型(一元操作符+object/字符串拼接 ‘’+object)时,会调用自身的valueOf方法取值,如果自身也存在toString方法 先调用valueOf 如果valueOf返回值不是基本数据类型 则调用toString, toString的返回值也不是基本数据类型就报错。
valueOf调用场景
1. let obj = { x: 1, y: 2 };2.3. obj.toString = function() {4. return this.x + this.y;5. }6.7. obj.valueOf = function() {8. return this.x + this.y + 100;9. }10.11. // 以下情况下自身valueOf被调用12. console.log('' + obj); // 10313. console.log(+obj); // 10314. 复制代码
1. function fn() {};2. fn.valueOf = () => console.log('valueof');3. console.log(fn); // valueof4. 复制代码
1. const mul = x => {2. const result = y => mul(x * y); // 递归调用mul3. result.valueOf = () => x;4. return result;5. }6. console.log(mul(2)(3)); // 67.8. // 在上面mul每执行一次,就会返回一个valueOf被改写后的新函数result 并且result执行会在里面调用mul(x * y)9. // 在result函数的valueOf里保存着 由上一次x * y 传进来的结果x, 也就是上一次x*y 会作为这一次的输出 依然叫x10.11. // 第一次mul(2) 此时 x为2 return result12. result 为 result = y => mul(2 * y);13. // 第二次 mul(2)(3) 等价于 第一个mul返回的result(3), result执行 => mul(2 * 3) 再次调用mul 将2*3 = 6 的结果作为mul参数14. // 最后mul(6) x = 6 在返回一个新函数result 此时result的valueOf = () => 615.16. // log(mul(2)(3)) 相当于log的最后返回的result 隐式调用valueOf 返回 617. 复制代码
curry 将多参数函数转换为接收单一参数的函数
1. function fe(a, b, c) {2. return a + b + c;3. }4.5. function curry(fe) {6. let args = []; // 参数集合7. let len = args.length;8. return function bar() {9. args = [...args, ...arguments]; // 收集参数10. if (args.length >= fe.length) {11. return fe.apply(this, args);12. }13. return bar;14. }15. }16.17. console.log(curry(fe)(1)(2)(3)); // 618. 复制代码
currying 部分求值
1. // currying 函数柯理化2. let currying = function(fn) {3. let args = [];4. return function fe() {5. if (arguments.length === 0) {6. return fn.apply(this, args);7. }8. [].push.apply(args, arguments);9. return fe;10. }11. }12. let count = currying(function (...rest) {13. return rest.reduce((prev, cur) => prev + cur, 0);14. });15.16. console.log(count(100)(200)(10)()); // 31017. 复制代码
收集参数 延迟执行 到达指定次数才执行
1. // 参数收集 指定次数后执行2. function fn(...rest) {console.log(rest);};3. function after(fn, time = 1) {4. let params = [];5. return function(...rest) {6. params = [...params, ...rest];7. if (--time === 0) {8. fn.apply(this, params);9. }10. }11. }12. let newFn = after(fn, 3); // 执行3次 内部fn才会执行13. newFn(2);14. newFn(3);15. newFn(4);16. 复制代码
函数节流
throttle 策略的电梯。保证如果电梯第一个人进来后,50毫秒后准时运送一次,不等待。如果没有人,则待机。
1. let throttle = (fn, delay = 50) => { // 节流 控制执行间隔时间 防止频繁触发 scroll resize mousemove2. let stattime = 0;3. return function (...args) {4. let curTime = new Date();5. if (curTime - stattime >= delay) {6. fn.apply(this, args);7. stattime = curTime;8. }9. }10. }11. 复制代码
函数节流完全版
1. /**2. * @desc 函数防抖3. * @param func 函数4. * @param wait 延迟执行毫秒数5. * @param immediate true 表立即执行,false 表非立即执行6. */7.8. function debounce(func,wait,immediate) {9. var timeout;10.11. return function () {12. var context = this;13. var args = arguments;14.15. if (timeout) clearTimeout(timeout);16. if (immediate) {17. var callNow = !timeout;18. timeout = setTimeout(function(){19. timeout = null;20. }, wait)21. if (callNow) func.apply(context, args)22. }23. else {24. timeout = setTimeout(function(){25. func.apply(context, args)26. }, wait);27. }28. }29. }30.31. 复制代码
防抖动
debounce 策略的电梯。如果电梯里有人进来,等待50毫秒。如果又人进来,50毫秒等待重新计时,直到50毫秒超时,开始运送。
1. let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间 用户输入频繁2. let timer;3. return function (...args) {4. let that = this;5. clearTimeout(timer);6. timer = setTimeout(fn.bind(that, ...args), time);7. }8. }9. 复制代码
深度拷贝兼容写法(不包括原型属性)
1. function deepCopy(obj) {2. if (typeof obj !== 'object') return obj;3. if (typeof window !== 'undefined' && window.JSON) { // 浏览器环境下 并支持window.JSON 则使用 JSON4. return JSON.parse(JSON.stringify(obj));5. } else {6. let newObj = obj.constructor === Array ? [] : {};7. for(let key in obj) {8. newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];9. }10. return newObj;11. }12. }13.14. let obj = {a: 1, b: [12]};15. let newObj = deepCopy(obj);16. newObj.b[1] = 100;17. console.log(obj);18. console.log(newObj);19. 复制代码
深度克隆加强版
1. function cloneDeep(obj) {2. let type = isType(obj)3. if (type === 'Array' || type === 'Object') {4. return cloneObj(obj)5. } else if (type === 'Date') {6. return obj.constructor(obj)7. } else {8. return obj9. }10. }11.12. function cloneObj(obj) {13. let newObj = obj instanceof Array ? [] : {};14. for (let key in obj) {15. newObj[key] = typeof obj[key] === 'object' ? cloneObj(obj[key]) : obj[key]16. }17. return newObj;18. }19.20. function isType(o) {21. return /\[object\s(.*?)\]/.exec(Object.prototype.toString.call(o))[1]22. }23.24. let fn = function () {25. return 12326. }27. var a = [[1, 2, 3], [4, 5, 6, 7, fn]];28. // let c = new Date();29. // var b = cloneDeep(c);30. var b = cloneDeep(a);31. console.log(b[0], a[0]);32. console.log(b[0] === a[0]);33.34. 复制代码
原生数据类型检测简易封装
1. Object.prototype.isType = function (type) {2. return function (params) {3. return Object.prototype.toString.call(params) === `[object ${type}]`4. }5. }6.7. let isString = Object.isType('String')8. let isArray = Object.isType('Array')9.10. console.log(isString(1)) // false11. console.log(isString('hello')) // true12.13. console.log(isArray(2)) // false14. console.log(isArray(['hello'])) // true15. 复制代码
Array的reduce实现
1. Array.prototype._reduce = function (callback, initVal) {2. let i = 03. let result = initVal4. if (typeof initVal === 'undefined') {5. result = this[0]6. i++7. }8.9. for (i; i < this.length; i++) {10. result = callback(result, this[i])11. }12. return result13. }14.15. const arr = [1, 2, 3]16. let result = arr._reduce((a, b) => {17. return a + b18. }, 0)19. console.log(result) // 620. 复制代码
Function的bind实现
1. 1.es52. Function.prototype._bind = function(context) {3. let func = this;4. let params = [].slice.call(arguments, 1);5. let Fnop = function() {};6. let fbound = function() {7. params = params.concat([].slice.call(arguments, 0));8. return func.apply(this instanceof Fnop ?9. this : context, params);10. }11. Fnop.prototype = this.prototype;12. fbound.prototype = new Fnop();13. return fbound;14. }15.16. function foo() {17. this.b = 100;18. return this.a;19. }20. let fe = foo._bind({ a: 1 });21. console.log(fe()); // 122. console.log(new fe()); // 实例 {b: 100}23.24. 2.es625. Function.prototype.mybind = function(context, ...rest) {26. return (...params) => this.call(context, ...rest, ...params);27. }28. 复制代码
函数组合串联compose(reduce中间件)
1. // 组合串联2. let fn1 = (a) => a + 1;3. let fn2 = (b) => b + 2;4. let fn3 = (c) => c + 3;5.6. let funs = [fn1, fn2, fn3];7.8. let compose = (func) => {9. return arg => func.reduceRight((composed, fn) => fn(composed), arg);10. }11. console.log(compose(funs)(100)); // 相当于fn1(fn2(fn3(100)))12. 复制代码
redux 源码中compose实现(github.com/reduxjs/red…)
1. export default function compose(...funcs) {2. if (funcs.length === 0) {3. return arg => arg4. }5.6. if (funcs.length === 1) {7. return funcs[0]8. }9.10. return funcs.reduce((a, b) => (...args) => a(b(...args)))11. }12. 复制代码
koa-compose 实现
1. function compose(middleware) {2. return function(ctx, next) {3. let index = -1;4. return dispatch(0)5. function dispatch(i) {6. if(i <= index) return Promise.reject(new Error('next() called multiple times'));7. index = i;8. let fn = middleware[i]9. if (i === middleware.length) fn = next10. if (!fn) return Promise.resolve()11. try {12. return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))13. } catch(e) {14. return Promise.reject(e)15. }16. }17. }18. }19.20. let mid1 = (ctx, next) => {21. console.log('ctx1', ctx);22. next()23. }24.25. let mid2 = (ctx, next) => {26. console.log('ctx2', ctx);27. next()28. }29.30. let mid3 = (ctx, next) => {31. console.log('ctx3', ctx);32. }33.34. let co = compose([mid1, mid2, mid3])35. co('ctx')36.37. 复制代码
co函数
1. function* fn(a = 0) {2. a = yield a;3. let b = yield 2;4. let c = yield 3;5. return a + b + c;6. }7.8. function co(fn, ...args) {9. let g = fn(...args);10. return new Promise((resolve, reject) => {11. function next(lastValue) {12. let { value, done } = g.next(lastValue);13. if (done) {14. resolve(value);15. } else {16. if (value instanceof Promise) {17. value.then(next, (val) => reject(val));18. } else {19. next(value)20. }21. }22. }23. next();24. });25. }26. co(fn, 100).then(value => {27. console.log(value); // 10528. });29. 复制代码
es6简版 promise
1. class Promise {2. constructor(fn) {3. this.status = 'Pending'4. setTimeout(() => {5. fn((data) => {6. this.resolve(data)7. }, (error) => {8. this.reject(error)9. })10. })11. }12.13. resolve(data) {14. if (this.status === 'Pending') {15. this.success(data)16. this.status = 'Fulfilled'17. }18. }19.20. reject(error) {21. if (this.status === 'Pending') {22. this.error(error)23. this.status = 'Rejected'24. }25. }26.27. then(success, error) {28. this.success = success29. this.error = error30. }31. }32.33. let p1 = new Promise((resolve, reject) => {34. // reject('hello error');35. setTimeout(() => {36. resolve('hello promise')37. }, 1000)38. })39.40. p1.then((data) => console.log(data), (err) => console.log(err))41.42. 复制代码
如何主动中止Promise调用链
1. const p1 = new Promise((resolve, reject) => {2. setTimeout(() => { // 异步操作3. resolve('start')4. }, 1000);5. });6.7. p1.then((result) => {8. console.log('a', result);9. return Promise.reject('中断后续调用'); // 此时rejected的状态将直接跳到catch里,剩下的调用不会再继续10. }).then(result => {11. console.log('b', result);12. }).then(result => {13. console.log('c', result);14. }).catch(err => {15. console.log(err);16. });17.18. // a start19. // 中断后续调用20. 复制代码
bluebird.promisify实现(将异步回调函数api 转换为promise形式)
1. // promisify.js2. module.exports = {3. promisify(fn){4. return function () {5. var args = Array.from(arguments);6. return new Promise(function (resolve, reject) {7. fn.apply(null, args.concat(function (err) {8. if (err) {9. reject(err);10. } else {11. resolve(arguments[1])12. }13. }));14. })15. }16. }17. }18.19. // main.js20. const fs = require('fs');21. const {promisify} = require('./promisify.js');22.23. const readFile = promisify('fs.readFile'); // 转换异步读取24.25. // 异步文件 由回调函数形式变成promise形式26. readFile('./1.txt', 'utf8').then(data => {27. console.log(data);28. }).catch(err => {29. console.log(err);30. });31. 复制代码
window.requestAnimationFrame兼容性处理
1. window._requestAnimationFrame = (function(){2. return window.requestAnimationFrame ||3. window.webkitRequestAnimationFrame ||4. window.mozRequestAnimationFrame ||5. function(callback){6. window.setTimeout(callback, 1000 / 60);7. };8. })();9. 复制代码
字符串是否符合回文规则
1. let str = 'My age is 0, 0 si ega ym.';2.3. 方法一4. function palindrome(params) {5. params = params.replace(/[\W\s_]/ig, '');6. return params.toLowerCase() === params.split('').reverse().join('').toLowerCase();7. }8. console.log(palindrome(str));9.10. 方法二11. function palindrome(params) {12. params = params.replace(/[\W\s_]/ig, '').toLowerCase();13. for (var i = 0, j = params.length-1; i<j; i++, j--) {14. if (params[i] !== params[j]) {15. return false;16. }17. }18. return true;19. }20. 复制代码
解构
1. // 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4}2. const targetArray = [1, [2, 3], 4];3. const formater = "[a, [b], c]";4.5. const destructuringArray = (values, keys) => {6. try {7. const obj = {};8. if (typeof keys === 'string') {9. keys = JSON.parse(keys.replace(/\w+/g, '"$&"'));10. }11.12. const iterate = (values, keys) =>13. keys.forEach((key, i) => {14. if(Array.isArray(key)) iterate(values[i], key)15. else obj[key] = values[i]16. })17.18. iterate(values, keys)19.20. return obj;21. } catch (e) {22. console.error(e.message);23. }24. }25. 复制代码
数组展平
将[[1, 2], 3, [[[4], 5]]] 展平为 [1, 2, 3, 4, 5]
1. let arr = [[1, 2], 3, [[[4], 5]]]; // 数组展平2. function flatten(arr) {3. return [].concat(4. ...arr.map(x => Array.isArray(x) ? flatten(x) : x)5. )6. }7. 复制代码
二分查找
1. const arr = [1, 2, 3, 4, 5, 6, 7, 8];2. // 二分查找 递归 由中间开始往两边查找 前提是有序的数组 返回对应的索引位置3. function binarySearch1(arr, dest, start = 0, end = data.length) {4. if (start > end) {5. return -16. }7. let midIndex = Math.floor((start + end) / 2); // 中间位置索引8. let mid = arr[midIndex]; // 中间值9.10. if (mid == dest) {11. return midIndex;12. }13. if (dest < mid) { // 要找的比中间值小 就从中间往开头找 一直到014. return binarySearch1(arr, dest, 0, midIndex - 1);15. }16. if (dest > mid) { // 要找的比中间值大 就从中间往后找 一直到end结束17. return binarySearch1(arr, dest, midIndex + 1, end);18. }19. return -1; // 找不到返回-120. }21. console.log(binarySearch1(arr, 7, 3, 6)); // 622.23. // 非递归 arr前提有序数组 (从小到大)返回对应的索引位置24. function binarySearch2(arr, dest) {25. let max = arr.length - 1;26. let min = 0;27. while (min <= max) {28. let mid = Math.floor((max + min) / 2); // mid中间位置索引29. if (dest < arr[mid]) { // 如果要找的这项比中间项还要小 说明应该在mid中间位置前面 修改最大边界值max=mid-130. max = mid - 1;31. } else if (dest > arr[mid]) { // 如果要找的这项比中间项还要大 说明应该在mid中间位置的后面 修改最小边界值min=mid+132. min = mid + 1;33. } else {34. return mid;35. }36. }37. return -1; // 找不到返回-138. }39. console.log(binarySearch2(arr, 3)); // 240. 复制代码
二分查找题
在一个二维数组中,每一行都按照从左到右递增,每一列都从上到下递增的顺序排序,完成一个函数,输入这个二维数组和一个整数,判断数组中是否含有该整数
思路是一样的,只不过从一维变成了二维,我们遍历思路可以这样子:
- 选取第一行的最后一个进行判断(这个是第一行中最大的)
- 如果目标大于该值,行数加1,遍历第二行(因为每列都是递增的)
- 如果目标小于该值,则在这一行中进行查找
循环以上步骤
1. function findTarget(arr,target) {2. let i = 0; // i代表行3. let j = arr[i].length -1; // j每行中每项索引位置 从最后项开始比较4. while(i < arr.length && j>=0) {5. if(target < arr[i][j]) {6. j--;7. } else if (target > arr[i][j]) {8. i++;9. } else {10. return `找到了,位置在${i},${j}`11. }12. }13. return `(${i},${j})`14. }15.16. let arr = [17. [1,2,3,4],18. [5,9,10,11],19. [13,20,21,23]20. ] //测试21. 复制代码
找出数组中重复出现过的元素
1. // 例如:[1,2,4,4,3,3,1,5,3]2. // 输出:[1,3,4]3. let arr = [1, 2, 4, 4, 3, 3, 1, 5, 3];4.5. // 方法一6. function repeat1(arr){7. var result = [], map = {};8. arr.map(function(num){9. if(map[num] === 1) result.push(num); // 等于1说明之前出现过一次 这次重复出现了10. map[num] = (map[num] || 0) + 1; // 微妙之处 开始第一次出现无值 记为 0 + 1 = 1 下一次从1开始累加11. });12. return result;13. }14. console.log(repeat1(arr));15.16. // 方法二17.18. function repeat(arr) {19. let result = arr.filter((x, i, self) => {20. return self.indexOf(x) === i && self.lastIndexOf(x) !== i21. }); //22. return result;23. }24. console.log(repeat(arr));25. 复制代码
数组中按照数字重复出现的次数进行排序
1. // 如果次数相同 则按照值排序 比如 2, 2, 2和 1, 1, 1 应排序为 [1, 1, 1, 2, 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]3.4. let arr = [9, 7, 7, 1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2];5. function sortArray(arr) {6. let obj = {};7. let newArr = [];8. for(let i = 0; i < arr.length; i++) {9. let cur = arr[i];10. if(obj[cur]){11. obj[cur].push(cur);12. continue;13. }14. obj[cur] = [cur];15. }16. for(let k in obj) {17. if(obj.hasOwnProperty(k)) {18. newArr.push(obj[k])19. }20. }21. newArr.sort((a, b) => {22. if(a.length === b.length){23. return a[0] - b[0];24. }25. return a.length - b.length;26. });27. newArr = newArr.reduce((prev, cur) => prev.concat(cur));28. return newArr;29. }30. console.log(sortArray(arr)); // [ 3, 9, 4, 4, 7, 7, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2 ]31. 复制代码
不用循环,创建一个长度为 100 的数组,并且每个元素的值等于它的下标。
1. // 方法一 递归写法2. function createArray(len, arr = []) {3.4. if (len > 0) {5. arr[--len] = len;6. createArray(len, arr);7. }8. return arr;9. }10. console.log(createArray(100));11.12. // 方法二13.14. // 下面评论中@MaDivH 提供的实现方法 长度为 100 的数组15. Array(100).fill().map((_,i)=>i+1);16.17. // 方法三18. [...Array(100).keys()]19. 复制代码
根据关键词找出 所在对象id
1. var docs = [2. {3. id: 1,4. words: ['hello', "world"]5. }, {6. id: 2,7. words: ['hello', "hihi"]8. }, {9. id: 3,10. words: ['haha', "hello"]11. }, {12. id: 4,13. words: ['world', "nihao"]14. }15. ];16. findDocList(docs, ['hello']) // 文档id1,文档id2,文档id317. findDocList(docs, ['hello', 'world']) // 文档id118. function findDocList(docs, word = []) {19. if (word.constructor !== Array) return;20. let ids = [];21. for (let i = 0; i < docs.length; i++) {22. let {id, words} = docs[i];23. let flag = word.every((item) => {24. return words.indexOf(item) > -1;25. });26. flag && ids.push(id);27. }28. return ids;29. }30. findDocList(docs, ['hello', 'world']);31.32. 复制代码
getElementsByClassName 兼容写法
1. function getByClass(cName) {2. if ('getElementsByClassName' in this) {3. return this.getElementsByClassName(cName);4. }5. cName = cName.replace(/(^\s+|\s+$)/g, '').split(/\s+/g);6. let eles = this.getElementsByTagName('*');7. for (let i = 0; i < cName.length; i++) {8. let reg = new RegExp(`(^| )${cName[i]}( |$)`);9. let temp = [];10. for (let j = 0; j < eles.length; j++) {11. let cur = eles[j];12. let {className} = cur;13. if (reg.test(className)) {14. temp.push(cur);15. }16. }17. eles = temp;18. }19. return eles;20. }21. console.log(content.getByClass('c1 c2 '));22. 复制代码
插入排序
插入排序 从后往前比较 直到碰到比当前项 还要小的前一项时 将这一项插入到前一项的后面
1. function insertSort(arr) {2. let len = arr.length;3. let preIndex, current;4. for (let i = 1; i < len; i++) {5. preIndex = i - 1;6. current = arr[i]; // 当前项7. while (preIndex >= 0 && arr[preIndex] > current) {8. arr[preIndex + 1] = arr[preIndex]; // 如果前一项大于当前项 则把前一项往后挪一位9. preIndex-- // 用当前项继续和前面值进行比较10. }11. arr[preIndex + 1] = current; // 如果前一项小于当前项则 循环结束 则将当前项放到 前一项的后面12. }13. return arr;14. }15. 复制代码
1. function insert(arr, i, x) {2. let prev = i - 1;3. while(prev >= 0 && arr[prev] > x) {4. arr[prev + 1] = arr[prev];5. prev--;6. }7. arr[prev + 1] = x;8. }9.10. function insert_sort(arr) {11. for (let i = 1; i < arr.length; i++) {12. insert(arr, i, arr[i]);13. }14. return arr;15. }16.17. console.log(insert_sort([1, 10, 3, 0]));18. 复制代码
选择排序
选择排序 每次拿当前项与后面其他项进行比较 得到最小值的索引位置 然后把最小值和当前项交换位置
1. function selectSort(arr) {2. let len = arr.length;3. let temp = null;4. let minIndex = null;5. for (let i = 0; i < len - 1; i++) { // 把当前值的索引作为最小值的索引一次去比较6. minIndex = i; // 假设当前项索引 为最小值索引7. for (let j = i + 1; j < len; j++) { // 当前项后面向一次比小8. if (arr[j] < arr[minIndex]) { // 比假设的值还要小 则保留最小值索引9. minIndex = j; // 找到最小值的索引位置10. }11. }12. // 将当前值和比较出的最小值交换位置13. if (i !== minIndex) {14. temp = arr[i]15. arr[i] = arr[minIndex];16. arr[minIndex] = temp;17. }18. }19. return arr;20. }21. 复制代码
冒泡排序
冒泡排序 相邻两项进行比较 如果当前值大于后一项 则交换位置
冒泡1
1.2. function swap(arr, i, j) {3. [arr[i], arr[j]] = [arr[j], arr[i]]4. }5.6. function bubleSort(arr) {7. let length = arr.length;8. let temp = null;9. for (let i = 0; i < length - 1; i++) { // 控制轮数10. let flag = false; // 当前这轮是否交换过标识11. for (let l = 0; l < length - i - 1; l++) { // 控制每轮比较次数12. if (arr[l] > arr[l + 1]) {13. // temp = arr[l];14. // arr[l] = arr[l + 1];15. // arr[l + 1] = temp;16. swap(arr, l, l + 1);17. flag = true; // 如果发生过交换flag则为true18. }19. }20. if (!flag) { // 优化 如果从头到尾比较一轮后 flag依然为false说明 已经排好序了 没必要在继续下去21. temp = null;22. return arr;23. }24. }25. return arr;26. }27. 复制代码
冒泡2
1. function swap(arr, i, j) {2. [arr[i], arr[j]] = [arr[j], arr[i]]3. }4.5. function bubble_sort(arr) {6. for (let i = arr.length - 1; i >= 1; i--) {7. for (let j = 1; j <= i; j++) {8. arr[j - 1] > arr[j] && swap(arr, j - 1, j)9. }10. }11. return arr;12. }13.14. console.log(bubble_sort([1, 10, 3, 0]));15. 复制代码
快速排序(阮一峰版)
1. function quickSort(arr) {2. if (arr.length <= 1) return arr;3. let midIndex = Math.floor(arr.length / 2);4. let midNum = arr.splice(midIndex, 1)[0];5. let left = [];6. let right = [];7. for(let i = 0; i < arr.length; i++) {8. let cur = arr[i];9. if (cur <= midNum) {10. left.push(cur);11. } else {12. right.push(cur);13. }14. }15. return quickSort(left).concat(midNum, quickSort(right));16. }17.18. let arr = [2, 4, 12, 9, 22, 10, 18, 6];19. quickSort(arr);20. 复制代码
快速排序 第二版
1. let array = [9, 6, 20, 3, 2];2. // let array = [15, 13, 20, 21, 29];3.4. function quickSort(arr, left = 0, right = arr.length - 1) {5. let len = arr.length;6. let partitionIndex;7. // left = typeof left != 'number' ? 0 : left;8. // right = typeof right != 'number' ? len - 1 : right;9. if (left < right) {10. partitionIndex = partition(arr, left, right);11. quickSort(arr, left, partitionIndex - 1);12. quickSort(arr, partitionIndex + 1, right);13. }14. return arr;15. }16.17. function partition(arr, left, right) {18. let pivot = left;19. let index = pivot + 1;20. for (let i = index; i <= right; i++) {21. if (arr[i] < arr[pivot]) {22. swap(arr, i, index);23. index++;24. }25. }26. swap(arr, pivot, index - 1);27. return index - 1;28. }29.30. function swap(arr, i, index) {31. [arr[i], arr[index]] = [arr[index], arr[i]];32. }33. console.log(quickSort(array));34. 复制代码
归并排序
1. let array = [5, 13, 20, 3, 2];2. // let array = [15, 13, 20, 21, 29];3.4. function mergeSort(array) {5. let arr = array.slice(0);6. let len = arr.length;7. if (len < 2) {8. return arr;9. }10. let midIndex = Math.floor(len / 2);11. let left = arr.slice(0, midIndex);12. let right = arr.slice(midIndex);13. return merge(mergeSort(left), mergeSort(right));14. }15.16. function merge(left, right) {17. let result = [];18. while(left.length && right.length) {19. result.push(left[0] < right[0] ? left.shift() : right.shift());20. }21.22. if (left.length && !right.length) {23. result = result.concat(left);24. }25.26. if (right.length && !left.length) {27. result = result.concat(right);28. }29. return result;30. }31.32. console.log(mergeSort(array));33.34. 复制代码
数组去重几种方法
1. const arr = [1, 2, 1, 2, 3, 4, 2, 1, 3];2.3. // 1 ES64. let newArr = [...new Set(arr)];5.6. // 27. const arr = [1, 2, 1, 2, 3, 4, 'l', 2, 1, 3, 'l'];8. const newArr = arr.filter(function(ele, index, array) {9. return index === array.indexOf(ele)10. });11. console.log(newArr); // [ 1, 2, 3, 4, 'l' ]12.13. // 314. Array.prototype.unique2 = function() {15. let newArr = [];16. let len = this.length;17. for(let i = 0; i < len; i++) {18. let cur = this[i];19. if(newArr.indexOf(cur) === -1) {20. newArr[newArr.length] = cur;21. }22. }23. return newArr;24. }25. console.log(arr.unique1());26.27. // 428. Array.prototype.unique3 = function() {29. let newArr = this.slice(0);30. let len = this.length;31. let obj = {};32. for(let i = 0; i < len; i++) {33. let cur = newArr[i];34. if(obj[cur]) {35. newArr[i] = newArr[newArr.length - 1];36. newArr.length--;37. i--;38. continue;39. }40. obj[cur] = cur;41. }42. return newArr;43. }44. console.log(arr.unique3());45.46. // 547. Array.prototype.unique4 = function() {48. let json = {}, newArr = [], len = this.length;49. for(var i = 0; i < len; i++) {50. let cur = this[i];51. if (typeof json[cur] == "undefined") {52. json[cur] = true;53. newArr.push(cur)54. }55. }56. return newArr;57. }58. console.log(arr.unique4());59. 复制代码
千分符
方法一
1. // 处理数字2. let str1 = 2123456789;3. let str2 = 2123456789.12;4. console.log(str1.toLocaleString()); // 2,123,456,7895. console.log(str2.toLocaleString()); // 2,123,456,789.126. 复制代码
方法二
1. // 处理字符串2. let str1 = '2123456789';3. let str2 = '2123456789.12';4.5. // 利用正向预查 匹配 开头一个数字\d 后面匹配这个数字后面必须是三个数字为一组为结尾或小数为结尾6. function thousandth(str) {7. let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g;8. return str.replace(reg, '$&,');9. }10. console.log(thousandth(str1)); // 2,123,456,78911. console.log(thousandth(str2)); // 2,123,456,789.1212. 复制代码
在一个数组中 如a、b两项, 要保证a和b两项的差 与 a和b两项索引的差 的相加后的结果max 是数组中其他两项max 中的最大值 找出符合条件两项a, b的值 (不可以排序 或改变数组位置) 如:
let max = (a - b) + (a的索引- b的索引); 求a b
答案:
1. // 思路:其实也就是找出数组中当前的每一项与自身索引相加后的和的最大值以及与索引相加后的最小值的和 找出符合条件的两项即可 如 let result = (maxItem-minItem) + (maxIndex-minIndex) 等价于 (maxItem+maxIndex) - (minItem+minIndex)2.3. // let arr = [1, 2, 3, 4, 5, 6]; // 最简单的测试数组 最小项1 最大项64. // 很显然这个数组中最大值6与索引相加(6+5)是当中最大值11 1与索引相加(1+0)为当中的最小值1(6 + 5)-(1+0)= 105.6. // 假设法7. let arr = [2, 10, 9, 1, 8, 3, 4];8. let minItem = arr[0]; // 假设第一项与自身索引的和是最小值 索引为0因此省略9. let maxItem = arr[0]; // 假设第一项与自身索引的和是最大值 索引为0因此省略10. let min = minItem; // 最小项11. let max = maxItem; // 最大项12. let minIndex = 0; // 最小项索引13. let maxIndex = 0; // 最大项索引14. for(let i = 1; i < arr.length; i++) {15. let cur = arr[i] + i; // 当前项和自身索引的和16. cur < minItem ? (minItem = cur, min = arr[i], minIndex = i) : null;17. cur > maxItem ? (maxItem = cur, max = arr[i], maxIndex = i) : null;18. }19. console.log(maxItem, minItem); // 最大项与索引的和 最小项与索引的和20. console.log(max, min); // 最大项 最小项21. console.log(maxIndex, minIndex); // 最大项的索引 最小项的索引22. 复制代码
检测 字符串中括号表达式是否平衡
1. // 如 balance('[()') = false; balance('[()()()]') = true2. // 一3. function match(a, b) {4. return (a === '(' && b === ')') || (a === ')' && b === '(') || (a === '[' && b === ']') || (a === ']' && b === '[');5. }6.7. function balance(str) {8. if (str.length % 2 === 0) {9. let len = str.length;10. for (let i = 0, j = len - 1; i < len / 2; i++, j--) {11. if (!match(str[i], str[j])) {12. return false;13. }14. }15. return true;16. }17. return false;18. }19. console.log(balance('[()()()]')); // true20. console.log(balance('[()')); // false21. console.log(balance('[]()')); // false22. // 二23. function is_balance(str) {24. return [...str].reduce((stack, c) => {25. match(stack[stack.length - 1], c) ?26. stack.pop() : stack.push(c);27. return stack;28. }, []).length === 0;29. }30. console.log(is_balance('[()()()]')); // true31. console.log(is_balance('[()')); // false32. console.log(is_balance('[]()')); // false33. 复制代码
求相邻两项最大和
1. // 一2. let arr1 = [-1, 3, 1, -5, 2]; // 如 [2, 4, -4, -3] => 43. function sum(arr) {4. let prev = arr[0];5. let sumArr = [];6. let len = arr.length;7. for(let i = 1; i < len; i++) {8. let cur = arr[i];9. sumArr.push(cur + prev);10. prev = cur;11. }12. return Math.max(...sumArr);13. }14. console.log(sum(arr1));15.16. // 二17. function maxsum(arr) {18. const M = [arr[0]];19. let max = M[0];20.21. for(let i = 1; i < arr.length; i++) {22. M[i] = Math.max(arr[i], M[i - 1] + arr[i]);23. max = Math.max(M[i], max);24. }25. return max;26. }27.28. 复制代码
字符串去除相邻的重复项 如:’aabbccddeexxxxaa’ => ‘abcdexa’
1. // 正则表达式2. let str = 'aabbccddeexxxxaa';3. function uniq1(str) {4. // return str.replace(/([a-z])(\1){1,}/g, '$1');5. return str.replace(/(.)(?=\1)/g, '');6. }7. console.log(uniq1(str));8.9. // 数组方式10. function uniq2(str) {11. let arr = str.split('');12. let newArr = [arr[0]];13. for(let i = 1; i < arr.length; i++) {14. let cur = arr[i];15. if (cur !== newArr[newArr.length - 1]) {16. newArr.push(cur);17. }18. }19. return newArr.join('');20. }21. console.log(uniq2(str));22. 复制代码
害怕手写代码 ? 只能硬着头皮
欢迎大家和我一起来补充 上面很多也都是可以优化的 我还是一个成长中的小白,只是分享和记录下自己碰到的问题 后续会持续更新…
