Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

手撕 JavaScript 高频知识点,彻底征服面试官 #97

Open
shanejix opened this issue Apr 12, 2022 · 0 comments
Open

手撕 JavaScript 高频知识点,彻底征服面试官 #97

shanejix opened this issue Apr 12, 2022 · 0 comments
Labels

Comments

@shanejix
Copy link
Owner

同步链接: https://www.shanejix.com/posts/手撕 JavaScript 高频知识点,彻底征服面试官/

  1. 数组扁平化
const arr = [1, [2, [3, [4, 5]]], 6];

// => [1, 2, 3, 4, 5, 6]

/** */

// method 1 : flat(Infinity)

const res = arr.flat(Infinity);

console.log(res);

// method 2: arr.reduce

function flatDeep(arr, d = 1) {
  return d > 0
    ? arr.reduce(
        (acc, val) =>
          acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val),
        []
      )
    : arr.slice();
}

const res2 = flatDeep(arr, Infinity);

console.log(res2);

// method 2 another

function flatten(arr) {
  return arr.reduce((acc, curr) => {
    return acc.concat(Array.isArray(curr) ? flatten(curr) : curr);
  }, []);
}

console.log(flatten(arr));

// method 3 : RegExp

const res3 = JSON.stringify(arr).replace(/\[|\]/g, "").split(",");

console.log(res3);

// method 3 perform

const str = "[" + JSON.stringify(arr).replace(/\[|\]/g, "") + "]";

console.log(JSON.parse(str));

// method 4 : recursivity

const res4 = [];
const recursivity = (arr) => {
  for (let item of arr) {
    if (Array.isArray(item)) {
      recursivity(item);
    } else {
      res4.push(item);
    }
  }
};

recursivity(arr);

console.log(res4);

//

// references

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
  1. 数组去重
const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

// => [1, '1', 17, true, false, 'true', 'a', {}, {}]

/** */

// method 1 : Set

// const res1 = Array.from(new Set(arr));
const res1 = [...new Set(arr)];

console.log("res1:", res1);

// method 2 : for

function unique(arr) {
  let len = arr.length - 1;

  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1); // del
        j--;
        len--;
      }
    }
  }

  return arr;
}

console.log("res2:", unique(arr));

// method 3 : indexOf / includes

const unique2 = (arr) => {
  const res = [];

  for (let i = 0; i < arr.length; i++) {
    // if (res.indexOf(arr[i] === -1)) {
    if (!res.includes(arr[i])) {
      res.push(arr[i]);
    }
  }

  return res;
};

// console.log('res3:', unique2(arr));
console.log(
  "res3:",
  unique2([1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}])
);

// method 4 : filter

const res4 = arr.filter((curr, idx) => {
  return arr.indexOf(curr) === idx;
});

console.log("res4", res4);

// method 5 : Map

const map = new Map();
const res5 = [];

for (let item of arr) {
  if (!map.has(item)) {
    res5.push(item);
    map.set(item, true);
  }
}

console.log("res5:", res5);

/** */

// references

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set
  1. 类数组转化为数组
// Array.form
arr.from(document.querySelectorAll("div"));

// ...
[...document.querySelectorAll("div")];

// slice.call
Array.prototype.slice.call(document.querySelectorAll("div"));

// concat.apply
Array.prototype.concat.apply([], document.querySelectorAll("div"));
  1. Array.prototype.filter()
// Array.prototype.filter()

const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

arr.filter((curr, idx, arr) => {}, null);

Array.prototype.myfilter = function (callback, thisArg) {
  const res = [];

  for (let i = 0; i < this.length; i++) {
    callback && callback.call(thisArg, this[i], i, this) && res.push(this[i]);
  }

  return res;
};
  1. Array.prototype.map()
// Array.prototype.map()

const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

arr.map((curr, idx, arr) => {
  return curr + 1;
}, null);

Array.prototype.mymap = function (callback, thisArg) {
  const res = [];

  for (let i = 0; i < this.length; i++) {
    // callback && (res[i] = callback.call(thisArg, this[i], i, this));
    res[i] = callback && callback.call(thisArg, this[i], i, this);
  }

  return res;
};
  1. Array.prototype.forEach()
// Array.prototype.forEach()

const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

arr.forEach((curr, idx, arr) => {
  // ...
}, null);

Array.prototype.myforEach = function (callback, thisArg) {
  const res = [];

  for (let i = 0; i < this.length; i++) {
    callback && callback.call(thisArg, this[i], i, this);
  }

  return res;
};
  1. Array.prototype.every()
// Array.prototype.every()

const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

arr.every((curr, idx, arr) => {
  // ...
}, null);

