# 手写常见的JS面试题 31-36
# 31、将虚拟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 _vnode(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.map(child => dom.appendChild(_vnode(child)));
return dom;
}
# 32、实现摸板字符串解析功能
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
name: '姓名',
age: 18
}
render(template, data); // 我是姓名,年龄18,性别undefined
function render(template, data) {
const computed = template.replace(/\{\{(\w+)\}\}/g, function (match, key) {
return data[key];
})
return computed;
}
# 33、实现一个对象的flatten方法
const obj = {
a: {
b: 1,
c: 2,
d: {e: 5}
},
b: [1, 3, {a: 2, b: 3}],
c: 3
}
flatten(obj) 结果返回如下
// {
// 'a.b': 1,
// 'a.c': 2,
// 'a.d.e': 5,
// 'b[0]': 1,
// 'b[1]': 3,
// 'b[2].a': 2,
// 'b[2].b': 3
// c: 3
// }
function isObject(val) {
return typeof val === 'object' && val !== null;
}
function objFlatten(obj) {
if (!isObject(obj)) return;
const res = {};
function dfs(cur, prefix) {
if (isObject(cur)) {
if (Array.isArray(cur)) {
cur.forEach((item, index) => {
dfs(item, `${prefix}[${index}]`)
})
}
Object.keys(cur).forEach(key => {
dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`)
})
} else {
res[prefix] = cur;
}
}
dfs(obj, "");
return res;
}
function objectFlat(obj = {}) {
const res = {}
function flat(item, preKey = '') {
Object.entries(item).forEach(([key, val]) => {
const newKey = preKey ? `${preKey}.${key}` : key
if (val && typeof val === 'object') {
flat(val, newKey)
} else {
res[newKey] = val
}
})
}
flat(obj)
return res
}
# 34、列表转成树结构
[
{
id: 1,
text: '节点1',
parentId: 0 //这里用0表示为顶级节点
},
{
id: 2,
text: '节点1_1',
parentId: 1 //通过这个字段来确定子父级
}
...
]
转成
[
{
id: 1,
text: '节点1',
parentId: 0,
children: [
{
id:2,
text: '节点1_1',
parentId:1
}
]
}
]
function convert(list) {
const map = new Map(); // 借用对象内存指针指向堆
return list.reduce((pre, cur) => {
const {id, parentId} = cur;
if (parentId === 0) {
pre.push(cur);
} else {
const itemCache = map.get(parentId);
if (itemCache) {
itemCache.children = itemCache.children ? [...itemCache.children, cur] : [cur];
}
}
if (!map.has(id)) {
map.set(id, cur);
}
return pre;
}, []);
}
# 35、树结构转换成列表
[
{
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 cover(arr) {
const result = [];
function dfs(cur) {
for (let i = 0; i < cur.length; i++) {
if (cur[i].child) {
dfs(cur[i].child);
delete cur[i].child;
}
result.push(cur[i]);
}
}
dfs(arr);
return res;
}
# 36、大数相加
题目描述:实现一个add方法完成两个大数相加
let a = "9007199254740991";
let b = "1234567899999999999";
function add(a, b) {
//...
}
function add(a, b) {
const maxLength = Math.max(a.length, b.length);
a.padStart(maxLength, '0');
b.padStart(maxLength, '0');
//定义加法过程中需要用到的变量
let f = 0; // "进位"
let sum = "";
for (let i = maxLength - 1; i >= 0; i--) {
const 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;
}
# 37、模拟Object.create
function create(proto) {
function Fn() {
}
Fn.prototype = proto;
return new Fn();
}
# 38、实现一个JSON.stringify
function jsonStringify(obj) {
let type = typeof obj;
if (type !== "object") {
if (/string|undefined|function/.test(type)) {
obj = '"' + obj + '"';
}
return String(obj);
} else {
let json = []
let arr = Array.isArray(obj)
for (let k in obj) {
let v = obj[k];
let type = typeof v;
if (/string|undefined|function/.test(type)) {
v = '"' + v + '"';
} else if (type === "object") {
v = jsonStringify(v);
}
json.push((arr ? "" : '"' + k + '":') + String(v));
}
return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}")
}
}
jsonStringify({x: 5}) // "{"x":5}"
jsonStringify([1, "false", false]) // "[1,"false",false]"
jsonStringify({b: undefined}) // "{"b":"undefined"}"
# 38、实现一个JSON.parse
function jsonParse(opt) {
return eval('(' + opt + ')')
}
# 39、JS解析URL Params对象
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
function parseParam(url) {
let paramsArr = url.slice(url.indexOf('?') + 1).split('&');
let paramsObj = {};
paramsArr.forEach(item => {
if (item.indexOf('=') !== -1) {
let [key, val] = item.split('=');
val = decodeURIComponent(val);
val = /^d+$/.test(val) ? parseFloat(val) : val;
if (paramsObj.hasOwnProperty(key)) {
paramsObj[key] = [].concat(paramsObj[key], val)
} else {
paramsObj[key] = val;
}
} else {
paramsObj[item] = true
}
})
return paramsObj;
}
# 40、转化驼峰命名
var s1 = "get-element-by-id"
// 转化为 getElementById
var f = function(s) {
return s.replace(/-\w/g, function(x) {
return x.slice(1).toUpperCase();
})
}