• 几道JS代码手写面试题


    几道JS代码手写面试题

     

    (1) 高阶段函数实现AOP(面向切面编程)

       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.非递归

    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)

    一道关于Array push的JS题

    // 类数组
    let obj = {
      '1': 'a',
      '2': 'b',
      length: 2
    };

    Array.prototype.push.call(obj, 'c');

    console.log(obj); // { '1': 'a', '2': 'c', length: 3 }

    push和pop实现

     

    Array的push底层实现是依赖于 数组的length属性的

    Array.prototype.push2 = function(){
      this.splice.apply(this, [this.length, 0].concat(Array.prototype.slice.apply(arguments)));
      return this.length;
    }

    对于 pop也是一样

    Array.prototype.pop2 = function(){
      return this.splice(this.length - 1, 1)[0];
    }

    算法题

    1.在一个数组中 找出里面其中两项相加后的和为num,如果存在就返回两个数的索引位置,否则false

    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) {
          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 ]

    字符串repeat实现

    // 原生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));

    当我们 new 一个类的时候 都发生了什么

    /**
     * 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');

    currying 函数柯理化

    bind 柯理化

    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

    curry 柯理化的实现(递归调用 + valueOf)

    知识点:对象的valueOf浏览器环境下 隐式转化为基本数据类型(一元操作符+object/字符串拼接 ”+object)时,会调用自身的valueOf方法取值,如果自身也存在toString方法 先调用valueOf 如果valueOf返回值不是基本数据类型 则调用toString, toString的返回值也不是基本数据类型就报错。

    valueOf调用场景

    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 部分求值

    // 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);

    函数节流

    throttle 策略的电梯。保证如果电梯第一个人进来后,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;
                    }
                }
            }

    函数节流安全版

    /**
     * @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);
            }
        }
    }

    防抖动

    debounce 策略的电梯。如果电梯里有人进来,等待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 /[objects(.*?)]/.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的reduce实现

    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

    Function的bind实现

    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);
      }

    函数组合串联compose(reduce中间件)

    // 组合串联
    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)))

    redux 源码中compose实现(https://github.com/reduxjs/redux/blob/master/src/compose.js)

    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')

    co函数

    function* fn(a = 0) {
      a = yield a;
      let b = yield 2;
      let c = yield 3;
      return a + b + c;
    }

    function co(fn, ...args) {
      let g = fn(...args);
      return new Promise((resolve, reject) => {
        function next(lastValue) {
            let { value, done } = g.next(lastValue);
            if (done) {
              resolve(value);
            } else {
             if (value instanceof Promise) {
               value.then(next, (val) => reject(val));
             } else {
               next(value)
             }
            }
        }
        next();
      });
    }
    co(fn, 100).then(value => {
        console.log(value); // 105
    });

    es6简版 promise

    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 转换为promise形式)

    // 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); 
    }; 
    })();

    字符串是否符合回文规则

    方法一

    function palindrome(params) { 
    params = params.replace(/[Ws_]/ig, ”); 
    return params.toLowerCase() === params.split(”).reverse().join(”).toLowerCase(); 

    console.log(palindrome(str));

    方法二 

    function palindrome(params) { 
    params = params.replace(/[Ws_]/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]

    let arr = [9, 7, 7, 1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2]; 
    function sortArray(arr) { 
    let obj = {}; 
    let newArr = []; 
    for(let i = 0; i < arr.length; i++) { 
    let cur = arr[i]; 
    if(obj[cur]){ 
    obj[cur].push(cur); 
    continue; 

    obj[cur] = [cur]; 

    for(let k in obj) { 
    if(obj.hasOwnProperty(k)) { 
    newArr.push(obj[k]) 


    newArr.sort((a, b) => { 
    if(a.length === b.length){ 
    return a[0] - b[0]; 

    return a.length - b.length; 
    }); 
    newArr = newArr.reduce((prev, cur) => prev.concat(cur)); 
    return newArr; 

    console.log(sortArray(arr)); // [ 3, 9, 4, 4, 7, 7, 1, 1, 1, 5, 5, 5, 2, 2, 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()]

    根据关键词找出 所在对象id

    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’]);

    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]));
  • 相关阅读:
    P3193 [HNOI2008]GT考试(KMP+矩阵乘法加速dp)
    P2606 [ZJOI2010]排列计数
    洛谷P2657 [SCOI2009]windy数
    P2602 [ZJOI2010]数字计数(递推)
    洛谷 P1073 最优贸易
    [一本通学习笔记] 字典树与 0-1 Trie
    [一本通学习笔记] KMP算法
    [一本通学习笔记] 字符串哈希
    [一本通学习笔记] 广度优先搜索和优化
    [一本通学习笔记] 深度优先搜索与剪枝
  • 原文地址:https://www.cnblogs.com/still1/p/11008209.html
Copyright © 2020-2023  润新知