手撕JavaScript代码

实现 new 关键字

const New = function(fn, ...args) {
  // 创建空对象 
  let obj = {};
  // 空对象的隐式原型连接构造函数的显式原型
  obj.__proto__ = fn.prototype;
  // 构造函数的this指向空对象并执行
  let result = fn.apply(obj, ...args);
  // 结果不是对象就返回空对象
  return result instanceof Object ? result : obj;
} 

实现 instanceof 关键字

function Instanceof(obj, Fn) {
  // 构造函数必须是函数类型
  if (typeof Fn !== 'function') throw new TypeError('不是函数');
  // 实例必须是对象或函数
  if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) return false;
  // Fn的prototype原型
  let proto = Fn.prototype;
  while (obj.__proto__) {
    if (obj.__proto__ === proto) return true;
    // 原型链查找
    obj = obj.__proto__;
  }
  return false;
}

实现 call() && apply()

Function.prototype.call = function(context, ...args) {
  // 传入对象为空则默认为window
  context = context || window;
  // obj2上保存obj1函数,可以用Symbol创建唯一属性
  context.fn = this;
  // 在obj2中执行obj1函数,obj1中的this指向obj2
  const result = context.fn(...args);
  Reflect.deleteProperty(context, 'fn');
  // 返回结果
  return result;
}
Function.prototype.apply = function(context, args=[]) {
  // 传入对象为空则默认为window
  context = context || window;
  // obj2上保存obj1函数,可以用Symbol创建唯一属性
  context.fn = this;
  // 在obj2中执行obj1函数,obj1中的this指向obj2
  const result = context.fn(...args);
  Reflect.deleteProperty(context, 'fn');
  // 返回结果
  return result;
}

实现 bind()

Function.prototype.bind = function(context, ...arg1) {
  // this是obj1,context是obj2
  const self = this;
  // 闭包一个函数
  const res = function(...arg2) {
    // self是obj1,this是res的调用者,context是obj2,res.prototype是obj1的原型
    // 当new res()时,res的调用者是隐式原型为obj1原型的对象
    // 如果调用者的隐式原型与obj1的显示原型一样,说明是res做构造函数使用,obj1的this指向调用者
    // 否则将obj1的this指向obj2
    return self.apply(this.__proto__ === res.prototype ? this: context, [...arg1, ...arg2]);
  }
  // this是obj1,obj1与res的原型连接
  if (this.prototype) res.prototype = this.prototype;
  return res;
}

实现 map() && reduce()

Array.prototype.map = function(fn) {
  let arr = []
  for (let i = 0; i < this.length; i++) {
    arr.push(fn(this[i], i, this));
  }
  return arr;
}
Array.prototype.reduce = function(fn, initVal) {
  let res = initVal ? initVal : this[0]
  for (let i = initVal ? 0 : 1; i < this.length; i++) {
    res = fn(res, this[i], i, this);
  }
  return res;
}

实现 throttle() && debounce()

function throttle(fn, delay, ...args) {
  let canRun = true;
  // 闭包
  return function() {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn.apply(this, args);
      canRun = true;
    }, delay);
  };
}
function debounce(fn, delay, ...args) {
  let timer = null;
  // 闭包
  return function() {
    clearTimeout(timer); 
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

用 setTimeout() 实现 setInterval()

// 储存定时器ID
const timer = {};
function setInterval(fn, delay, ...args) {
  timer.id = setTimeout(() => {
    clearTimeout(timer);
    fn.apply(this, args);
    setInterval(fn, delay);
  }, delay);
}
// 关闭定时器
clearTimeout(timer.id);

实现 Promise.retry()

Promise.prototype.retry = function(fn, times, delay) {
  return new Promise((resolve, reject) => {
    const action = () => {
      // 执行异步操作
      fn()
      .then(res => resolve(res))
      .catch(err => {
        if (times <= 1) reject(err);
        else {
          times--;
          setTimeout(() => action(), delay);
        }
      })
    };
    action(resolve, reject);
  })
}

实现 Promise.all()

Promise.prototype.all = function(promises) {
  return new Promise((resolve, reject) => {
    const len = promises.length;
    const p = new Array(len);
    let count = 0;
    for (let i = 0; i < len; i++) {
      // 转成Promise对象
      Promise.resolve(promises[i])
      .then(res => {
        p[i] = res;
        count++;
        if (count === len) resolve(p);
      })
      .catch(err => reject(err))
    }
  })
}

实现 Promise.race()

Promise.prototype.race = function(promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      // 转成Promise对象
      Promise.resolve(promises[i])
      .then(res => resolve(res))
      .catch(err => reject(err))
    }
  })
}

