面试手写题
文章
- 精进 JavaScript|这些手写你都会吗 ? - 掘金
- 死磕 36 个 JS 手写题(搞懂后,提升真的大) - 掘金
- 2021 年前端各大公司都考了那些手写题(附带代码) - 掘金
- 一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧 - 掘金
- 22 道高频 JavaScript 手写面试题及答案 - 掘金
- 32个手写JS,巩固你的JS基础(面试高频) - 掘金
- 20 道 JS 原理题助你面试一臂之力! - 掘金
数组与树
给定数组
ts
const array: List = [
{ id: 2, name: '部门B', parentId: 0 },
{ id: 3, name: '部门C', parentId: 1 },
{ id: 1, name: '部门A', parentId: 2 },
{ id: 4, name: '部门D', parentId: 1 },
{ id: 5, name: '部门E', parentId: 2 },
{ id: 6, name: '部门F', parentId: 3 },
{ id: 7, name: '部门G', parentId: 2 },
{ id: 8, name: '部门H', parentId: 4 },
]
数组转树
ts
function arrayToTree(list: List, pId: number): Tree {
const len = list.length
const loop = (pId: number) => {
const res: Tree = []
for (let i = 0; i < len; i++) {
// console.log(pId, i) //72次
const item: TreeItem = list[i]
if (item.parentId === pId) {
item.children = loop(item.id)
res.push(item)
}
}
return res
}
return loop(pId)
}
const tree = arrayToTree(array, 0)
console.log('数组转树', tree)
树转数组
ts
function treeToArray(tree: Tree): List {
const result = []
tree.forEach(item => {
const loop = (data: TreeItem) => {
result.push({
id: data.id,
name: data.name,
parentId: data.parentId,
})
const child = data.children
if (child) {
for (let i = 0; i < child.length; i++) {
loop(child[i])
}
}
}
loop(item)
})
return result
}
console.log('树转数组', treeToArray(tree))
新增节点
ts
function addNode(root: Tree, node: TreeItem) {
let added = false
const loop = (tree: Tree) => {
const len = tree.length
for (let i = 0; i < len; i++) {
if (added) break
const item = tree[i]
// console.log('新增 for item', item)
if (item.id === node.parentId) {
item.children ? item.children.push(node) : (item.children = [node])
added = true
} else {
if (item.children) {
loop(item.children)
}
}
}
}
loop(root)
return root
}
console.log('新增节点', addNode(tree, { id: 9, name: '新增部门', parentId: 3 }))
删除节点
ts
function deleteNode(root: Tree, deleteTreeId: number) {
let deleted = false
const loop = (tree: Tree) => {
const len = tree.length
for (let i = 0; i < len; i++) {
if (deleted) break
const node = tree[i]
// console.log('删除 for item', node)
if (node.id === deleteTreeId) {
tree.splice(i, 1)
deleted = true
} else {
if (node.children) {
loop(node.children)
}
}
}
}
loop(root)
return root
}
console.log('删除节点', deleteNode(tree, 9))
修改节点
ts
function updateNode(root: Tree, node: NodeItem) {
let updated = false
const loop = (tree: Tree) => {
const len = tree.length
for (let i = 0; i < len; i++) {
if (updated) break
const item = tree[i]
// console.log('修改 for item', item)
if (item.id === node.id) {
tree[i] = node
updated = true
} else {
if (item.children) {
loop(item.children)
}
}
}
}
loop(root)
return root
}
console.log('修改节点', updateNode(tree, { id: 5, name: '修改部门' }))
查找节点
ts
function findNode(root: Tree, id: number) {
let foundNode = null
const loop = (tree: Tree) => {
const len = tree.length
for (let i = 0; i < len; i++) {
if (foundNode) break
const node = tree[i]
if (node.id === id) {
foundNode = node
} else {
if (node.children) {
loop(node.children)
}
}
}
}
loop(root)
return foundNode
}
console.log('查找节点', findNode(tree, 4))
函数式编程
柯里化
javascript
function currying(fn) {
const length = fn.length
return function (...args) {
return args.length >= length
? fn.apply(this, args)
: currying(fn.bind(this, ...args))
}
}
// Test
const fn = currying(function (a, b, c) {
console.log([a, b, c])
})
fn('a', 'b', 'c') // ["a", "b", "c"]
fn('a', 'b')('c') // ["a", "b", "c"]
fn('a')('b')('c') // ["a", "b", "c"]
fn('a')('b', 'c') // ["a", "b", "c"]
累加函数
javascript
function sum(...args) {
let params = args
const _sum = (...newArgs) => {
if (newArgs.length === 0) {
return params.reduce((pre, cur) => pre + cur, 0)
} else {
params = [...params, ...newArgs]
return _sum
}
}
return _sum
}
// Test
console.log(sum(1, 2)(3)()) // 6
console.log(sum(1)(2)(3)()) // 6
console.log(sum(1, 2, 4)(4)()) // 11
once 函数
javascript
const once = fn => {
let res,
isFirst = true
return function (...args) {
if (!isFirst) return res
res = fn.call(this, ...args)
isFirst = false
return res
}
}
// Test
const f = x => x
const onceF = once(f)
//=> 3
onceF(3)
//=> 3
onceF(4)
vDom转成真实Dom
ts
const vnode: VNode = {
tag: 'DIV',
attrs: { id: 'app' },
children: [
{
tag: 'SPAN',
children: [
{
tag: 'mark',
attrs: { class: 'text-amber-500' },
children: ['这里是添加的dom'],
},
],
},
{
tag: 'SPAN',
children: [
{ tag: 'A', children: [] },
{ tag: 'A', children: [] },
],
},
],
}
function _render(vnode: VNode) {
if (typeof vnode === 'number') {
vnode = String(vnode)
}
//处理文本节点
if (typeof vnode === 'string') {
return document.createTextNode(vnode)
}
const { tag, attrs, children } = vnode
//普通dom
const dom = document.createElement(tag)
if (attrs) {
for (let key in attrs) {
dom.setAttribute(key, attrs[key])
}
}
if (children.length > 0) {
children.forEach(node => dom.appendChild(_render(node)))
}
return dom
}
function render(vnode: VNode, container: HTMLElement) {
const dom = _render(vnode)
console.log(dom)
container.appendChild(dom)
}
onMounted(() => {
render(vnode, document.getElementById('root'))
})