Array.prototype.myevery = function (callback, thisArg) {
  for (let i = 0; i < this.length; i++) {
    if (callback && !callback.call(thisArg, this[i], i, this)) {
      return false;
    }
  }

  return true;
};
  1. Array.prototype.some()
// Array.prototype.some()

const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

arr.some((curr, idx, arr) => {
  // ...
}, null);

Array.prototype.mysome = function (callback, thisArg) {
  for (let i = 0; i < this.length; i++) {
    if (callback && callback.call(thisArg, this[i], i, this)) {
      return true;
    }
  }

  return false;
};
  1. Array.prototype.reduce()
// Array.prototype.reduce()

const arr = [1, 1, "1", 17, true, true, false, false, "true", "a", {}, {}];

arr.reduce((acc, curr, idx, arr) => {
  // ...

  return acc;
}, []);

Array.prototype.myreduce = function (callback, initial) {
  let acc;
  let start = 0;

  if (initial) {
    acc = initial;
  } else {
    acc = this[0];
    start = 1;
  }

  for (let i = start; i < this.length; i++) {
    callback && callback(acc, this[i], i, this);
  }

  return acc;
};
  1. Array.prototype.join
Array.prototype.myjoin = function (str = ",") {
  let resStr = "";

  for (let i = 0; i < this.length; i++) {
    let item = this[i];

    resStr = i === 0 ? item : `${resStr}${str}${item}`;
  }

  return resStr;
};
  1. Array.prototype.flat
Array.prototype.myflat = function (deep = Infinity) {
  let arr = this;
  let i = 0;

  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
    i++;
    if (i >= deep) {
      break;
    }
  }

  return arr;
};
  1. Array.prototype.splice
Array.prototype.mysplice = function (start, len, ...values) {
  if (len === 0) {
    return [];
  }

  len = start + len > this.length - 1 ? this.length - start : this.length;

  // todo
};

// 算是 Array接口中最复杂的一个了,比较有挑战性,没做出来,我是彩笔!
  1. Array.prototype.apply
Array.prototype.myapply = function (thisArg, argsArr) {
  if (typeof this !== "function") {
    throw Error("no function");
  }

  if (thisArg === null || thisArg === undefined) {
    thisArg = window;
  } else {
    thisArg = Object(thisArg);
  }

  const func = new Symbol("func");

  thisArg[func] = this;

  const result = thisArg[func](...argsArr);

  delete thisArg[func];

  return result;
};

function foo(...args) {
  return args;
}

foo.myapply(null, [1, 2]);
  1. Array.prototype.call
Array.prototype.mycall = function (thisArg, ...argsArr) {
  if (typeof this !== "function") {
    throw Error("no function");
  }

  if (thisArg === null || thisArg === undefined) {
    thisArg = window;
  } else {
    thisArg = Object(thisArg);
  }

  const func = new Symbol("func");

  thisArg[func] = this;

  const result = thisArg[func](...argsArr);

  delete thisArg[func];

  return result;
};

function foo(...args) {
  return args;
}

foo.myapply(null, [1, 2]);
  1. Array.prototype.bind
Array.prototype.mybind = function (thisArg, ...argsArr) {
  if (typeof this !== "function") {
    throw Error("no function");
  }

  if (thisArg === undefined || thisArg === null) {
    thisArg = window;
  } else {
    thisArg = Object(thisArg);
  }

  let func = this;

  return function (...args) {
    return func.apply(this instanceof func ? this : thisArg, args);
  };
};

function foo(...args) {
  return args;
}

const bar = foo.mybind(null, [1, 2]);

bar(1, 2);
  1. debounce
function debounce(func, wait) {
  let timer = null;

  return function () {
    clearTimeout(timer);

    timer = setTimeout(() => func(), wait);
  };
}

function debounce2(func, wait, immediate) {
  let timer = null;

  return function () {
    clearTimeout(timer);

    if (immediate) {
      let callNow = !timer;

      timer = setTimeout(() => func(), wait);

      if (callNow) {
        func();
      }
    } else {
      timer = setTimeout(() => func(), wait);
    }
  };
}

function foo(...args) {
  console.log(1);
  return args;
}

const bar = debounce(foo, 3000);

const bar1 = debounce2(foo, 3000, true);

for (let i = 0; i < 30000; i++) {
  // bar()
  bar1();
}

// for (let i = 0; i < 30000000; i++) {
//   bar()
// }
  1. throttle
function throttle1(func, wait) {
  let start = +new Date();

  return function () {
    let end = +new Date();

    if (end - start >= wait) {
      func();
      start = +new Date();
    }
  };
}

