实现filter办法

Array.prototype.myFilter=function(callback, context=window){  let len = this.length      newArr = [],      i=0  for(; i < len; i++){    if(callback.apply(context, [this[i], i , this])){      newArr.push(this[i]);    }  }  return newArr;}

实现一下hash路由

根底的html代码:

<html>  <style>    html, body {      margin: 0;      height: 100%;    }    ul {      list-style: none;      margin: 0;      padding: 0;      display: flex;      justify-content: center;    }    .box {      width: 100%;      height: 100%;      background-color: red;    }  </style>  <body>  <ul>    <li>      <a href="#red">红色</a>    </li>    <li>      <a href="#green">绿色</a>    </li>    <li>      <a href="#purple">紫色</a>    </li>  </ul>  </body></html>

简略实现:

<script>  const box = document.getElementsByClassName('box')[0];  const hash = location.hash  window.onhashchange = function (e) {    const color = hash.slice(1)    box.style.background = color  }</script>

封装成一个class:

<script>  const box = document.getElementsByClassName('box')[0];  const hash = location.hash  class HashRouter {    constructor (hashStr, cb) {      this.hashStr = hashStr      this.cb = cb      this.watchHash()      this.watch = this.watchHash.bind(this)      window.addEventListener('hashchange', this.watch)    }    watchHash () {      let hash = window.location.hash.slice(1)      this.hashStr = hash      this.cb(hash)    }  }  new HashRouter('red', (color) => {    box.style.background = color  })</script>

二叉树档次遍历

// 二叉树档次遍历class Node {  constructor(element, parent) {    this.parent = parent // 父节点     this.element = element // 以后存储内容    this.left = null // 左子树    this.right = null // 右子树  }}class BST {  constructor(compare) {    this.root = null // 树根    this.size = 0 // 树中的节点个数    this.compare = compare || this.compare  }  compare(a,b) {    return a - b  }  add(element) {    if(this.root === null) {      this.root = new Node(element, null)      this.size++      return    }    // 获取根节点 用以后增加的进行判断 放右边还是放左边    let currentNode = this.root     let compare    let parent = null     while (currentNode) {      compare = this.compare(element, currentNode.element)      parent = currentNode // 先将父亲保存起来      // currentNode要不停的变动      if(compare > 0) {        currentNode = currentNode.right      } else if(compare < 0) {        currentNode = currentNode.left      } else {        currentNode.element = element // 相等时 先笼罩后续解决      }    }    let newNode = new Node(element, parent)    if(compare > 0) {      parent.right = newNode    } else if(compare < 0) {      parent.left = newNode    }    this.size++  }  // 档次遍历 队列  levelOrderTraversal(visitor) {    if(this.root == null) {      return    }    let stack = [this.root]    let index = 0 // 指针 指向0    let currentNode     while (currentNode = stack[index++]) {      // 反转二叉树      let tmp = currentNode.left      currentNode.left = currentNode.right      currentNode.right = tmp      visitor.visit(currentNode.element)      if(currentNode.left) {        stack.push(currentNode.left)      }      if(currentNode.right) {        stack.push(currentNode.right)      }    }  }}
// 测试var bst = new BST((a,b)=>a.age-b.age) // 模仿sort办法// ![](http://img-repo.poetries.top/images/20210522203619.png)// ![](http://img-repo.poetries.top/images/20210522211809.png)bst.add({age: 10})bst.add({age: 8})bst.add({age:19})bst.add({age:6})bst.add({age: 15})bst.add({age: 22})bst.add({age: 20})// 应用访问者模式class Visitor {  constructor() {    this.visit = function (elem) {      elem.age = elem.age*2    }  }}// ![](http://img-repo.poetries.top/images/20210523095515.png)console.log(bst.levelOrderTraversal(new Visitor()))

二分查找

function search(arr, target, start, end) {  let targetIndex = -1;  let mid = Math.floor((start + end) / 2);  if (arr[mid] === target) {    targetIndex = mid;    return targetIndex;  }  if (start >= end) {    return targetIndex;  }  if (arr[mid] < target) {    return search(arr, target, mid + 1, end);  } else {    return search(arr, target, start, mid - 1);  }}// const dataArr = [1, 2, 3, 4, 5, 6, 7, 8, 9];// const position = search(dataArr, 6, 0, dataArr.length - 1);// if (position !== -1) {//   console.log(`指标元素在数组中的地位:${position}`);// } else {//   console.log("指标元素不在数组中");// }

实现一个padStart()或padEnd()的polyfil

String.prototype.padStartString.prototype.padEndES8中新增的办法,容许将空字符串或其余字符串增加到原始字符串的结尾或结尾。咱们先看下应用语法:

String.padStart(targetLength,[padString])

用法:

'x'.padStart(4, 'ab') // 'abax''x'.padEnd(5, 'ab') // 'xabab'// 1. 若是输出的指标长度小于字符串本来的长度则返回字符串自身'xxx'.padStart(2, 's') // 'xxx'// 2. 第二个参数的默认值为 " ",长度是为1的// 3. 而此参数可能是个不确定长度的字符串,若是要填充的内容达到了指标长度,则将不要的局部截取'xxx'.padStart(5, 'sss') // ssxxx// 4. 可用来解决日期、金额格式化问题'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

polyfill实现:

