代码题

101 阅读3分钟

将结构转为树结构

 const linearStructure = [
      { id: 1, name: "总经理", parentId: null },
      { id: 2, name: "财务总监", parentId: 1 },
      { id: 3, name: "技术总监", parentId: 1 },
      { id: 4, name: "工程部副总", parentId: 3 },
      { id: 5, name: "软件开发部经理", parentId: 4 },
      { id: 6, name: "软件工程师", parentId: 5 },
      { id: 7, name: "质量保证部经理", parentId: 4 },
      { id: 8, name: "质量保证工程师", parentId: 7 },
      { id: 9, name: "销售总监", parentId: 3 },
      { id: 10, name: "销售经理", parentId: 9 },
      { id: 11, name: "销售团队", parentId: 10 },
    ];
    
    //方法一 使用forEach结合filter
    linearStructure.forEach((item) => {
      item.children = linearStructure.filter((iten) => iten.parentId === item.id);
    });
    const rusult = linearStructure.filter((item) => !item.parentId);
    console.log(rusult);

   //方法二 使用Map结合forEach
    function formatTree(arr){
      const result = [];
      const map = new Map();
      arr.forEach(item=>map.set(item.id,{...item,children:[]}));

      arr.forEach(item=>{
        if(map.has(item.parentId)){
          map.get(item.parentId).children.push(map.get(item.id))          
        }else{
          result.push(map.get(item.id))
        }
      })
      return result;
    }
    console.log(formatTree(linearStructure));

反转字符串

    const str = "Hello World";
    
    //方法一 转数组通过数组反转方法再转字符串
    const newStr = str.split('').reverse().join('');
    console.log(newStr);
    
    //方法二 转数组然后通过reduce
    const newStr2 = Array.from(str).reduce((acc,cur)=>`${cur}${acc}`,'');
    console.log(newStr2);

实现柯里化函数add

function add(...args1){
      let parms = args1;

      function addFn(...args2){
        parms = parms.concat(args2);
        return addFn;
      }
      addFn.valueOf = ()=>{
        return parms.reduce((acc,cur)=>{
          return acc+cur;
        },0)
      }
      return addFn;

    }
    console.log(add(1,2,3).valueOf()); //6
    console.log(add(4)(5,6)(7,8,9).valueOf()); //39

虚拟列表

完善虚拟列表

<script setup>
import {computed, onMounted, reactive, ref} from "vue";

// 数据定义
const listRef = ref(null);
let scrollTop = ref(0);
let viewHeight = 0;
let itemHeight = 30;
let itemSum = ref(0);
let startIndex = ref(0);

// 后端返回的数据
const data = [];
for (let i = 1; i <= 200; i++) {
  data.push({id: i, content: `列表${i}`});
}
// 计算属性
const handleListResult = computed(() => {
  const endIndex = startIndex.value + itemSum.value;
  endIndex > data.length ? data.length : endIndex;
  const result = data.slice(startIndex.value, endIndex);
  console.log(result);
  console.log(startIndex.value, endIndex);
  return result;
});
// 数据监听
// 生命周期钩子
onMounted(() => {
  viewHeight = listRef.value.offsetHeight;
  itemSum.value = Math.ceil(viewHeight / itemHeight);
});

// 方法处理
const handleListScroll = () => {
  scrollTop.value = listRef.value.scrollTop;
  startIndex.value = Math.floor(scrollTop.value / itemHeight);
};
const throttle = (fn, dalay) => {
  let timer = null;
  return function (...agrgs) {
    if (timer) return;
    timer = setTimeout(() => {
      fn.apply(this, agrgs);
      timer = null;
    }, dalay);
  };
};
const handleThrottleScroll = throttle(handleListScroll, 100);
</script>

<template>
  <div class="list" @scroll="handleThrottleScroll" ref="listRef">
    <div :style="{height: `${itemHeight * data.length}px`,}">
      <ul
          :style="{
        transform: `translateY(${startIndex * itemHeight}px)`,
      }"
      >
        <li class="list_item" v-for="item in handleListResult" :key="item.id">
          {{ item.content }}
        </li>
      </ul>
    </div>
  </div>
</template>