function throttle2(func, wait) {
  let start = +new Date();
  let timer = null;

  return function () {
    let end = +new Date();
    let remaining = wait - (end - start);

    clearTimeout(timer);

    if (remaining <= 0) {
      func();
      start = +new Date();
    } else {
      timer = setTimeout(() => func(), remaining);
    }
  };
}

function foo() {
  console.log("1");
}

const bar = throttle2(foo, 3000);

for (let i = 0; i < 300000000000; i++) {
  bar();
}
  1. 函数柯里化
function add(...argsArr) {
  const _argsArr = [...argsArr];

  function func(...args) {
    _argsArr.push(...args);

    return func;
  }

  func.console = function () {
    console.log(_argsArr);
  };

  func.sum = function () {
    return _argsArr.reduce((sum, curr) => {
      return (sum += curr);
    }, 0);
  };

  func.toString = function () {
    return _argsArr.reduce((sum, curr) => {
      return (sum += curr);
    }, 0);
  };

  return func;
}

const res1 = add(1)(2)(3)(4);
const res2 = add(1, 2, 4)(2)(3)(4);

console.log(res1.console());
console.log(res2.console());
console.log(res1.sum());
console.log(res2.sum());
console.log(res1.toString());
console.log(res2.toString());
  1. new
function mynew(F, ...args) {
  let obj = {};

  Object.setPrototypeOf(obj, F.prototype);

  const res = F.apply(obj, args);

  const isObject = typeof res === "object" && typeof res !== "null";
  const isFunction = typeof res === "function";

  return isObject || isFunction ? res : obj;
}

function Foo(...args) {
  this.args = args;
}

const res = mynew(Foo, 1, 2, 3);

console.log(res);
  1. instanceof
function myinstanceof(left, right) {
  if (
    (typeof left !== "object" && typeof left !== "function") ||
    typeof left === null
  ) {
    return false;
  }

  let proto = Object.getPrototypeOf(left);

  while (true) {
    if (proto === null) {
      return false;
    }
    if (proto === right.prototype) {
      return true;
    }

    proto = Object.getPrototypeOf(proto);
  }
}

function foo() {}

// const bar = new foo()

// console.log(Object.getPrototypeOf(bar) === foo.prototype)

// const res = myinstanceof(bar, foo)
const res = myinstanceof(foo, Function);

console.log(res);
  1. 寄生组合式继承
function Parent(...args) {
  this.args = args;
  this.getArgs = function () {
    console.log(this.args);
  };
}

Parent.prototype.method = function () {
  console.log("perent method");
};

function Child(...args) {
  Parent.call(this, ...args);
  this.childArgs = args;
}

function _extends(Child, Parent) {
  let proto = Object.create(Parent.prototype);
  Child.prototype = proto;
  Child.prototype.constructor = Child;
}

_extends(Child, Parent);

const child = new Child(1, 2);

console.log(child);
console.log(child.__proto__.__proto__);
console.log(Object.getPrototypeOf(child));

child.method();
  1. Object.is
function is(x, y) {
  // 0 === -0 false
  if (x === y) {
    return x !== 0 || y !== 0 || 1 / x === 1 / y;
  } else {
    // NaN === NaN true
    return x !== x && y !== y;
  }
}

console.log(is(0, -0));
console.log(is(NaN, NaN));
  1. Object.assign
Object.defineProperty(Object, "myassign", {
  value: function (target, ...args) {
    if (target === null) {
      throw Error("not null");
    }

    const to = Object(target);

    for (let source of args) {
      if (typeof source !== null) {
        for (let key in source) {
          if (Object.prototype.hasOwnProperty.call(source, key)) {
            to[key] = source[key];
          }
        }
      }
    }

    return to;
  },
  enumerable: false,
  writable: false,
  configurable: true,
});

const res = Object.myassign({}, { foo: 1, bar: "2" });

console.log(res);
  1. 深、浅拷贝
const shallowClone = (obj) => {
  const newObj = {};

  for (let key of obj) {
    if (Object.hasOwnProperty.call(obj, key)) {
      newObj[key] = obj[key];
    }
  }

  return newObj;
};

