手写前端常用算法

判断对象属性

var uniqueObject = function(arr) {
    var v, r = [], o = {};
    for(var i = 0; (v = arr[i]) !== undefined; i++) {
        !o[v] && (r.push(v), o[v] = true);
    }
    return r;
};

数组过滤重复项filter

var uniqueFilter = function(arr) {
    return arr.filter(function(elem, pos, self) {
        // 如果没有重复项,返回true
        return self.indexOf(elem, pos + 1) === -1;
    });
};

防抖函数

function debounce(fn,delay) {
    let timeout = null;
    return function() {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            fn.apply(this.arguments);
        },delay);
    }
};

节流函数

function throttle(fn,delay) {
    let canRun = true;
    return function() {
        if(!canRun) return;
        canRun = false;
        setTimeout(() => {
            fn.apply(this, arguments);
            canRun = true;
        },delay);
    };
}

深度优先遍历 递归:

function deepTraversal1(node,nodeList = []) {
    if(node !== null) {
        nodeList.push(node)
        let children = node.children
        for(let i = 0; i < children.length; i++){
            deepTraversal1(children[i],nodeList)
        }
    }
    return nodeList;
}

深度优先遍历 非递归

function deepTraversal2(node) {
    let stack = [];
    let nodes = [];
    if(node) {
        stack.push(node)
        while(stack.length) {
            let item = stack.pop()
            let children = item.children;
            nodes.push(item)
            for(let i = children.length - 1; i >= 0; i--) {
                stack.push(children[i])
            }
        }
    }
    return nodes;
}

广度优先遍历

function bfs(node) {
    let nodes = [];
    let stack = [];
    if(node){
        stack.push(node)
        while(stack.length) {
            let item = stack.shift()
            let children = item.children
            nodes.push(item)
            for(let i = 0;i < children.length; i++) {
                stack.push(children[i])
            }
        }
    }
    return nodes;
}

浅拷贝

function clone(target){
    let cloneTarget = {};
    for(const key in target){
        cloneTarget[key] = target[key];
    }
    return cloneTarget;
}

深拷贝

function isObject(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function');
}
function getType(target) {
    return Object.prototype.toString.call(target);
}
function getInit(target) {
    const Ctor = target.constructor;
    return new Ctor();
}
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';

function forEach(array, iteratee) {
    let index = -1;
    const length = array.length;
    while (++index < length) {
        iteratee(array[index], index);
    }
    return array;
}
function deepclone(target, map = new WeakMap()) {
    const mapTag = '[object Map]';
    const setTag = '[object Set]';
    const arrayTag = '[object Array]';
    // 克隆原始类型
    const targetType = typeof target;
    if(!(target !== null
        && (targetType === 'object' || targetType === 'function')
        )){
        return target;
    }
    // 初始化
    const type = Object.prototype.toString.call(target);
    let cloneTarget;
    // 暂时考虑四种可遍历的
    const deepTag = ['[object Map]','[object Set]','[object Array]','[object Object]'];
    if (deepTag.includes(type)) {
        // 拿到对象原型
        const Ctor = target.constructor
        cloneTarget = new Ctor();
    }

    // 防止循环引用,判断target被拷贝过了就直接返回,否则去set[key,value]
    // weakmap 弱引用,可以被垃圾回收机制回收,避免内存被占用
    if (map.get(target)) {
        return map.get(target);
    }
    map.set(target, cloneTarget);

    // 克隆set
    if (type === setTag) {
        target.forEach(value => {
            cloneTarget.add(clone(value,map));
        });
        return cloneTarget;
    }

    // 克隆map
    if (type === mapTag) {
        target.forEach((value, key) => {
            cloneTarget.set(key, clone(value,map));
        });
        return cloneTarget;
    }

    // 克隆对象和数组
    const keys = type === arrayTag ? undefined : Object.keys(target);
    // 这里的foreach 是用while改写的,while的遍历性能最快
    forEach(keys || target, (value, key) => {
        if (keys) {
            key = value;
        }
        cloneTarget[key] = clone(target[key], map);
    });

    return cloneTarget;
}

promise

// MyPromise.js

// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// 新建 MyPromise 类
class MyPromise {
  constructor(executor){
    // executor 是一个执行器,进入会立即执行
    // 并传入resolve和reject方法
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  // 储存状态的变量,初始值是 pending
  status = PENDING;
  // 成功之后的值
  value = null;
  // 失败之后的原因
  reason = null;

  // 存储成功回调函数
  onFulfilledCallbacks = [];
  // 存储失败回调函数
  onRejectedCallbacks = [];

  // 更改成功后的状态
  resolve = (value) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改为成功
      this.status = FULFILLED;
      // 保存成功之后的值
      this.value = value;
      // resolve里面将所有成功的回调拿出来执行
      while (this.onFulfilledCallbacks.length) {
        // Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
        this.onFulfilledCallbacks.shift()(value)
      }
    }
  }

  // 更改失败后的状态
  reject = (reason) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态成功为失败
      this.status = REJECTED;
      // 保存失败后的原因
      this.reason = reason;
      // resolve里面将所有失败的回调拿出来执行
      while (this.onRejectedCallbacks.length) {
        this.onRejectedCallbacks.shift()(reason)
      }
    }
  }

  then(onFulfilled, onRejected) {
    const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};

    // 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
    const promise2 = new MyPromise((resolve, reject) => {
      const fulfilledMicrotask = () =>  {
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          try {
            // 获取成功回调函数的执行结果
            const x = realOnFulfilled(this.value);
            // 传入 resolvePromise 集中处理
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error)
          } 
        })  
      }

      const rejectedMicrotask = () => { 
        // 创建一个微任务等待 promise2 完成初始化
        queueMicrotask(() => {
          try {
            // 调用失败回调,并且把原因返回
            const x = realOnRejected(this.reason);
            // 传入 resolvePromise 集中处理
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error)
          } 
        }) 
      }
      // 判断状态
      if (this.status === FULFILLED) {
        fulfilledMicrotask() 
      } else if (this.status === REJECTED) { 
        rejectedMicrotask()
      } else if (this.status === PENDING) {
        // 等待
        // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
        // 等到执行成功失败函数的时候再传递
        this.onFulfilledCallbacks.push(fulfilledMicrotask);
        this.onRejectedCallbacks.push(rejectedMicrotask);
      }
    }) 
    
    return promise2;
  }

  // resolve 静态方法
  static resolve (parameter) {
    // 如果传入 MyPromise 就直接返回
    if (parameter instanceof MyPromise) {
      return parameter;
    }

    // 转成常规方式
    return new MyPromise(resolve =>  {
      resolve(parameter);
    });
  }

  // reject 静态方法
  static reject (reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  // 如果相等了,说明return的是自己,抛出类型错误并返回
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  // 判断x是不是 MyPromise 实例对象
  if(x instanceof MyPromise) {
    // 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
    // x.then(value => resolve(value), reason => reject(reason))
    // 简化之后
    x.then(resolve, reject)
  } else{
    // 普通值
    resolve(x)
  }
}

数组扁平化去重升序

var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
function flatten(arr) {

    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr);
    }
    return arr;
}

function flatten2(arr) {
    let arrs =[...arr]
    let newArr = [];
    while (arrs.length) {
      let item = arrs.shift()
      if(Array.isArray(item)){
          arrs.unshift(...item)
      }else {
        newArr.push(item)
      }
    }
  return newArr
}

Array.from(new Set(flatten(arr))).sort((a, b) => {
 return a - b
})

实现一个new

function _new() {
  let constructor = Array.prototype.shift.call(arguments)
  let args = arguments;
  const obj = new Object;
  obj._proto_ = constructor.prototype;
  constructor.call(obj,...args);
  return obj;
}

一个简单的数据劫持

// 订阅器模型
let Dep = {
  clientList: {},
  // 添加订阅
  listen: function(key, fn) {
    (this.clientList[key] || (this.clientList[key] = [])).push(fn);
  },
  // 发布
  trigger: function(){
    // 将类数组转化为数组
    let key = Array.prototype.shift.call(arguments),
        fnd = this.clientList[key];
    if(!fns || fns.length === 0){
      return false;
    }
    for(let i = 0,fn; fn = fns[i++];) {
      fn.apply(this,arguments)
    }
  }
}
//数据劫持
/**
 * data:我们要劫持的数据
 * datakey:具体的属性值
 * selector:dom节点
 */
let mydatadefineProperty = function ({data, tag, datakey, selector}){
  let value = '',
      el = document.querySelector(selector);
  Object.defineProperty(data,datakey,{
    get: function () {
      return value;
    },
    set: function (val) {
      value = val;
      // 发布
      Dep.trigger(tag, val);
    }
  })
  // 订阅
 Dep.listen(tag, function(text){
   el.innerHtml = text;
 })
}

改造为输出0-9

for (var i = 0; i< 10; i++){
	setTimeout(() => {
		console.log(i);
    }, 1000)
}
// 1 setTimeout 第三个参数
for (var i = 0; i < 10; i++) {
  setTimeout(i => {
    console.log(i);
  }, 1000, i)
}
// 利用let
for(let i = 0; i < 10; i++){
  setTimeout(() => {
		console.log(i);
    }, 1000)
}
//立即执行函数iife,构造出块级作用域

for (var i = 0; i < 10; i++) {
  (i => {
    setTimeout(() => {
      console.log(i);
    }, 1000)
  })(i)
}
// 利用try catch
for(var i = 0; i < 10; i++){
  try{
     throw i;
  }catch(i){
     setTimeout(() => { console.log(i); },1000)
  }
}

var a = ?;如何输出1

if(a == 1 && a == 2 && a == 3){
 	console.log(1);
}
// 1、重写toString
var a = {
  i: 1,
  toString() {
    return a.i++;
  }
}

if( a == 1 && a == 2 && a == 3 ) {
  console.log(1);
}
// 2、利用valueOf
let a = {
  i: 1,
  valueOf () {
    return a.i++
  }
}

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

实现一个sleep

function sleep(time) {
  return new Promise(resolve => setTimeout(resolve,time))
}
function* sleepGen(time) {
  yield new Promise(function(resolve,reject){
    setTimeout(resolve,reject);
  })
}
sleepGen(1000).next().value.then(()=>{console.log(1)})

冒泡排序

function buddleSort (arr) {
  let len = arr.length;
  for (let i = len;  i >= 2;  i-- ) {
      for (let j = 0;  j < i - 1;  j++) {
           if (arr[j] > arr[j+1]) {
                [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
           }
      }
  }
  return arr;
}

实现一个字符串匹配算法, **从长度为 n 的字符串 S 中,查找是否存在字符串 T,T 的长度是 m,若存在返回所在位置

const find = (S, T) => {
  if (S.length < T.length) return -1
  for (let i = 0; i < S.length - T.length; i++) {
    if (S.slice(i, i + T.length) === T) return i
  }
  return -1
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值