<style scoped lang="less">
.list {
  width: 310px;
  height: 320px;
  border: 1px solid red;
  overflow-y: scroll;

  .list_item {
    height: 30px;
    width: 300px;
    border: 1px solid green;
    margin-left: -10px;
    list-style: none;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>


下拉加载更多

<script setup>

import {computed, ref} from "vue";

const page = ref(1);
const pageSize = 10;
const pageItem = 30;
const dataRef = ref(null);
const data=[];
for (let i= 1; i < 200; i++){
  data.push({id:i,content:'数据'+i})
}

const dataResult = computed(()=>{
  return data.slice(0,page.value*pageSize);
})

const handleScroll = () => {
  const scrollTop = dataRef.value.scrollTop;
  const boxHeight = dataRef.value.offsetHeight;
  console.log(scrollTop,boxHeight)
  if(scrollTop >= pageItem*pageSize*page.value - boxHeight  + 10){
    page.value++;
    console.log('加载更多数据');
  }
}
</script>

<template>
  <div class="bigbox" @scroll="handleScroll" ref="dataRef">
    <div :style="{height: `${dataResult.length*pageItem+22}px`}">
      <div class="data_item" v-for="item in dataResult">{{item.content}}</div>
    </div>
  </div>
</template>

<style scoped>
.bigbox {
  width: 320px;
  height: 320px;
  border: 1px solid red;
  overflow-y: scroll;

  .data_item {
    width: 300px;
    height: 30px;
    border: 1px solid green;
    list-style: none;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>

简易版axios实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
  function myAxios(config) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open(config.method || "GET", config.url);

      // 判断是否有请求头
      if (Reflect.ownKeys(config.headers||{}).length > 0) {
        Object.keys(config.headers).forEach((key) => {
          xhr.setRequestHeader(key, config.headers[key]);
        });
      }
      xhr.onload = () => {
        resolve({
          data: xhr.responseText,
          status: xhr.status,
        });
      };
      xhr.onerror = () => {
        reject("Error");
      };

      xhr.send();
  });
 }

(async () => {
  try {
    const result = await myAxios({
      url: "https://jsonplaceholder.typicode.com/todos/1",
    });
    console.log(result.status);
  } catch (error) {
    console.log("error",error);
  }
})();

  </script>
</body>
</html>

实现一个获取时间的函数 YYYY-MM-DD HH-mm-ss (装饰者模式)

function addZero(str) {
  return str.toString().padStart(2, "0");
}

function getTime(currentTime) {
  const year = currentTime.getFullYear();
  const month = addZero(currentTime.getMonth() + 1);
  const day = addZero(currentTime.getDate());
  const hour = addZero(currentTime.getHours());
  const minute = addZero(currentTime.getMinutes());
  const second = addZero(currentTime.getSeconds());
  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}

console.log(getTime(Date()));

两数之和

// 给定一个数组,给定一个计算结果target,查找出来符合条件的数据索引

function findSum1(arr, target) {
  for (let i = 0; i < arr.length; i++) {
    const findIndex = arr.findIndex((item) => item === target - arr[i]);
    if (findIndex !== -1) {
      return [i, findIndex];
    }
  }
  return [];
}

function findSum2(arr, target) {
  const map = new Map();
  arr.forEach((element) => {
    map.set(arr[element], element);
  });
  for (let i = 0; i < arr.length; i++) {
    const findValue = target - arr[i];
    if (map.has(findValue)) {
      return [i, map.get(findValue)];
    }
  }
  return [];
}

console.log(findSum1([8, 2, 6, 5, 4, 1, 3], 7));
console.log(findSum2([8, 2, 6, 5, 4, 1, 3], 7));

找出出现两次的数字

function findValue(arr) {
  return arr.filter((item, index) => arr.indexOf(item) !== index);
}

function findValue2(arr) {
  const newSet = new Set();
  const result = [];
  for (let item of arr) {
    if (newSet.has(item)) {
      result.push(item);
    } else {
      newSet.add(item);
    }
  }
  return result;
}

console.log(findValue([1, 2, 2, 3, 4, 5, 6, 7, 8]));
console.log(findValue2([1, 2, 2, 3, 4, 5, 6, 7, 8]));

判断字符串是否有效

const map = new Map();
map.set("(", ")");
map.set(")", "(");
map.set("{", "}");
map.set("}", "{");
map.set("[", "]");
map.set("]", "[");

function isValid(str) {
  return str.split("").every((item) => str.includes(map.get(item)));
}

console.log(isValid("[]")); //true
console.log(isValid("()")); //true
console.log(isValid("{[()]}")); //true
console.log(isValid("(")); //false
console.log(isValid("{(]}")); //false

实现debounce函数

function debounce(fn, delay, immediate = false) {
  let time = null;
  return function (...args) {
    if (immediate && !time) {
      fn.apply(this, args);
    }
    if (time) clearTimeout(time);
    time = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

找到第一个不重复出现的字符的下标

function findIndex(str) {
  const map = new Map();
  for (let item of str) {
    if (map.has(item)) {
      map.set(item, map.get(item) + 1);
    } else {
      map.set(item, 1);
    }
  }
  for (let i = 0; i < str.length; i++) {
    if (map.get(str[i]) === 1) {
      return i;
    }
  }
  return -1;
}
console.log(findIndex("abcabcde"));

深拷贝实现

// 深拷贝实现
function deepClone(obj) {
  if (!(obj instanceof Object)) {
    throw new TypeError("请传入复杂数据类型");
  }

  return Object.keys(obj).reduce((acc, cur) => {
    // 如果值是数组
    if (Object.prototype.toString.call(obj[cur]) === "[object Array]") {
      acc[cur] = [...obj[cur]];
    } else if (typeof obj[cur] === "object" && obj[cur] !== null) {
      // 如果值是对象
      acc[cur] = deepClone(obj[cur]);
    } else {
      // 属性值为基本数据类型
      acc[cur] = obj[cur];
    }
    return acc;
  }, {});
}

const obj1 = { a: 1, b: { c: 2 }, d: [99, 98] };
const obj2 = deepClone(obj1);
obj1.b.c = 5;
obj1.d = [90, 91, 92];
console.log(obj2);

flat实现

Array.prototype.myFlag = function (deep) {
  let step = arguments.length === 1 ? deep : 1;
  let result = [];
  for (let i = 0; i < this.length; i++) {
    if (Array.isArray(this[i]) && step > 0) {
      result = result.concat(this[i].myFlag(step - 1));
    } else {
      result.push(this[i]);
    }
  }
  return result;
};

console.log([1, 2, [3, 4, [5]]].myFlag(2));