SOURCE

var virtualDom = {
    tag: 'DIV',
    attrs: {
        id: 'app'
    },
    children: [{
        tag: 'SPAN',
        children: [
            { tag: 'A', children: [] }
        ]
    }, {
        tag: 'SPAN',
        children: [
            { tag: 'A', children: [] },
            { tag: 'A', children: [] },
        ]
    }]
}

function render(dom) {
    let node = null
    if (dom.tag) {
        node = document.createElement(dom.tag.toLowerCase())
    }
    if (dom.attrs && Object.keys(dom.attrs)) {
        Object.keys(dom.attrs).forEach(key => {
            node.setAttribute(key, dom.attrs[key] || '')
        })
    }
    if (dom.children && dom.children.length) {
        dom.children.forEach(child => node.appendChild(render(child)))
    }
    return node
}

var element = render(virtualDom)
// console.log(element)

var a1 = [1,2,3,4,[5,[6]]]

function useWhile (arr) {
    while(arr.some(v => Array.isArray(v))) {
        arr = [].concat(...arr)
    }
    console.log('useWhile ', arr)
    return arr
}
// useWhile(a1)

const obj = {
    a: {
        b: 1,
        c: {},
        d: {e: 3}
    },
    b: [1,2, {a: 3, b: []}],
    c: 3,
    d: [] 
}

function demo(data) {
    const result = {}
    function format(value, key) {
        // 基础类型
        if (typeof value !== 'object') {
            key && (result[key] = value)
        } else if (Array.isArray(value)) {
            value.forEach((v, i) => {
                format(v, key ? `${key}.${i}` : i)
            })
            // 空数组
            if (value.length === 0) {
                result[key] = value
            }
        } else {
            Object.keys(value).forEach(k => {
                format(value[k], key ? `${key}.${k}` : k)
            })
            // 空对象
            if (Object.keys(value).length === 0) {
                result[key] = value
            }
        }
    }
    data && format(data, '')
    console.log('result ', result)
    return result
}
// demo(obj)


const arr1 = [
	{id:"01", name: "张大大", pid:"", job: "项目经理"},
	{id:"02", name: "小亮", pid:"01", job: "产品leader"},
	{id:"03", name: "小美", pid:"01", job: "UIleader"},
	{id:"04", name: "老马", pid:"01", job: "技术leader"},
	{id:"05", name: "老王", pid:"01", job: "测试leader"},
	{id:"06", name: "老李", pid:"01", job: "运维leader"},
	{id:"07", name: "小丽", pid:"02", job: "产品经理"},
	{id:"08", name: "大光", pid:"02", job: "产品经理"},
	{id:"09", name: "小高", pid:"03", job: "UI设计师"},
	{id:"10", name: "小刘", pid:"04", job: "前端工程师"},
	{id:"11", name: "小华", pid:"04", job: "后端工程师"},
	{id:"12", name: "小李", pid:"04", job: "后端工程师"},
	{id:"13", name: "小赵", pid:"05", job: "测试工程师"},
	{id:"14", name: "小强", pid:"05", job: "测试工程师"},
	{id:"15", name: "小涛", pid:"06", job: "运维工程师"}
]

// 数组转树
function arr2tree(data) {
    const root = []
    const map = data.reduce((cur, pre) => ({...cur, [pre.id]: pre}), {})
    // console.log(map)
    for (const item of data) {
        const parent = map[item.pid]
        if (parent) {
            if (!parent.children) {
                parent.children = []
            }
            parent.children.push(item)
        } else {
            root.push(item)
        }
    }
    console.log(root)
}
// arr2tree(arr1)

function arr2tree2(data, pid) {
    return data.filter(v => v.pid === pid).map(v=> ({...v, children: arr2tree2(data, v.id)}))
}
// console.log(arr2tree2(arr1, ''))

const treeData = [
	{
		id: 2, title: '中国', pid: 0,
		children: [
			{
				id: 3, title: '广东省', pid: 2,
				children: [
					{
						id: 4, title: '广州市', pid: 3,
						children: [
							{ id: 5, title: '天河区', pid: 4 }
						]
					}
				]
			},
			{ id: 6, title: '湖南省', pid: 2 }
		]
	},
	{ id: 1, title: '俄罗斯', pid: 0 },
]

// 树转数组
function getChild(nodes) {
    const res = []
    for (const item of nodes) {
        const {children, ...rest} = item
        res.push(rest)
        if (children && children.length) {
            res.push(...getChild(item.children))
        }
    }
    return res
}

function tree2arr(nodes) {
    return nodes.reduce((cur, pre) => {
        const {children, ...rest} = pre
        return cur.concat(rest, Array.isArray(children) ? tree2arr(children) : [])
    }, [])
}
// console.log(tree2arr(treeData))
// console.log(getChild(treeData))