实现 懒惰计算(Lazy)

function Lazy(num) {
  this.fns = [];
  this.res = num;
  this.f = null;
  // setTimeout(() => this.next(), 0);
}
Lazy.prototype = {
  add(num) {
    const fn = () => {
      this.res += num;
      this.f?.(this.res);
      this.next();
    };
    this.fns.push(fn);
    return this;
  },
  tap(f) {
    this.f = f;
    const fn = () => this.next();
    this.fns.push(fn);
    return this;
  },
  delay(time) {
    const fn = () => {
      setTimeout(() => this.next(), time);
    };
    this.fns.push(fn);
    return this;
  },
  next() {
    const fn = this.fns.shift();
    fn?.();
  },
};

const lazy = (num) => new Lazy(num);

const lazyCalc = lazy(2).add(2).delay(1000).add(3).tap(console.log);
lazyCalc.next();

实现 数据类型判断

function getType(obj) {
  const map = {
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object'
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Function]': 'function',
  };
  if (obj instanceof Element) return 'element';
  return map[Object.prototype.toString.call(obj)];
}

实现 对象扁平化

function flatten(obj) {
  let result = {}
  const process = (key, value) => {
    // 基础数据类型: String, Number, Boolean
    if (Object(value) !== value) {
      if (value !== null && value !== undefined) result[key] = value;
    } 
    // 引用数据类型: Array
    else if (Array.isArray(value)) {
      for (let i = 0; i < value.length; i++) {
        process(`${key}[${i}]`, value[i]);
      }
      if (value.length === 0) result[key] = [];
    } 
    // 引用数据类型: Object
    else {
      const keys = Object.keys(value);
      keys.forEach(item => process(key ? `${key}.${item}` : `${item}`, value[item]));
      if (keys.length === 0 && key) result[key] = {};
    }
  }
  process('', obj);
  return result;
}

实现 扁平转对象

function process(obj) {
  const keys = Object.keys(obj);
  const res = {};
  for (const key of keys) {
    const chain = key.split(".");
    let temp = res;
    for (let i = 0; i < chain.length; i++) {
      const k = chain[i];
      temp[k] = temp[k] ?? (i === chain.length - 1 ? obj[key] : {});
      temp = temp[k];
    }
  }
  return res;
}

实现 数组扁平化

function flatten(arr) {
  let res = []
  arr.forEach(item => {
    if (Array.isArray(item)) res = res.concat(flatten(item));
    else  res.push(item);
  })
  return res;
}

实现 对象深拷贝

①遇到函数时,可以调用toString()方法获取字符串表示,并且eval()还原来实现深拷贝。

function deepClone(obj) {
  let copy = Array.isArray(obj) ? [] : {};
  if (typeof obj === "object") {
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        if (obj[key] && typeof obj[key] === "object") {
          copy[key] = deepClone(obj[key]);
        } else {
          copy[key] = obj[key];
        }
      }
    }
  }
  return copy;
}

实现 函数柯里化

函数参数不确定的柯里化

function add() {
  return [...arguments].reduce((r, v) => r + v);
}
function curry(fn) {
  let args = [];
  return function Fun() {
    args = [...args, ...arguments];
    if (arguments.length) return Fun;
    else return fn.apply(this, args);
  }
}

函数参数确定的柯里化

function add(arg1, arg2, arg3) {
  return [...arguments].reduce((r, v) => r + v)
}
function curry(fn) {
  let args = [];
  return function Fun(){
    args = [...args, ...arguments];
    if(arg.length < fn.length) return Fun;
    else return fn.apply(this, args);
  }
}

实现 数组 转 树结构

