前端手写题之 树 场景题 js
本人github链接 求follow
前端手写题集锦 use js 记录大厂面试常考手写题,github仓库地址:https://github.com/Sunny-117/Front-end-handwritten-question。伴随秋招陆续更新,求star

前端手写题系列文章: 前端手写题之正则表达式 前端手写题之 树 场景题 js 前端手写题之JavaScript 原生方法重写
鉴于现在的手写题还有笔试题都常考树形结构,本人面试笔试也遇到很多,所以总结了以下几个题,几乎覆盖所有笔面试场景,希望对uu们有用
如果认为题解有问题或者不是最优解,欢迎提issue
DOM2JSON
{
tag: 'DIV',
children: [
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] }
]
},
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] },
{ tag: 'A', children: [] }
]
}
]
}
function dom2Json(domtree) {
let obj = {};
obj.name = domtree.tagName;
obj.children = [];
domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child)));
return obj;
}
将虚拟 Dom 转化为真实 Dom
{
tag: 'DIV',
attrs:{
id:'app'
},
children: [
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] }
]
},
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] },
{ tag: 'A', children: [] }
]
}
]
}
把上诉虚拟Dom转化成下方真实Dom
<div id="app">
<span>
<a></a>
</span>
<span>
<a></a>
<a></a>
</span>
</div>
// 真正的渲染函数
function _render(vnode) {
// 如果是数字类型转化为字符串
if (typeof vnode === "number") {
vnode = String(vnode);
}
// 字符串类型直接就是文本节点
if (typeof vnode === "string") {
return document.createTextNode(vnode);
}
// 普通DOM
const dom = document.createElement(vnode.tag);
if (vnode.attrs) {
// 遍历属性
Object.keys(vnode.attrs).forEach((key) => {
const value = vnode.attrs[key];
dom.setAttribute(key, value);
});
}
// 子数组进行递归操作
vnode.children.forEach((child) => dom.appendChild(_render(child)));
return dom;
}
计算目录树的深度
const tree = {
name: 'root',
children: [
{ name: '叶子1-1' },
{ name: '叶子1-2' },
{
name: '叶子2-1',
children: [{
name: '叶子3-1',
children: [{
name: '叶子4-1',
children: [{}]
}]
}]
}
]
}
function getLevel(tree) {
if (tree == null) return 0;
const queue = [tree]
let dep = 0;
while (queue.length) {
dep++;
const size = queue.length
for (let i = 0; i < size; i++) {
const node = queue.shift()
if (node.children) {
for (const child of node.children) {
queue.push(child)
}
}
}
}
return dep
}
console.log(getLevel(tree));
树形结构获取路径名
const treeData = [
{
name: "root",
children: [
{ name: "src", children: [{ name: "index.html" }] },
{ name: "public", children: [] },
],
},
];
const RecursiveTree = (data) => {
const res = []
const dfs = (data) => {
data.forEach(ele => {
res.push(ele.name)
ele.children && dfs(ele.children)
});
}
dfs(data)
return res;
}
console.log(RecursiveTree(treeData));
树形结构转成列表
const data = [
{
id: 1,
text: '节点1',
parentId: 0,
children: [
{
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;
}
//直接放需要的,我写的
function treeToList(data) {
const res = []
function dfs(data) {
const obj = {}
data.forEach(ele => {
obj.id = ele.id
obj.text = ele.text
obj.parentId = ele.parentId
ele.children && dfs(ele.children)
});
res.push(obj)
}
dfs(data)
return res;
}
console.log(treeToList(data));
列表转成树形结构
const rootList = [
{ id: 1, parent: null, text: "菜单1" },
{ id: 11, parent: 1, text: "菜单1-1" },
{ id: 12, parent: 1, text: "菜单1-2" },
{ id: 2, parent: null, text: "菜单2" },
{ id: 21, parent: 2, text: "菜单2-1" },
];
function getTreeList(rootList, id, list) {
for (const item of rootList) {
if (item.parent === id) {
list.push(item);
}
}
for (const i of list) {
i.children = [];
getTreeList(rootList, i.id, i.children);
if (i.children.length === 0) {
delete i.children;
}
}
return list;
}
const res = getTreeList(rootList, null, []);
console.log("res", res);
对象树遍历
const tree = {
name: 'root',
children: [
{
name: 'c1',
children: [
{
name: 'c11',
children: []
},
{
name: 'c12',
children: []
}
]
},
{
name: 'c2',
children: [
{
name: 'c21',
children: []
},
{
name: 'c22',
children: []
}
]
}
]
}
// 深度优先的方式遍历 打印 name
// ['root', 'c1','c11', 'c12', 'c2', 'c21', 'c22']
// 我写的
function solve(root) {
const res = []
function dfs(root) {
for (const key in root) {
if (key === 'name') {
res.push(root[key])
} else if (key === 'children') {
root[key].forEach(ele => {
dfs(ele)
});
}
}
}
dfs(root)
return res;
}
console.log(solve(tree));
获取树对象属性
var tree = {
name: '中国',
children: [
{
name: '北京',
children: [
{
name: '朝阳群众'
},
{
name: '海淀区'
},
{
name: '昌平区'
}
]
},
{
name: '浙江省',
children: [
{
name: '杭州市',
code: '0571',
},
{
name: '嘉兴市'
},
{
name: '绍兴市'
},
{
name: '宁波市'
}
]
}
]
};
function fn(tree, name) {
const obj = {}
function dfs(tree) {
for (const key in tree) {
if (tree.name === name) {
obj[key] = tree[key]
} else {
tree.children && tree.children.forEach(ele => {
dfs(ele)
});
}
}
}
dfs(tree)
return obj
}
function fn(tree, name) {
//bfs
let Queue = [[tree.name, tree.children]];
while (Queue.length > 0) {
//出队当前节点
let cur = Queue.shift();
if (cur[0] === name) return { name: name, code: cur[1] }
//将children入队
if (cur.length === 1) continue;
for (let node of cur[1]) {
let obj = [node.name];
if (node.hasOwnProperty("children")) obj.push(node.children);
if (node.hasOwnProperty("code")) obj.push(node.code);
Queue.push(obj);
}
}
return -1;
}
var node = fn(tree, '杭州市');
console.log(node); // { name: '杭州市', code: 0571 }
查找json中的children路径 现有如下json(简化为对象),已知每个节点id唯一,编写findNode(id),返回路径,如findNode(5 输出 1->4->5
json = {
id: 1,
children: [
{ id: 2, children: [{ id: 3, children: [] }] },
{
id: 4,
children: [
{ id: 5, children: [] },
{ id: 6, children: [] },
],
},
{ id: 7, children: [] },
],
};
let result = []
// 独立完成
function findNode(obj) {
const res = []
function dfs(obj, currPath, target) {
if (!obj) return;
if (obj.id === target) {
currPath += obj.id
res.push(currPath)
return
}
currPath += obj.id + '->'
obj.children && obj.children.forEach(ele => {
dfs(ele, currPath, target)
});
}
dfs(obj, '', 5)
return res;
}
console.log(findNode(json));
对象字符串转化成树形结构
let strarr = {
'a-b-c-d':1,
'a-b-c-e':2,
'a-b-f':3,
'a-j':4
}
let obj = {
a:{
b:{
c:{
d:1,
e:2
},
f:3
},
j:4
}
}
function parse(obj) {
let ans = {}
for (let att in obj) {
let temp = ans;
for (let i = 0, len = att.length; i < len; i += 2) {
let cur = att[i];
if (i == len - 1) {
temp[cur] = obj[att];
} else {
if (!temp[cur]) {
temp[cur] = {};
}
temp = temp[cur];
}
}
}
return ans;
}
判断有无符合路径和 -> 打印所有路径
const data3 = [
{
id: 1,
name: '前端',
children: [
{
id: 2,
name: 'html',
children: [
{ id: 5, name: 'vue', children: [] },
{ id: 6, name: 're', children: [] },
]
},
{
id: 3,
name: 'html',
children: [
{ id: 7, name: 'vue', children: [] },
{ id: 8, name: 're', children: [] },
]
}
]
}
]
function findData(data, id = 1) {
let queue = [data[0]]
let map = new Map()
map.set(data[0], [data[0].name])
while (queue.length) {
let length = queue.length
for (let i = 0; i < length; i++) {
let node = queue.shift()
for (let i = 0; i < node.children.length; i++) {
if (node.children[i].id === id) {
return [...map.get(node), node.children[i].name].join('-')
} else {
queue.push(node.children[i])
map.set(node.children[i], [...map.get(node), node.children[i].name])
}
}
}
console.log(map);
}
}
console.log(findData(data3, 5));//前端-html-vue
#算法##前端工程师##秋招##如何反向拿捏领导##后端开发实习生#
查看9道真题和解析

汤臣倍健公司氛围 361人发布