// 模拟Object.create
function objCreate(proto) {
    function F() {}
    F.prototype = proto
    return F
}

// 模拟实现instanceof
function instanceof2(left, right) {
    const o = right.prototype
    left = left.__proto__
    if (left === null) {
        return false
    }
    return left === o
}

// 深度克隆
var s = {
    a: 1,
    b: function () {
        console.log('b123');
    },
    c: 'is c',
    d: {
        e: null,
        f: {
            g: undefined,
        }
    },
    h: [1, 2, 3]
};

function cloneDeep(data) {
    if (typeof data !== 'object') {
        return data
    }
    let child = data instanceof Array ? [] : {}
    for (const key in data) {
        const val = data[key]
        child[key] = typeof val !== 'object' ? val : cloneDeep(val)
    }
    return child
}

const newObj = cloneDeep(s)
newObj.d.f.g = 123
// console.log(newObj)
// console.log(s)

// bind call apply
var cat = {
    type: 'cat',
    name: 'miaomiao'
}

function animal(age, tall) {
    console.log(`tall = ${tall}`)
    console.log(`${this.name} is a ${this.type}, ${age} years old.`)
}

// bind
Function.prototype.bind2 = function(ctx) {
    const context = ctx || window
    context.fn = this
    const args = arguments.splice(1)
    return function() {
        context.fn(...args, ...arguments)
        delete context.fn
    }
}
// animal.bind(cat)(2)

// call
Function.prototype.call2 = function(ctx) {
    const context = ctx || window
    context.fn = this
    const result = context.fn(...arguments)
    delete context.fn
    return result
}
// animal.call(cat)

// apply
Function.prototype.apply2 = function(ctx, params = []) {
    const context = ctx || window
    context.fn = this
    const result = context.fn(params)
    delete context.fn
    return result
}
// animal.apply(cat, [11, 12])

// 防抖
function debounce(fn, delay) {
    let timer = null
    return function(...args) {
        timer && clearTimeout(timer)
        timer = setTimeout(() => {
            fn && fn.apply(this, args)
        }, delay)
    }
}

// 节流
function throttle(fn, delay) {
    let latest = 0
    return function(...args) {
        const now = Date.now()
        if (now - latest > delay) {
            fn && fn.apply(this, args)
            latest = now
        }
    }
}

// reduce 实现filter

var f = [1,2,3,4,5,6]
Array.prototype.filter2 = function(callbak) {
    return this.reduce((cur, pre) => {
        return cur.concat(callbak && callbak(pre) ? pre : [])
    }, [])
}
// console.log(f.filter2(v => v > 4))

// filter
Array.prototype.filter3 = function(callback) {
    const result = []
    for (let i = 0; i < this.length; i++) {
        if (callback && callback(this[i], i, this)) {
            result.push(this[i])
        }
    }
    return result
}
// console.log(f.filter3(v => v > 3))

// some
Array.prototype.some1 = function(callbak) {
    let result = false
    for (let i = 0;i<this.length;i++) {
        if (callbak && callbak(this[i], i, this)) {
            result = true
            break
        }
    }
    return result
}
// console.log(f.some1(v => v >4))

// every
Array.prototype.every1 = function(callback) {
    let total = 0
    for (let i=0;i<this.length; i++) {
        if (callback && callback(this[i], i, this)) {
            total += 1
        }
    }
    return total === this.length
}
// console.log(f.every1(v => v > 4))

// map
Array.prototype.map1 = function(callback) {
    const result = []
    for (let i =0; i< this.length; i++) {
        result.push(callback && callback(this[i], i, this))
    }
    return result
}

// console.log('map => ', f.map(v => v > 1))
// console.log('map1 => ', f.map1(v => v > 1))

// 字符模板
var str = 'test/action?name=${name}&age=${age}';
var strObj = {
    name: 'jack',
    age: 20
}
function renderTpl(tpl, obj) {
    Object.keys(obj).forEach(key => {
        // const reg = new RegExp("\\${"+key+ "}", 'g')
        const reg = new RegExp(`\\$\{${key}\}`, 'g')
        tpl = tpl.replace(reg, obj[key])
        // tpl = tpl.replace(/\$\{(.*?)\}/g, obj[key])
    })
    return tpl
}
// console.log(renderTpl(str, strObj))

// 继承 组合式
function Person(name) {
    this.name = name
    this.say = function() {
        console.log(`my name is ${this.name}`)
    }
}

function Child(age) {
    Person.call(this, age)
}

Child.prototype = new Person()
Child.prototype.constructor = Child
// const c = new Child(11)
// c.name = 'jack'
// c.say()

// 继承 寄生组合式
function Child2(age) {

}
Child2.prototype = Object.create(Person)
Child2.prototype.constructor = Child2
console 命令行工具 X clear

                    
>
console