function fun(data) {
  let res = [];
  let map = {};
  data.forEach(item => map[item.id] = item);
  data.forEach(item => {
    let parent = map[item.parentId];
    if (parent) (parent.children = parent.children || []).push(item);
    else res.push(item);
  })
  return res;
}

实现 XML转JSON对象

function xml2json(str) {
  let res;
  let stack = [];
  let text = "";
  for (let i = 0; i < str.length; i++) {
    if (str[i] === "<") {
      i++;
      let tagName = "";
      while (i < str.length && str[i] !== ">") {
        tagName += str[i];
        i++;
      }
      if (tagName[0] === "/") {
        res = stack.pop();
        if (!res.children.length) res.children = text;
        if (stack.length > 1) stack[stack.length - 1].children.push(res);
      } else {
        stack.push({ tag: tagName, children: [] });
      }
      text = "";
      continue;
    }
    text += str[i];
  }
  return res;
}

实现 EventEmitter

function EventEmitter() {
  this.events = {};
  // 订阅
  this.on = (event, fn) => (this.events[event] = this.events[event] || []).push(fn);
  // 发布
  this.emit = (event, ...args) => {
    const fns = this.events[event];
    fns.forEach(fn => fn.apply(this, args));
  };
  // 取消订阅
  this.off = (event, fn) => {
  	const fns = this.events[event];
  	this.events[event] = fns && fns.filter(f => f !== fn);
  };
  // 触发一次
  this.once = (event, fn) => {
  	const wrapFun = (...args) => {
  	  fn.apply(this, args);
  	  this.off(event, wrapFun);
  	};
  	this.on(event, wrapFun);
  };
}

实现 JSONP

<script type="text/javascript">
    let url = "http://xxx/xxx?callback=fun";
    let script = document.createElement('script');
    script.setAttribute('src', url);
    document.getElementsByTagName('head')[0].appendChild(script); 

    var fun = function(data){
        alert(data);
    };
</script>

二叉树的遍历

前序

function preorderTraversal(root) {
  const res = [];
  const stack = [];
  while (root || stack.length) {
    while (root) {
      res.push(root.val);
      stack.push(root);
      root = root.left;
    }
    root = stack.pop();
    root = root.right;
  }
  return res;
};

中序

function inorderTraversal(root) {
  const res = [];
  const stack = [];
  while (root || stack.length) {
    while (root) {
      stack.push(root)
      root = root.left;
    }
    root = stack.pop();
    res.push(root.val);
    root = root.right;
  }
  return res;
};

后序

function postorderTraversal(root) {
  const res = [];
  const stack = [];
  while (root || stack.length) {
    while (root) {
      stack.push(root);
      res.unshift(root.val);
      root = root.right;
    }
    root = stack.pop();
    root = root.left;
  }
  return res;
};

层序

function levelOrder(root) {
    const ans = [];
    if (!root) {
        return ans;
    }
    let q = [root];
    while (q.length) {
        const newQ = [];
        let layer = [];
        for (const node of q) {
            layer.push(node.val);
            if (node.left) newQ.push(node.left);
            if (node.right) newQ.push(node.right);
        }
        ans.push(layer);
        q = newQ;
    }
    return ans;
};

快速排序

function qSort(arr, l, r) {
  if (l >= r) return;
  let i = l, j = r;
  while (i < j) {
    while (i < j && arr[j] >= arr[l]) j--;
    while (i < j && arr[i] <= arr[l]) i++;
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  [arr[i], arr[l]] = [arr[l], arr[i]];
  qSort(arr, l, i - 1);
  qSort(arr, i + 1, r);
};

排列组合公式

C(n, m)n个元素中取出m个的组合方案。

function C(n, m) {
  if (m > n) return 0;
  let numerator = 1;
  let denominator = 1;
  while (m > 0) {
    numerator *= n--;
    denominator *= m--;
  }
  return numerator / denominator;
}

A(n, m)n个元素中选出m个的排列方案。

function A(n, m) {
  if (m > n) return 0;
  let ans = 1;
  while (m-- > 0) {
    ans *= n--;
  }
  return ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我才是真的李成贤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值