常见手写函数整理(一)

2022/2/16 function

# 手写typof

function typeOf(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
typeOf([])        // 'array'
typeOf({})        // 'object'
typeOf(new Date)  // 'date'
1
2
3
4
5
6

# 手写instanceof

function instanceOf(l, r) {
  // let proto = l.__proto__;
  let proto = Object.getPrototypeOf(l);
  let prototype = r.prototype
  while (true) {
    if (proto == null) {
      return false
    }
    if (proto == prototype) {
      return true
    }
    proto = Object.getPrototypeOf(proto)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 手写Object.create

if (typeof Object.create !== "function") {
  Object.create = function(proto, propertiesObject) {
    if (typeof proto !== "object" && typeof proto !== "function") {
      throw new TypeError("Object prototype may only be an Object: " + proto);
    } else if (proto === null) {
      throw new Error(
        "This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument."
      );
    }

    if (typeof propertiesObject != "undefined")
      throw new Error(
        "This browser's implementation of Object.create is a shim and doesn't support a second argument."
      );

    function F() {}
    F.prototype = proto;

    return new F();
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 防抖函数debounce

JavaScript 专题之跟着 underscore 学防抖 (opens new window)

事件在被触发 n 秒后,再执行回调;如果在这 n 秒中内再次被触发,则重新计时然后在执行回调

  • 简化版
// 函数防抖的实现
function debounce(fn, wait) {
  let timer = null;

  return function() {
    let context = this,
        args = arguments;

    // 如果此时存在定时器的话,则取消之前的定时器重新记时
    if (timer) {
      clearTimeout(timer);
      timer = null;
    }

    // 设置定时器,使事件间隔指定事件后执行
    timer = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
See More
// underscore.js
function debounce2(func, wait, immediate) {
  var timer, result;
  var debounced = function() {
    var context = this;
    var args = arguments;
    if (timer) clearTimeout(timer);
    if (immediate) {
      var callNow = !timer;
      timer = setTimeout(function() {
        timer = null;
      }, wait);
      if (callNow) result = func.apply(context, args);
    } else {
      timer = setTimeout(function() {
        func.apply(context, args);
      }, wait);
    }
    return result;
  };
  debounced.cancel = function() {
    clearTimeout(timer);
    timer = null;
  };
  return debounced;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 节流函数throttle

JavaScript 专题之跟着 underscore 学节流 (opens new window)

单位时间内有事件被多次触发则,只生效一次

  • 简化版
// 函数节流的实现;
function throttle(fn, delay) {
  let curTime = Date.now();

  return function() {
    let context = this,
        args = arguments,
        nowTime = Date.now();

    // 如果两次时间间隔超过了指定时间,则执行函数。
    if (nowTime - curTime >= delay) {
      curTime = Date.now();
      return fn.apply(context, args);
    }
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
See More
function throttle(func, wait, options) {
  var timeout, context, args, result;
  var previous = 0;
  if (!options) options = {};

  var later = function() {
    previous = options.leading === false ? 0 : new Date().getTime();
    timeout = null;
    func.apply(context, args);
    if (!timeout) context = args = null;
  };

  var throttled = function() {
    var now = new Date().getTime();
    if (!previous && options.leading === false) previous = now;
    var remaining = wait - (now - previous);
    context = this;
    args = arguments;
    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      func.apply(context, args);
      if (!timeout) context = args = null;
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
  };

  throttled.cancel = function() {
    clearTimeout(timeout);
    previous = 0;
    timeout = null;
  };

  return throttled;
}

function throttle(callback, time, ...arr) {
  // 上次执行时间 第一次马上执行
  let last = 0;
  return () => {
    // 当前时间
    let cur = Date.now();
    // 当前时间与上次执行的时间,是否超过间隔时间
    if (cur - last > time) {
      // ...arr为callback的参数
      callback(...arr);
      // 重置上次执行时间为当前时间 方便下次执行
      last = cur;
    }
  };
}
let fn = (a, b) => {
  console.log('回调', a, b);
};
// 重复执行函数
setInterval(throttle(fn, 1000, '参数1', '参数2'), 10);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# 手写new函数

「2021」高频前端面试题汇总之手写代码篇 (opens new window)

  • 首先创建了一个新的空对象
  • 设置原型,将对象的原型设置为函数的 prototype 对象。
  • 让函数的 this 指向这个对象,执行构造函数的代码
  • 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
function new() {
  // 1.将 arguments 对象转为数组
  var args = [].slice.call(arguments);
  var result = null
  // 2.取出构造函数
  var constructor = args.shift();
  // 3.判断参数是否是一个函数
  if (typeof constructor !== "function") {
    console.error("type error");
    return;
  }
  // 4.创建一个空对象,继承构造函数的 prototype 属性
  // var context.__proto__ = constructor.prototype;
  var context = Object.create(constructor.prototype);
  // 5.执行构造函数
  var result = constructor.apply(context, args);
  var isObject = (typeof result === "object") && result != null
  // 6.如果返回结果是对象,就直接返回,则返回 context 对象
  return isObject ? result : context;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 实现call

  • es6写法
Function.prototype._call = function (context) {
  // 判断 context 是否传入,如果未传入则设置为 window
  let context = context || window;
  context.fn = this; // 将调用函数设为对象的方法
  let args = [...arguments].slice(1);
  let result = context.fn(...args);
  delete context.fn;
  return result;
}
1
2
3
4
5
6
7
8
9
See More
  • es5写法
Function.prototype.call2 = function (context) {
    var context = context || window;
    context.fn = this;

    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }

    var result = eval('context.fn(' + args +')');
    delete context.fn
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 实现apply

Function.prototype._apply = function (context) {
  var context = context || window;
  context.fn = this
  let result;
  // 判断是否有第二个参数
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn
  return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
See More
Function.prototype.apply2 = function (context, arr) {
    var context = context || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    } else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }

    delete context.fn
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 实现bind

Function.prototype._bind = function(context) {
  // 保存原函数
  let func = this;
  // 获取参数
  let params = [].slice.call(arguments, 1);

  let Nop = function() {};

  let bound = function() {
    params = params.concat([].slice.call(arguments, 0));

    return func.apply(this instanceof Nop
           ? this : context, params);
  }

  Nop.prototype = func.prototype;
  bound.prototype = new Nop();

  return bound;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 实现浅拷贝shallowCopy

  • Object.assign
  • 扩展运算符(...)
  • 数组方法实现数组浅拷贝
    • Array.prototype.slice
    • Array.prototype.concat
  • 实现浅拷贝shallowCopy
function shallowCopy(obj) {
    if (typeof obj !== 'object') return

    let newObj = obj instanceof Array ? [] : {}
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key]
        }
    }
    return newObj
}
1
2
3
4
5
6
7
8
9
10
11

# 实现深拷贝deepClone

// 深拷贝的实现
function deepCopy(object) {
  if (!object || typeof object !== "object") return;

  let newObject = Array.isArray(object) ? [] : {};

  for (let key in object) {
    if (object.hasOwnProperty(key)) {
      newObject[key] =
        typeof object[key] === "object" ? deepCopy(object[key]) : object[key];
    }
  }

  return newObject;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • deepClone
function deepClone(obj, map = new WeakMap()) {
  if (obj instanceof RegExp) return new RegExp(obj);
  if (obj instanceof Date) return new Date(obj);
  // 判断是否是一个非对象
  if (obj == null || typeof obj != "object") return obj;

  if (map.has(obj)) {
    return map.get(obj);
  }
  let t = {};
  map.set(obj, t);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      t[key] = deepClone(obj[key], map);
    }
  }
  return t;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
See More
const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;

function deepClone(target, map = new WeakMap()) {
    if (map.get(target)) {
        return target;
    }
    // 获取当前值的构造函数:获取它的类型
    let constructor = target.constructor;
    // 检测当前对象target是否与正则、日期格式对象匹配
    if (/^(RegExp|Date)$/i.test(constructor.name)) {
        // 创建一个新的特殊对象(正则类/日期类)的实例
        return new constructor(target);
    }
    if (isObject(target)) {
        map.set(target, true);  // 为循环引用的对象做标记
        const cloneTarget = Array.isArray(target) ? [] : {};
        for (let prop in target) {
            if (target.hasOwnProperty(prop)) {
                cloneTarget[prop] = deepClone(target[prop], map);
            }
        }
        return cloneTarget;
    } else {
        return target;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 数组flat

  • reduce
function flat(arr, depth) {
  if(!Array.isArray(arr) || depth <= 0) {
    return arr;
  }
  return arr.reduce((prev, cur) => {
    if (Array.isArray(cur)) {
      return prev.concat(_flat(cur, depth - 1))
    } else {
      return prev.concat(cur);
    }
  }, []);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
See More
  • es5
function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        } else {
            result.push(arr[i])
        }
    }
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
const eachFlat = (arr = [], depth = 1) => {
  const result = []; // 缓存递归结果
  // 开始递归
  (function flat(arr, depth) {
    // forEach 会自动去除数组空位
    arr.forEach((item) => {
      // 控制递归深度
      if (Array.isArray(item) && depth > 0) {
        // 递归数组
        flat(item, depth - 1)
      } else {
        // 缓存元素
        result.push(item)
      }
    })
  })(arr, depth)
  // 返回递归结果
  return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 使用setTimeout实现setInterval

function mySetInterval(fn, timeout) {
  // 控制器,控制定时器是否继续执行
  var timer = {
    flag: true
  };
  // 设置递归函数,模拟定时器执行
  function interval() {
    if (timer.flag) {
      fn();
      setTimeout(interval, timeout);
    }
  }
  // 启动定时器
  setTimeout(interval, timeout);
  // 返回控制器
  return timer;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 实现数组forEach

  • forEach
Array.prototype._forEach = function(fn, thisArg) {
    if (typeof fn !== 'function') throw "参数必须为函数";
    if(!Array.isArray(this)) throw "只能对数组使用forEach方法";
    let arr = this;
    for(let i=0; i<arr.length; i++) {
        fn.call(thisArg, arr[i], i, arr)
    }
}
1
2
3
4
5
6
7
8
See More
Array.prototype._forEach = function(callback, thisArg) {
    if (this == null) {
        throw new TypeError('this is null or not defined')
    }
    if (typeof callback !== "function") {
        throw new TypeError(callback + ' is not a function')
    }
    const O = Object(this)
    const len = O.length >>> 0

    let k = 0, res = []
    while (k < len) {
        if (k in O) {
          res[k] = callback.call(thisArg, O[k], k, O);
        }
        k++;
    }
    return res
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 实现数组map

  • map
Array.prototype.map = function(fn) {
   if (typeof fn !== "function") {
        throw Error('参数必须是一个函数');
    }
    const res = [];
    for (let i = 0, len = this.length; i < len; i++) {
        res.push(fn(this[i]));
    }
    return res;
}
1
2
3
4
5
6
7
8
9
10
See More
Array.prototype.map = function(callback, thisArg) {
    if (this == null) {
        throw new TypeError('this is null or not defined')
    }
    if (typeof callback !== "function") {
        throw new TypeError(callback + ' is not a function')
    }
    const O = Object(this)  // this 就是当前的数组
    const len = O.length >>> 0  // 后面有解释
    let k = 0, res = []
    while (k < len) {
        if (k in O) {
          res[k] = callback.call(thisArg, O[k], k, O);
        }
        k++;
    }
    return res
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 实现数组filter

  • filter
Array.prototype._filter = function(fn) {
    if (typeof fn !== "function") {
        throw Error('参数必须是一个函数');
    }
    const res = [];
    for (let i = 0, len = this.length; i < len; i++) {
        fn(this[i]) && res.push(this[i]);
    }
    return res;
}
1
2
3
4
5
6
7
8
9
10
See More
if (!Array.prototype.filter){
  Array.prototype.filter = function(func, thisArg) {
    'use strict';
    if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
        throw new TypeError();

    var len = this.length >>> 0,
        res = new Array(len), // preallocate array
        t = this, c = 0, i = -1;
    if (thisArg === undefined){
      while (++i !== len){
        // checks to see if the key was set
        if (i in this){
          if (func(t[i], i, t)){
            res[c++] = t[i];
          }
        }
      }
    }
    else{
      while (++i !== len){
        // checks to see if the key was set
        if (i in this){
          if (func.call(thisArg, t[i], i, t)){
            res[c++] = t[i];
          }
        }
      }
    }

    res.length = c; // shrink down array to proper size
    return res;
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 实现数组reduce

function mReduce(arr, reduceCallback, initialValue) {
  if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== 'function'){
    return [];
  } else {
    let hasInitialValue = initialValue !== undefined;
    let value = hasInitialValue ? initialValue : arr[0];
    // 如果有传递 initialValue,则索引从 1 开始,否则从 0 开始
    for (let i = hasInitialValue ? 0 : 1, len = arr.length; i < len; i++) {
      value = reduceCallback(value, arr[i], i, arr);
    }
    return value;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
See More
Array.prototype.reduce = function(callback, initialValue) {
    if (this == null) {
        throw new TypeError('this is null or not defined')
    }
    if (typeof callback !== "function") {
        throw new TypeError(callback + ' is not a function')
    }
    const O = Object(this)
    const len = O.length >>> 0
    let k = 0, acc

    if (arguments.length > 1) {
        acc = initialValue
    } else {
        // 没传入初始值的时候,取数组中第一个非 empty 的值为初始值
        while (k < len && !(k in O)) {
            k++
        }
        if (k > len) {
            throw new TypeError( 'Reduce of empty array with no initial value' );
        }
        acc = O[k++]
    }
    while (k < len) {
        if (k in O) {
            acc = callback(acc, O[k], k, O)
        }
        k++
    }
    return acc
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 实现Object.assign

36 个 JS 手写题 (opens new window)

Object.assign2 = function(target, ...source) {
    if (target == null) {
        throw new TypeError('Cannot convert undefined or null to object')
    }
    let ret = Object(target)
    source.forEach(function(obj) {
        if (obj != null) {
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    ret[key] = obj[key]
                }
            }
        }
    })
    return ret
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 柯里化curry

  • 逐步接收参数,并缓存供后期计算使用
  • 不立即计算,延后执行
  • 符合计算的条件,将缓存的参数,统一传递给执行方法
  • curry1:判断参数是否满足条件,满足条件执行方法,不满足则缓存参数
function curry(fn) {
  var allArgs = []; // 用来接收参数

  return function next() {
    var args = [].slice.call(arguments);

    // 判断是否执行计算,即最后一个执行函数参数是否为空
    if (args.length > 0) {
      // 收集传入的参数,进行缓存
      allArgs = allArgs.concat(args);
      return next;
    } else {
      // 符合执行条件,执行计算
      return fn.apply(null, allArgs);
    }
  };
}

var add = currying(function() {
  var sum = 0;
  for (var i = 0; i < arguments.length; i++) {
    sum += arguments[i];
  }
  return sum;
});

console.log(add(10, 2, 3)(4)());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • curry2: 判断最后的参数是否与函数需要的参数数量相同,如果相同,则执行计算
function curry(fn) {
    var _args = [];
    return function next() {
      // 将参数收集起来
      [].push.apply(_args, [].slice.call(arguments));
      // 判断是否执行计算
      if (_args.length === fn.length) {
        const args = _args
        _args = []
        return fn.apply(this, args);
      }
      return next;
    }
}
var abc = function(a, b, c) {
  return a + b + c;
};

var curried = curry(abc)
console.log(curried(1)(2)(3))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • curry3: 使用toString调用函数
function curry2(fn) {
    var _args = [];

    function next() {
        var args = [].slice.call(arguments);
        _args = _args.concat(args)
        return next;
    }
    // 字符类型
    next.toString = function() {
        return fn.apply(null, _args);
    }
    // 数值类型
    next.valueOf = function() {
        return fn.apply(null, _args);
    }
    return next;

}
var add = curry2(function() {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
});

alert(add(1, 2, 3)(4))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 偏函数partial

function partial(fn, ...args) {
  return (...arg) => {
    // 收集参数
    return fn(...args, ...arg)
  }
}
// demo
function add(...args) {
  return args.reduce((a, b) => a + b)
}
let partial_add = partial(add, 1, 2);
console.log(partial_add(3, 4, 5));
1
2
3
4
5
6
7
8
9
10
11
12

# 实现字符串的repeat方法

function repeat(s, n) {
  return (new Array(n + 1)).join(s);
}

function repeat(s, n) {
  return (n > 0) ? s.concat(repeat(s, --n)) : "";
}
1
2
3
4
5
6
7

# compose and pipe

  • compose
function compose(fns){
  return function(arg){
    return fns.reduceRight((acc, fn) => fn(acc), arg);
  }
}
1
2
3
4
5
  • pipe
function pipe(fns){
  return function(...args){
    return fns.reduce((acc, fn) => {
      return fn(acc)
    })
  }
}
1
2
3
4
5
6
7

# formateTime

module.exports = {
  formatDateTime(time, fmt) {
    var date = new Date(time)
    var o = {
      'Y+': date.getFullYear(), // 年
      'M+': date.getMonth() + 1, // 月份
      'D+': date.getDate(), // 日
      'h+': date.getHours(), // 小时
      'm+': date.getMinutes(), // 分
      's+': date.getSeconds(), // 秒
      'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
      S: date.getMilliseconds(), // 毫秒
    }
    for (var k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) {
        fmt = fmt.replace(
          RegExp.$1,
          o[k] < 10 ? '0' + o[k] : o[k],
        )
      }
    }
    return fmt
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 实现一个 JSON.stringify

  • 简单版:支持 obect/array/string/number
function jsonStringify(data) {
  let dataType = typeof data;
  if (dataType !== 'object') { // 判断类型是否为普通类型
    return String(data);
  } else if (dataType === 'object') {
    if (Array.isArray(data)) { // 判断是否是数组
      let result = [];
      data.forEach((item, index) => {
        result[index] = jsonStringify(item);
      });
      result = "[" + result + "]";
      return result.replace(/'/g, '"');
    } else { // 判断是否是对象
      let result = [];
      Object.keys(data).forEach((item, index) => {
        result.push('"' + item + '"' + ":" + jsonStringify(data[item]));
      });
      return ("{" + result + "}").replace(/'/g, '"');
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function jsonStringify(data) {
    let dataType = typeof data;

    if (dataType !== 'object') {
        let result = data;
        //data 可能是 string/number/null/undefined/boolean
        if (Number.isNaN(data) || data === Infinity) {
            //NaN 和 Infinity 序列化返回 "null"
            result = "null";
        } else if (dataType === 'function' || dataType === 'undefined' || dataType === 'symbol') {
            //function 、undefined 、symbol 序列化返回 undefined
            return undefined;
        } else if (dataType === 'string') {
            result = '"' + data + '"';
        }
        //boolean 返回 String()
        return String(result);
    } else if (dataType === 'object') {
        if (data === null) {
            return "null"
        } else if (data.toJSON && typeof data.toJSON === 'function') {
            return jsonStringify(data.toJSON());
        } else if (data instanceof Array) {
            let result = [];
            //如果是数组
            //toJSON 方法可以存在于原型链中
            data.forEach((item, index) => {
                if (typeof item === 'undefined' || typeof item === 'function' || typeof item === 'symbol') {
                    result[index] = "null";
                } else {
                    result[index] = jsonStringify(item);
                }
            });
            result = "[" + result + "]";
            return result.replace(/'/g, '"');

        } else {
            //普通对象
            /**
             * 循环引用抛错(暂未检测,循环引用时,堆栈溢出)
             * symbol key 忽略
             * undefined、函数、symbol 为属性值,被忽略
             */
            let result = [];
            Object.keys(data).forEach((item, index) => {
                if (typeof item !== 'symbol') {
                    //key 如果是symbol对象,忽略
                    if (data[item] !== undefined && typeof data[item] !== 'function'
                        && typeof data[item] !== 'symbol') {
                        //键值如果是 undefined、函数、symbol 为属性值,忽略
                        result.push('"' + item + '"' + ":" + jsonStringify(data[item]));
                    }
                }
            });
            return ("{" + result + "}").replace(/'/g, '"');
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 实现一个 JSON.parse

// new Function
var jsonStr = '{ "age": 20, "name": "jack" }';
var json = new Function("return " + jsonStr)();
console.log(json);

// eval
var json = '{"a":"1", "b":2}';
var obj = eval("(" + json + ")");  // obj 就是 json 反序列化之后得到的对象
1
2
3
4
5
6
7
8

# AOP

https://juejin.cn/post/7072545785769885726#heading-84

Function.prototype.before=function(fn){
  return (...arg)=>{
    fn.call(this,...arg)
    this(...arg)
  }
}
Function.prototype.after=function(fn){
  return (...arg)=>{
    const result =this(...arg)
    fn.call(this,...arg)
    return result
  }
}

// use
let func = () => console.log('func');
func = func.before(() => {
  console.log('===before===');
}).after(() => {
  console.log('===after===');
});

func();
// ===before===
// func
// ===after===
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26