String.prototype.myPadStart = function (targetLen, padString = " ") {  if (!targetLen) {    throw new Error('请输出须要填充到的长度');  }  let originStr = String(this); // 获取到调用的字符串, 因为this本来是String{},所以须要用String转为字符串  let originLen = originStr.length; // 调用的字符串本来的长度  if (originLen >= targetLen) return originStr; // 若是 本来 > 指标 则返回本来字符串  let diffNum = targetLen - originLen; // 10 - 6 // 差值  for (let i = 0; i < diffNum; i++) { // 要增加几个成员    for (let j = 0; j < padString.length; j++) { // 输出的padString的长度可能不为1      if (originStr.length === targetLen) break; // 判断每一次增加之后是否到了指标长度      originStr = `${padString[j]}${originStr}`;    }    if (originStr.length === targetLen) break;  }  return originStr;}console.log('xxx'.myPadStart(16))console.log('xxx'.padStart(16))

还是比较简单的,而padEnd的实现和它一样,只须要把第二层for循环里的${padString[j]}${orignStr}换下地位就能够了。

转化为驼峰命名

var s1 = "get-element-by-id"// 转化为 getElementByIdvar f = function(s) {    return s.replace(/-\w/g, function(x) {        return x.slice(1).toUpperCase();    })}

参考 前端进阶面试题具体解答

实现一个队列

基于链表构造实现队列
const LinkedList = require('./实现一个链表构造')// 用链表默认应用数组来模仿队列,性能更佳class Queue {  constructor() {    this.ll = new LinkedList()  }  // 向队列中增加  offer(elem) {    this.ll.add(elem)  }  // 查看第一个  peek() {    return this.ll.get(0)  }  // 队列只能从头部删除  remove() {    return this.ll.remove(0)  }}var queue = new Queue()queue.offer(1)queue.offer(2)queue.offer(3)var removeVal = queue.remove(3)console.log(queue.ll,'queue.ll')console.log(removeVal,'queue.remove')console.log(queue.peek(),'queue.peek')

字符串最长的不反复子串

题目形容

给定一个字符串 s ,请你找出其中不含有反复字符的 最长子串 的长度。示例 1:输出: s = "abcabcbb"输入: 3解释: 因为无反复字符的最长子串是 "abc",所以其长度为 3。示例 2:输出: s = "bbbbb"输入: 1解释: 因为无反复字符的最长子串是 "b",所以其长度为 1。示例 3:输出: s = "pwwkew"输入: 3解释: 因为无反复字符的最长子串是 "wke",所以其长度为 3。     请留神,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。示例 4:输出: s = ""输入: 0

答案

const lengthOfLongestSubstring = function (s) {  if (s.length === 0) {    return 0;  }  let left = 0;  let right = 1;  let max = 0;  while (right <= s.length) {    let lr = s.slice(left, right);    const index = lr.indexOf(s[right]);    if (index > -1) {      left = index + left + 1;    } else {      lr = s.slice(left, right + 1);      max = Math.max(max, lr.length);    }    right++;  }  return max;};

手写深度比拟isEqual

思路:深度比拟两个对象,就是要深度比拟对象的每一个元素。=> 递归
  • 递归退出条件:

    • 被比拟的是两个值类型变量,间接用“===”判断
    • 被比拟的两个变量之一为null,直接判断另一个元素是否也为null
  • 提前结束递推:

    • 两个变量keys数量不同
    • 传入的两个参数是同一个变量
  • 递推工作:深度比拟每一个key
function isEqual(obj1, obj2){    //其中一个为值类型或null    if(!isObject(obj1) || !isObject(obj2)){        return obj1 === obj2;    }    //判断是否两个参数是同一个变量    if(obj1 === obj2){        return true;    }    //判断keys数是否相等    const obj1Keys = Object.keys(obj1);    const obj2Keys = Object.keys(obj2);    if(obj1Keys.length !== obj2Keys.length){        return false;    }    //深度比拟每一个key    for(let key in obj1){        if(!isEqual(obj1[key], obj2[key])){            return false;        }    }    return true;}

查找字符串中呈现最多的字符和个数

例: abbcccddddd -> 字符最多的是d,呈现了5次
let str = "abcabcabcbbccccc";let num = 0;let char = ''; // 使其依照肯定的秩序排列str = str.split('').sort().join('');// "aaabbbbbcccccccc"// 定义正则表达式let re = /(\w)\1+/g;str.replace(re,($0,$1) => {    if(num < $0.length){        num = $0.length;        char = $1;            }});console.log(`字符最多的是${char},呈现了${num}次`);

判断是否是电话号码

function isPhone(tel) {    var regx = /^1[34578]\d{9}$/;    return regx.test(tel);}

实现一个add办法实现两个大数相加

// 题目let a = "9007199254740991";let b = "1234567899999999999";function add(a ,b){   //...}

实现代码如下:

function add(a ,b){   //取两个数字的最大长度   let maxLength = Math.max(a.length, b.length);   //用0去补齐长度   a = a.padStart(maxLength , 0);//"0009007199254740991"   b = b.padStart(maxLength , 0);//"1234567899999999999"   //定义加法过程中须要用到的变量   let t = 0;   let f = 0;   //"进位"   let sum = "";   for(let i=maxLength-1 ; i>=0 ; i--){      t = parseInt(a[i]) + parseInt(b[i]) + f;      f = Math.floor(t/10);      sum = t%10 + sum;   }   if(f!==0){      sum = '' + f + sum;   }   return sum;}

实现一个 sleep 函数,比方 sleep(1000) 意味着期待1000毫秒

// 应用 promise来实现 sleepconst sleep = (time) => {  return new Promise(resolve => setTimeout(resolve, time))}sleep(1000).then(() => {  // 这里写你的骚操作})

实现 getValue/setValue 函数来获取path对应的值

// 示例var object = { a: [{ b: { c: 3 } }] }; // path: 'a[0].b.c'var array = [{ a: { b: [1] } }]; // path: '[0].a.b[0]'function getValue(target, valuePath, defaultValue) {}console.log(getValue(object, "a[0].b.c", 0)); // 输入3console.log(getValue(array, "[0].a.b[0]", 12)); // 输入 1console.log(getValue(array, "[0].a.b[0].c", 12)); // 输入 12

实现

/** * 测试属性是否匹配 */export function testPropTypes(value, type, dev) {  const sEnums = ['number', 'string', 'boolean', 'undefined', 'function']; // NaN  const oEnums = ['Null', 'Object', 'Array', 'Date', 'RegExp', 'Error'];  const nEnums = [    '[object Number]',    '[object String]',    '[object Boolean]',    '[object Undefined]',    '[object Function]',    '[object Null]',    '[object Object]',    '[object Array]',    '[object Date]',    '[object RegExp]',    '[object Error]',  ];  const reg = new RegExp('\\[object (.*?)\\]');  // 齐全匹配模式,type应该传递相似格局[object Window] [object HTMLDocument] ...  if (reg.test(type)) {    // 排除nEnums的12种    if (~nEnums.indexOf(type)) {      if (dev === true) {        console.warn(value, 'The parameter type belongs to one of 12 types:number string boolean undefined Null Object Array Date RegExp function Error NaN');      }    }    if (Object.prototype.toString.call(value) === type) {      return true;    }    return false;  }}
const syncVarIterator = {  getter: function (obj, key, defaultValue) {    // 后果变量    const defaultResult = defaultValue === undefined ? undefined : defaultValue;    if (testPropTypes(obj, 'Object') === false && testPropTypes(obj, 'Array') === false) {      return defaultResult;    }    // 后果变量,临时指向obj持有的援用,后续将可能被一直的批改    let result = obj;    // 失去晓得值    try {      // 解析属性档次序列      const keyArr = key.split('.');      // 迭代obj对象属性      for (let i = 0; i < keyArr.length; i++) {        // 如果第 i 层属性存在对应的值则迭代该属性值        if (result[keyArr[i]] !== undefined) {          result = result[keyArr[i]];          // 如果不存在则返回未定义        } else {          return defaultResult;        }      }    } catch (e) {      return defaultResult;    }    // 返回获取的后果    return result;  },  setter: function (obj, key, val) {    // 如果不存在obj则返回未定义    if (testPropTypes(obj, 'Object') === false) {      return false;    }    // 后果变量,临时指向obj持有的援用,后续将可能被一直的批改    let result = obj;    try {      // 解析属性档次序列      const keyArr = key.split('.');      let i = 0;      // 迭代obj对象属性      for (; i < keyArr.length - 1; i++) {        // 如果第 i 层属性对应的值不存在,则定义为对象        if (result[keyArr[i]] === undefined) {          result[keyArr[i]] = {};        }        // 如果第 i 层属性对应的值不是对象(Object)的一个实例,则抛出谬误        if (!(result[keyArr[i]] instanceof Object)) {          throw new Error('obj.' + keyArr.splice(0, i + 1).join('.') + 'is not Object');        }        // 迭代该层属性值        result = result[keyArr[i]];      }      // 设置属性值      result[keyArr[i]] = val;      return true;    } catch (e) {      return false;    }  },};

应用promise来实现

创立 enhancedObject 函数

const enhancedObject = (target) =>  new Proxy(target, {    get(target, property) {      if (property in target) {        return target[property];      } else {        return searchFor(property, target); //理论应用时要对value值进行复位      }    },  });let value = null;function searchFor(property, target) {  for (const key of Object.keys(target)) {    if (typeof target[key] === "object") {      searchFor(property, target[key]);    } else if (typeof target[property] !== "undefined") {      value = target[property];      break;    }  }  return value;}

应用 enhancedObject 函数

const data = enhancedObject({  user: {    name: "test",    settings: {      theme: "dark",    },  },});console.log(data.user.settings.theme); // darkconsole.log(data.theme); // dark

以上代码运行后,控制台会输入以下代码:

darkdark
通过观察以上的输入后果可知,应用 enhancedObject 函数解决过的对象,咱们就能够不便地拜访一般对象外部的深层属性。

实现一个拖拽

<style>  html, body {    margin: 0;    height: 100%;  }  #box {    width: 100px;    height: 100px;    background-color: red;    position: absolute;    top: 100px;    left: 100px;  }</style>
<div id="box"></div>
window.onload = function () {  var box = document.getElementById('box');  box.onmousedown = function (ev) {    var oEvent = ev || window.event; // 兼容火狐,火狐下没有window.event    var distanceX = oEvent.clientX - box.offsetLeft; // 鼠标到可视区右边的间隔 - box到页面右边的间隔    var distanceY = oEvent.clientY - box.offsetTop;    document.onmousemove = function (ev) {      var oEvent = ev || window.event;      var left = oEvent.clientX - distanceX;      var top = oEvent.clientY - distanceY;      if (left <= 0) {        left = 0;      } else if (left >= document.documentElement.clientWidth - box.offsetWidth) {        left = document.documentElement.clientWidth - box.offsetWidth;      }      if (top <= 0) {        top = 0;      } else if (top >= document.documentElement.clientHeight - box.offsetHeight) {        top = document.documentElement.clientHeight - box.offsetHeight;      }      box.style.left = left + 'px';      box.style.top = top + 'px';    }    box.onmouseup = function () {      document.onmousemove = null;      box.onmouseup = null;    }  }}

版本号排序的办法

题目形容:有一组版本号如下 ['0.1.1', '2.3.3', '0.302.1', '4.2', '4.3.5', '4.3.4.5']。当初须要对其进行排序,排序的后果为 ['4.3.5','4.3.4.5','2.3.3','0.302.1','0.1.1']

arr.sort((a, b) => {  let i = 0;  const arr1 = a.split(".");  const arr2 = b.split(".");  while (true) {    const s1 = arr1[i];    const s2 = arr2[i];    i++;    if (s1 === undefined || s2 === undefined) {      return arr2.length - arr1.length;    }    if (s1 === s2) continue;    return s2 - s1;  }});console.log(arr);

实现千位分隔符

// 保留三位小数parseToMoney(1234.56); // return '1,234.56'parseToMoney(123456789); // return '123,456,789'parseToMoney(1087654.321); // return '1,087,654.321'
function parseToMoney(num) {  num = parseFloat(num.toFixed(3));  let [integer, decimal] = String.prototype.split.call(num, '.');  integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,');  return integer + '.' + (decimal ? decimal : '');}

树形构造转成列表(解决菜单)

[    {        id: 1,        text: '节点1',        parentId: 0,        children: [            {                id:2,                text: '节点1_1',                parentId:1            }        ]    }]转成[    {        id: 1,        text: '节点1',        parentId: 0 //这里用0示意为顶级节点    },    {        id: 2,        text: '节点1_1',        parentId: 1 //通过这个字段来确定子父级    }    ...]

实现代码如下:

function treeToList(data) {  let res = [];  const dfs = (tree) => {    tree.forEach((item) => {      if (item.children) {        dfs(item.children);        delete item.children;      }      res.push(item);    });  };  dfs(data);  return res;}

请实现一个 add 函数,满足以下性能

add(1);             // 1add(1)(2);      // 3add(1)(2)(3);// 6add(1)(2, 3); // 6add(1, 2)(3); // 6add(1, 2, 3); // 6
function add(...args) {  // 在外部申明一个函数,利用闭包的个性保留并收集所有的参数值  let fn = function(...newArgs) {   return add.apply(null, args.concat(newArgs))  }  // 利用toString隐式转换的个性,当最初执行时隐式转换,并计算最终的值返回  fn.toString = function() {    return args.reduce((total,curr)=> total + curr)  }  return fn}

考点:

  • 应用闭包, 同时要对JavaScript 的作用域链(原型链)有深刻的了解
  • 重写函数的 toSting()办法
// 测试,调用toString办法触发求值add(1).toString();             // 1add(1)(2).toString();      // 3add(1)(2)(3).toString();// 6add(1)(2, 3).toString(); // 6add(1, 2)(3).toString(); // 6add(1, 2, 3).toString(); // 6

字符串查找

请应用最根本的遍从来实现判断字符串 a 是否被蕴含在字符串 b 中,并返回第一次呈现的地位(找不到返回 -1)。
a='34';b='1234567'; // 返回 2a='35';b='1234567'; // 返回 -1a='355';b='12354355'; // 返回 5isContain(a,b);
function isContain(a, b) {  for (let i in b) {    if (a[0] === b[i]) {      let tmp = true;      for (let j in a) {        if (a[j] !== b[~~i + ~~j]) {          tmp = false;        }      }      if (tmp) {        return i;      }    }  }  return -1;}