function deepClone(obj, has = new WeakMap()) {
  if (obj === null || obj === undefined) {
    return obj;
  }

  if (obj instanceof Date) {
    return new Date(obj);
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  if (obj !== "object") {
    return obj;
  }

  if (has.get(obj)) {
    return has.get(obj);
  }

  let cloneObj = new obj.constructor();
  hash.set(obj, cloneObj);

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // cloneObj[key] = obj[key]
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }

  return cloneObj;
}
  1. Promise
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class Promise {
  constructor(excutor) {
    this.status = PENDING;
    this.value = null;
    this.reason = null;
    this.onFullfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resovle = (value) => {
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        this.onFullfilledCallbacks.forEach((cb) => cb());
      }
    };

    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach((cb) => cb());
      }
    };

    try {
      excutor(resovle, reject);
    } catch (e) {
      // throw e
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;

    onRejected = typeof onRejected === "function" ? onRejected : (r) => r;

    const self = this;

    return new Promise((resolve, reject) => {
      if (self.status === PENDING) {
        self.onFullfilledCallbacks.push(() => {
          try {
            setTimeout(() => {
              const result = onFulfilled(self.value);

              result instanceof Promise
                ? result.then(
                    (res) => resolve(res),
                    (rej) => reject(rej)
                  )
                : resolve(result);
            });
          } catch (error) {
            reject(error);
          }
        });

        self.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            const result = onRejected(self.reason);

            result instanceof Promise
              ? result.then(
                  (res) => resolve(res),
                  (rej) => reject(rej)
                )
              : reject(result);
          });
        });
      }

      if (self.status === FULFILLED) {
        try {
          setTimeout(() => {
            const result = onFulfilled(self.value);

            result instanceof Promise
              ? result.then(resolve, reject)
              : resolve(result);
          });
        } catch (error) {
          reject(error);
        }
      }

      if (self.status == REJECTED) {
        try {
          setTimeout(() => {
            const result = onRejected(self.reason);

            result instanceof Promise
              ? result.then(resolve, reject)
              : reject(result);
          });
        } catch (error) {
          reject(error);
        }
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  static resolve(value) {
    // return new Promise((resolve, reject) => {
    //   // resolve(null)

    // })

    if (value instanceof Promise) {
      return value;
    } else {
      return new Promise((resolve, reject) => {
        resolve(value);
      });
    }
  }

  static reject(reason) {
    return new Promise((resolve, reject) => reject(reason));
  }

  all(promises) {
    return new Promise((resolve, reject) => {
      const result = [];
      let count = 0;

      for (let i = 0; i < promises.length; i++) {
        const promise = Promise.resolve(promises[i]);

        promise
          .then((res) => {
            result[i] = res;
            count++;
            if (count === promises.length) {
              resolve(result);
            }
          })
          .catch((error) => {
            reject(error);
          });
      }
    });
  }

  trace(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach((p) => {
        const promise = Promise.resolve(p);

        promise
          .then((res) => {
            resolve(res);
          })
          .catch((err) => {
            reject(err);
          });
      });
    });
  }

  allSetted(promises) {
    return new Promise((resovle, reject) => {
      try {
        const result = [];
        let count = 0;

        for (let i = 0; i < promises.length; i++) {
          promises[i]
            .then((res) => {
              result[i] = {
                status: "fulfilled",
                value: res,
              };
              count++;
              if (count === promises.length) {
                resovle(result);
              }
            })
            .catch((err) => {
              result[i] = {
                status: "rejected",
                value: err,
              };
              count++;
              if (count === promises.length) {
                resovle(result);
              }
            });
        }
      } catch (error) {
        reject(error);
      }
    });
  }
}

https://www.shanejix.com/posts/Promises%20implementation%20with%20ES6%20class/

  1. 获取页面中所有的 tagName
function func() {
  return [
    ...new Set([...document.querySelectorAll("*")].map((el) => el.tagName)),
  ].length;
}
  1. 数组乱序
const func = (arr) => {
  return arr.sort(() => (Math.random() > 0.5 ? 1 : -1));
};
  1. 对象扁平化
const objTmp = {
  a: { b: { c: 1 } },
  d: 2,
  e: [3, { f: 4, g: [5] }, [6, 7]],
  h: 8,
};

// const res = {
//   "a.b.c": 1,
//   d: 2,
//   "e[0]": 3,
//   "e[1].f": 4,
//   "e[1].g[0]": 5,
//   "e[2][0]": 6,
//   "e[2][1]": 7,
//   h: 8
// };

function fattenObj(obj, res = {}, prevKey = "", isArr = false) {
  for (let [key, value] of obj.entries()) {
    // console.log(key, value)

    if (typeof value === "object" && value !== null) {
      const theKey = isArr ? prevKey + "[" + key + "]" : prevKey + key;
      fattenObj(value, res, theKey);
    }

    if (Array.isArray(value)) {
      const theKey = isArr ? prevKey + "[" + key + "]" : prevKey + key + ".";
      fattenObj(value, res, theKey, true);
    }

    const theKey = isArr ? prevKey + "[" + key + "]" : prevKey + key;
    res[theKey] = value;
  }
}

const res = fattenObj(objTmp, {});

console.log("res", res);

作者:shanejix
出处:https://www.shanejix.com/posts/手撕 JavaScript 高频知识点,彻底征服面试官/
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
声明:转载请注明出处!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant