Advanced-Frontend / Daily-Interview-Question

我是依扬(木易杨),公众号「高级前端进阶」作者,每天搞定一道前端大厂面试题,祝大家天天进步,一年后会看到不一样的自己。

Home Page:https://muyiy.cn/question/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

第 111 题:编程题,写个程序把 entry 转换成如下对象

yygmind opened this issue · comments

var entry = {
a: {
 b: {
   c: {
     dd: 'abcdd'
   }
 },
 d: {
   xx: 'adxx'
 },
 e: 'ae'
}
}

// 要求转换成如下对象
var output = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae'
}

我先来

function flatObj(obj, parentKey = "", result = {}) {
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      let keyName = `${parentKey}${key}`;
      if (typeof obj[key] === 'object')
        flatObj(obj[key], keyName+".", result)
      else
        result[keyName] = obj[key];
    }
  }
  return result;
}
commented
function isObject (obj) {
    return Object.prototype.toString.call(obj) === '[object Object]'
}
function flatObj (obj, prefix = '', res = {}) {
    for (let i in obj) {
        let key = prefix ? prefix + '.' + i : i
        isObject(obj[i]) ? flatObj(obj[i], key, res) : (res[key] = obj[i])
    }
    return res
}
commented
var entry = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}

var keys = [];
function flatObj(from, to) {
  for (var key in from) {
    var res = from[key];
    keys.push(key);
    if (typeof res === "object") {
      flatObj(res, to);
    } else {
      to[keys.join(".")] = res;
    }
    keys.pop();
  }
}

var output = {};
flatObj(entry, output);
console.log(output);
function en(obj) {
    const keyArr = [];
    const newObj = {};
    const _c = function (o) {
        for (k in o) {
            keyArr.push(k);
            if (typeof o[k] === 'object') {
                _c(o[k]);
            } else {
                newObj[keyArr.join('.')] = o[k];
                keyArr.pop();
            }
        }
        keyArr.pop();
    }
    _c(obj);
    return newObj;
}

bfs

function flatObj(entry) {
	const queue = Object.entries(entry)
	const res = {}
	while (queue.length) {
		const [key, obj] = queue.pop()
		for (const [k, v] of Object.entries(obj)) {
			if (typeof v !== 'object') {
				res[`${key}.${k}`] = v
			} else {
				queue.push([`${key}.${k}`, v])
			}
		}
	}
	return res
}
function func (origin, output = {}, keys = []) => {
  if (typeof origin === 'object') {
    for (const k in origin) {
      generate(origin[k], output, [...keys, k])
    }
  } else {
    output[keys.join('.')] = origin
  }
}
const output = {}
func(entry, output)
console.log('output', output)
    var obj = {
        a: {
            b: {
                c: {
                    dd: 'abcdd'
                }
            },
            d: {
                xx: 'adxx'
            },
            e: 'ae'
        }
    };

    function convert(target,preKey = '',result = {}){
        let keys = Object.keys(target),
            len = keys.length;

        while(len--){
            let curKey = keys[len];
            let targetKey = preKey ? `${preKey}.${curKey}` : curKey;
            if(Object.prototype.toString.call(target[curKey]) === '[object Object]'){
                convert(target[curKey],targetKey,result);
            }else{
                result[targetKey] = target[curKey];
            }
        }

        return result;
    }

    console.log(convert(obj));
    function flat(obj, key = "", res = {}) {
      Object.keys(obj).forEach(k => {
        if (Object.prototype.toString.call(obj[k]) == "[object Object]") {
          flat(obj[k], key + k + ".", res);
        } else {
          res[key + k] = obj[k];
        }
      });
      return res;
    }
    console.log(flat(entry));

题目

var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
};

// 要求转换成如下对象
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
};

实现方案

思路 遍历对象,遇到还是对象的地方递归深入即可。

核心代码:

/**
 *
 * @param {String | null} prevKey 前面的key
 * @param {Object} obj 当前操作对象
 * @returns {Array<Object>} 扁平化后的对象数组
 */
function getFlat(prevKey, obj) {
    const arr = [];
    Object.keys(obj).forEach(k => {
        const currentKey = prevKey ? `${prevKey}.${k}` : k;
        if (Object.prototype.toString.call(obj[k]) != '[object Object]') {
            arr.push({
                [currentKey]: obj[k]
            });
        } else {
            arr.push(...getFlat(currentKey, obj[k]));
        }
    });

    return arr;
}

以给定代码为例,即可转化为如下形式,然后进行合并即可。

[
    {'a.b.c.dd': 'abcdd'},
    {'a.d.xx': 'adxx'},
    {'a.e': 'ae'},
]

如果不考虑纯函数的问题,可以初始就定义一个空对象,然后在递归函数中直接将每次的结果写入,这样就少了后续的合并操作,详见后续实现中的 flatObject2

完整代码

var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
};
/**
 * 对象扁平化
 * @param {Object}  obj 操作对象
 * @returns {Object} 扁平化后的对象
 */
function flatObject(obj) {
    const flat = {};

    return Object.assign(flat, ...getFlat(null, obj));

    /**
     *
     * @param {String | null} prevKey 前面的key
     * @param {Object} obj 当前操作对象
     * @returns {Array<Object>} 扁平化后的对象数组
     */
    function getFlat(prevKey, obj) {
        const arr = [];
        Object.keys(obj).forEach(k => {
            const currentKey = prevKey ? `${prevKey}.${k}` : k;
            if (Object.prototype.toString.call(obj[k]) != '[object Object]') {
                arr.push({
                    [currentKey]: obj[k]
                });
            } else {
                arr.push(...getFlat(currentKey, obj[k]));
            }
        });

        return arr;
    }
}

console.log(JSON.stringify(flatObject(entry), 0, 4));
// {
//     "a.b.c.dd": "abcdd",
//     "a.d.xx": "adxx",
//     "a.e": "ae"
// }

/**
 * 对象扁平化
 * @param {Object}  obj 操作对象
 * @returns {Object} 扁平化后的对象
 */
function flatObject2(obj) {
    const flat = {};
    getFlat(null, obj);
    return flat;
    /**
     * 递归将对象扁平化
     * @param {String | null} prevKey 前面的key
     * @param {Object} obj 当前操作对象
     */
    function getFlat(prevKey, obj) {
        Object.keys(obj).forEach(k => {
            const currentKey = prevKey ? `${prevKey}.${k}` : k;
            if (Object.prototype.toString.call(obj[k]) != '[object Object]') {
                flat[currentKey] = obj[k];
            } else {
                getFlat(currentKey, obj[k]);
            }
        });
    }
}
console.log(JSON.stringify(flatObject2(entry), 0, 4));
// {
//     "a.b.c.dd": "abcdd",
//     "a.d.xx": "adxx",
//     "a.e": "ae"
// }
function flatObj(entry){
  function rec (entry, parentKey , result){
    Object.keys(entry).forEach((key) => {
       if(typeof entry[key] === 'object') {
         rec(entry[key], parentKey + key, result)
    } else {
         const keyname = parentKey.replace(/(?=\B)/g, '.')+ '.' +key
      result[keyname] = entry[key]
    }
    })
  }
  rec(entry, parentKey = '', result = {}) 
  return result
}

function flatObj(obj) {
let arr = Object.entries(obj);
arr.map(item => {
if(typeof item[1] === 'object'){
let keys = Object.keys(item[1]);
let values = Object.values(item[1]);
let temp = {};
for(let i=0;i<keys.length;i++) {
temp[${item[0]}.${keys[i]}] = values[i]
}
flatObj(temp)
}else {
output[item[0]] = item[1];
}
})
}

        function objs(_old,key,_new){
            if(!key) key = '';
            if(!_new)_new = {};
            for(let attr in _old){
                let data = _old[attr];
                if(data!=null && typeof data === 'object'){
                     objs(data,key+attr+'.',_new);
                }else{
                    _new[key+attr] = data;
                }
            }
            return _new;
        }

        console.log(objs({
            a:{
                b:{
                    c:{
                      dd:'abcdd'
                    }
                },
                d:{
                    xx:{
                        cc:'xxxx'
                    }
                },
                e:'ae',
                g:{
                  ooxx:'xxx'  
                }
            }
        }));
function flatJson(obj = {}, parentKey = '', res = {}) {
    for (let k in obj) {
        if (typeof obj[k] !== 'object' && obj[k] !== null) {
            res[`${parentKey}${k}`] = obj[k];
        } else {
            flatJson(obj[k], `${parentKey}${k}.`, res);
        }
    }
    return res;
}

大相径庭

var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
           }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
}
/**
 * [getFlat]
 * @param  {[Object]} entry [传入对象]
 * @param  {String} hea   [属性名前缀]
 * @param  {Object} res   [返回对象]
 */
function getFlat (entry, hea = '', res = {}) {
    for (let k in entry) {
        if (entry.hasOwnProperty(k)) {
            if (Object.prototype.toString.call(entry[k]) === '[object Object]' ) {
                getFlat(entry[k], hea + k + '.', res)
            } else {
                res[hea + k] = entry[k]
            }
        }
    }
    return res
}
console.log(getFlat(entry))
// 1.先遍历,判断是否包含属性
// 2.属性值是对象继续递归
// 3.属性值不是对象返回
const flattenObject = (obj, prefix = '') =>
  Object.keys(obj).reduce((acc, k) => {
    const pre = prefix.length ? prefix + '.' : '';
    if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
    else acc[pre + k] = obj[k];
    return acc;
  }, {})
commented
function chang(obj, parentKey = '', res = {}) {
	for(let i in obj) {
		let Key = parentKey ? (parentKey + '.' + i) : i;
		(typeof obj[i] === 'object')?chang(obj[i], Key, res):res[Key] = obj[i];
	}
	return res
}

console.log(chang(entry))//{a.b.c.dd: "abcdd", a.d.xx: "adxx", a.e: "ae"}

function fun111(entry) {
let array111 = {}
function fun111_1 (entry, f) {
for (let i in entry) {
let t = f ? ${f}.${i} : i
if (typeof entry[i] === 'string') {
array111[t] = entry[i]
} else {
fun111_1(entry[i], t)
}
}
}
fun111_1(entry)
return array111
}

`var entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}

	function getOutput(obj){
		let parentKey = '';
		let output = {};
		
		if(Object.prototype.toString.call(entry) === '[object Object]'){
			(function getKeys(obj, str){
				for(let key in obj){
					let newStr = str === '' ? key : `${str}.${key}`;
					
					if(Object.prototype.toString.call(obj[key]) === '[object Object]'){
						getKeys(obj[key], newStr);
					}else{
						output[newStr] = obj[key];
					}
				}		
			})(obj, '')
		}else{
			console.log('传入的不是对象');
		}
		
		return output;
	}
	
	getOutput(entry)`
var entry = {
    a: {
      b: {
        c: {
          dd: 'abcdd'
        }
      },
      d: {
        xx: 'adxx'
      },
      e: 'ae'
    }
  }

  const deepFlat = (obj) => {
    let res = {}
    function deep(obj, prekey = '') {
      for (let key of Object.keys(obj)) {
        if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
          deep(obj[key], prekey ? `${prekey}.${key}` : key)
        } else {
          res[`${prekey}.${key}`] = obj[key]
        }
      }
    }
    deep(obj)
    return res
  }

  console.log(deepFlat(entry))
function fun1(obj, str = '', result = {}) {

  Object.keys(obj).forEach((key) => {

    if (typeof obj[key] == 'object') {
      fun1(obj[key], str + key + '.', result)
    } else {
      str += key
      result[str] = obj[key]
    }
  })
  return result
}

console.log(fun1(entry))

上一版typescript实现

function transformObject(input: any, keyStr: string='', result: any={}): any{
    const keys: Array<string> = Object.keys(input);
    keys.map(key => {
        if (typeof input[key] === 'object') {
            transformObject(input[key], keyStr+`${key}.`, result)
        } else {
            keyStr += `${key}`;
            result[keyStr] = input[key];
        }
    })

    return result
}
commented
const  isObject = (value) => (typeof value === 'object') && (value !== null)

function reduceObject(obj, parentName, resultObj) { // 对 {} 的每个值进行判断
  const keyNames = Object.keys(obj); // ['b', 'd']
  keyNames.forEach(keyName => {
    let currentValue = obj[keyName] // 当前值
    let currentKeyName = parentName ? `${parentName}.${keyName}` : keyName // 当前键名
    // 键值为对象则继续递归, 为其它值则将新的键值对添加到result中
    if(isObject(currentValue)) {
      reduceObject(currentValue, currentKeyName, resultObj)
    } else {
      resultObj[currentKeyName] = currentValue
    }
  })
}

function flatKeyName(obj) {
  let outputObj = {}
  reduceObject(entry, null, outputObj)
  return outputObj
}

console.log(flatKeyName(entry))
commented
function isPlainObject(obj){
   return Object.prototype.toString.call(obj) === '[object Object]'
}
const output = {}
function parserObj(obj,parentKey=''){
  if(isPlainObject(obj)){
     Object.keys(obj).forEach(key=>{
         parserObj(obj[key],`${parentKey}${key}.`)
     })
  }else{
     output[parentKey] = obj
  }
}
var entry = {
a: {
 b: {
   c: {
     dd: 'abcdd'
   }
 },
 d: {
   xx: 'adxx'
 },
 e: 'ae'
}
}
parserObj(entry)
console.log(output)
function flatObj(preKey, obj, result = {}) {
    if (JSON.stringify(obj) === '{}') {
        return {};
    }
    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            const curKey = preKey ? `${preKey}.${key}` : key;
            if (typeof obj[key] !== 'object') {
                result[curKey] = obj[key];
            } else {
                flatObj(curKey, obj[key], result);
            }
        }
    }
    return result;
}
commented
function flatObj(entry, prev = "", result = {}) {
  Object.keys(entry).map((key) =>
    typeof entry[key] === "object"
      ? flatObj(entry[key], prev ? key : `${prev}.${key}`, result)
      : (result[prev ? key : `${prev}.${key}`] = entry[key])
  );
  return result;
}
commented
        a: {
          b: {
            c: {
              dd: 'abcdd'
            }
          },
          d: {
            xx: 'adxx'
          },
          e: 'ae'
        }
      }

      function exchange(obj) {
        if (typeof obj != 'object') {
          throw new Error('请输入 [object Object] 类型')
        }
        let O = {}
        let digui = function(obj, str) {
          for (let key in obj) {
            let str_ = str + '.' + key
            if (typeof obj[key] == 'object') {
              digui(obj[key], str_)
            } else {
              O[str_.slice(1)] = obj[key]
            }
          }
        }
        let res = digui(obj, '')
        return O
      }
      let res = exchange(entry)
      console.log(res)   //{a.b.c.dd: "abcdd", a.d.xx: "adxx", a.e: "ae"}
var entry = {
  a: {
    b: {
      c: {
        dd: 'abcdd',
      },
    },
    d: {
      xx: 'adxx',
    },
    e: 'ae',
  },
}

function flatPlainObj(entry) {
  if (Object.prototype.toString.call(entry) !== '[object Object]') {
    throw new Error('entry must be a plain object')
  }

  var output = {}
  var pathArr = []

  function recur(entry) {
    if (Object.prototype.toString.call(entry) === '[object Object]') {
      Object.keys(entry).forEach(key => {
        pathArr.push(key)
        recur(entry[key])
        pathArr.pop()
      })
    } else {
      output[pathArr.join('.')] = entry
    }
  }

  recur(entry)

  return output
}

console.log(flatPlainObj(entry))
commented
function flattern(o, path = '', res = {}) {
  Object.keys(o).forEach((key) => {
    if (Object.prototype.toString.call(o[key]) === '[object Object]' || Array.isArray(o[key])) {
      flattern(o[key], `${path}.${key}`, res)
    } else {
      res[`${path}.${key}`.slice(1)] = o[key]
    }
  });
  return res
}

深度遍历

   function convert(entry) {
      const queue = [];
      const output = {};
      function dft(obj) {
        const keys = Object.keys(obj);
        for (let i of keys) {
          queue.push(i);
          if (typeof obj[i] === 'object') {
            dft(obj[i]);
          } else {
            output[queue.join('.')] = obj[i];
          }
          queue.pop();
        }
      }
      dft(entry);
      return output;
    }

function f1() {
var str = '',obj = {};
return function (en) {
for(var i in en){
if(Object.prototype.toString.call(en[i])=="[object Object]" ){
str+=i+'.';
arguments.callee(en[i],str);
str = str.slice(0,str.length-1-i.length);
}else{
str+=i;
obj[str] = en[i];
str = str.slice(0,str.length-1-i.length)+'.';

            }

        }
        console.log(obj);
    }
}

var cc =f1()(entry);
不用闭包是不完美的!

    var arr = []
    output = (entry, key = '') => {
        for (var [k, v] of Object.entries(entry)) {
            if (Object.prototype.toString.call(v) === '[object Object]') {
                this.output(v, key + k + '.')
            } else {
                arr.push([key + k, v])
            }
        }
    }
    output(entry)
    Object.fromEntries(arr)

这个编辑器也太难用了吧~~~~~

function flatObj(obj, keyList = [], retObj = {}) {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
let newkeyList = [...keyList]
newkeyList.push(key)
if (typeof obj[key] === 'object') {
flatObj(obj[key], newkeyList, retObj);
} else {
var str = newkeyList.join('.')
retObj[str] = obj[key]
}
}
}
return retObj;
}

function selfFlat (obj, keystr="", newObj = {}) {
  for (key in obj) {
    if (!obj.hasOwnProperty(key)) continue;  // 判断是否存在该属性
    let newkeystr = keystr ? keystr + '.' + key : key; 
    if(obj[key] instanceof Object) {
       selfFlat(obj[key], newkeystr, newObj)  // 如果当前还是个对象递归
    }
    else {
      newObj[newkeystr] = obj[key]   // 否之将键值对赋予新对象
    }
  }
  return newObj;
}
commented

深度优先遍历

function transform(v, k, output = {}) {
  Object.keys(v).forEach(key => {
    if (typeof v[key] === 'object') {
      return transform(v[key], k ? `${k}.${key}` : key, output)
    }
    output[`${k}` ? `${k}.${key}` : key] = v[key]
  })
  return output
}
let target = {
  a: {
    b: {
      c: 1
    }
  },
  b: {
    c: 2
  },
  d: {
    a: {
      b: {
        c: {
          e: 3
        }
      }
    }
  }
}

let getRes = (function formatObj (target) {
  let objRes = {}

  let init = function (obj = {}, name = '') {
     let propArr = Object.keys(obj)
     if (propArr.length) {
       propArr.forEach(item => {
         init(obj[item], name ? `${name}.${item}` : `${item}`)
       })
     } else {
       objRes[name] = obj
     }
     return objRes
  }
  
  return init
})(target)


let res = getRes(target) 

顺便问一句,为啥大佬们出来的代码是彩色的,是我操作姿势不对么。。囧RZ

function flatObjTO(obj,parentKey = "",result={}){ 
    for (var key in obj){
        debugger;
        let keyName = `${parentKey}${key}`;
        if (typeof obj[key]=== 'object'){
            flatObjTO( obj[key] ,keyName+"." ,result);
        } else {
            result[keyName]=obj[key];
        }
    }
    return result;
}

var entry = {
    a: {
      b: {
        c: {
          dd: 'abcdd'
        }
      },
      d: {
        xx: 'adxx'
      },
      e: 'ae'
    }
  };

  console.log(flatObjTO(entry));  

学习了

function flatten(entry, p, result = {}) {
    var keys = Object.keys(entry);

    return keys.reduce((acc, key) => {
        let newp = key;
        if (p) { newp = p + '.' + newp }

        if (typeof entry[key] === 'string') {
            acc[newp] = entry[key]
            return acc
        } else {
            return a(entry[key], newp, result)
        }
    }, result)
}
function flatten(entry, p, result = {}) {
    var keys = Object.keys(entry);

    return keys.reduce((acc, key) => {
        let newp = key;
        if (p) { newp = p + '.' + newp }

        if (typeof entry[key] === 'string') {
            acc[newp] = entry[key]
            return acc
        } else {
            return a(entry[key], newp, result)
        }
    }, result)
}

代码是怎么变色的?

var entry = {
a: {
 b: {
   o: 'o',
   c: {
     dd: 'abcdd'
   }
 },
 d: {
   xx: 'adxx'
 },
 e: 'ae'
 }
}
let totalKey = ''
let result = {}
function convertObj(obj,totalKey){
  Object.getOwnPropertyNames(obj).forEach(key=>{
     totalKey = `${totalKey}${ key}`+'.';
    if(typeof obj[key] == 'object'){
      convertObj(obj[key], totalKey);
    }else {
       totalKey.substr(0,totalKey.length-1)
      result[totalKey.substr(0,totalKey.length-1)] = obj[key];
    }
  })
  return result
}

console.log(convertObj(entry,totalKey));
var output = {}
function conver(obj,next) {
  var next = next || ''
  if (obj instanceof Object && obj.constructor.name === 'Object' ) {
    
    for(var key in obj) {
      conver(obj[key], next ? `${next}.${key}`: `${key}`)
    }
  } else {
    if (next) {
      output[next] = obj
    } else {
      throw '非法的数据类型!'
    }
  }
}
commented
  • 挺冗余的
var test = function (input) {
    var output = {};
    function copyCore(subObj, inputKey, output) {
        var keyList = Object.keys(subObj);
        var len = keyList.length;
        for (var i = 0; i < len; i++) {
            if (typeof subObj[keyList[i]] == 'object') {
                if (inputKey == '') {
                    copyCore(subObj[keyList[i]], keyList[i], output);
                }
                else {
                    copyCore(subObj[keyList[i]], inputKey + '.' + keyList[i], output);
                }
            }
            else {
                if (inputKey == '') {
                    output[inputKey + keyList[i]] = subObj[keyList[i]];
                }
                else {
                    output[inputKey + "." + keyList[i]] = subObj[keyList[i]];
                }
            }
        }
    }
    copyCore(input, '', output);
    return output;
};

标准的backtracking解法。

var entry = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}

let _entry = {};

function flatten(obj, key_arr) {
  for (let key in obj) {
    key_arr.push(key)
    if (typeof obj[key] !== 'object') {
      _entry[key_arr.join('.')] = obj[key];
    } else {
      flatten(obj[key], key_arr)
    }
    key_arr.pop();
  }
}

flatten(entry, [])
console.log(_entry)
commented

我先来

function flatObj(obj, parentKey = "", result = {}) {
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      let keyName = `${parentKey}${key}`;
      if (typeof obj[key] === 'object')
        flatObj(obj[key], keyName+".", result)
      else
        result[keyName] = obj[key];
    }
  }
  return result;
}

使用 typeof 判断是否是 object 有些不妥, 值为 null 的时候会出错

commented
判断都不做了。。
function entries(obj, preKey = '',result = {}){
  for(let [key, value] of Object.entries(obj)){
    const realKey = preKey ? `${preKey}.${key}` : key
    if(typeof value === 'object'){
      entries(value, realKey, result)
    } else {
      result[realKey] = value
    }
  }
  return result
}
/* 解答 */
const toString = (item) => Object.prototype.toString.call(item)

const result = {};  // 结果容器
const transform = (target, key=[]) => {
  if (toString(target) === '[object String]') {
    const newKey = key.join('.');
    const newValue = target;
    Object.assign(result, {
      [newKey]: newValue
    })
    return;  // 终止递归,输出值
  }
  else {
    Object.keys(target).forEach(item => {
      transform(target[item], [].concat(key,item));  // 递归执行,保存key
    })
  }
}

transform(entry);
console.log(result);

觉得自己的代码仍然可以优化,另外问一句各位大佬,这里的代码高亮是如何做的?

今天的编程题呢?

我先来

function flatObj(obj, parentKey = "", result = {}) {
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      let keyName = `${parentKey}${key}`;
      if (typeof obj[key] === 'object')
        flatObj(obj[key], keyName+".", result)
      else
        result[keyName] = obj[key];
    }
  }
  return result;
}

换了一种方法:

  function loop(entry, key = '', result = {}) {
    const obj = Object.keys(entry);
    for (let i = 0; i < obj.length; i++) {
      const keyName = key + obj[i];
      if (typeof entry[obj[i]] === 'object') {
        this.loop(entry[obj[i]], `${keyName}.`, result);
      } else {
        result[keyName] = entry[obj[i]];
      }
    }
   return result;
  }

function getMyFlat(entry, parent= '', result ={}) {
  for (let key in entry) {
    if (entry.hasOwnProperty(key)) {
      if(Object.prototype.toString.call(entry[key]) === '[object Object]') {
        getMyFlat(entry[key], `${parent}${key}.`, result)
      } else {
        result[`${parent}${key}`] = entry[key]
      }
    }
  }
  return result;
}
console.log(getMyFlat(entry));

菜鸟版

const converst = (obj, result, valStr) => {
  const keys =Object.keys(obj);
  keys.forEach(function(i) {
    if (typeof(obj[i]) === 'object') {
      const val = `${valStr}${i}.`;
      const objInfo = Object.keys(obj[i]);
      converst(obj[i], result, val);
    }
    else {
      const val = `${valStr}${i}`;
      result[val] = obj[i];
    }
  });

  return result;
}

let values = {}; 
let valStr = '';
const output = converst(entry, values, valStr);
console.log(output);
const entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
};

function isObject (obj) {
    return Object.prototype.toString.call(obj) === '[object Object]'
}

function flatObject(obj, key) {
    if( !isObject(obj) ){
        const o = {};
        o[key] = obj;
        return o;
    }
    const keys = Object.keys(obj);
    const oo = {};
    for (let i=0;i<keys.length;i++) {
        const k = keys[i];
        const o = flatObject(obj[k], key?(key+'.'+k):k);
        Object.assign(oo, o);
    }
    return oo;
}

const o = flatObject(entry);

console.log(o);
var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
}

// 要求转换成如下对象
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function func(obj) {
    let res = {}
    let queue = [{
        prop: "",
        value:obj
    }]

    while (queue.length) {
        let {prop,value} = queue.shift()
        Object.keys(value).forEach(key => {
            if (typeof value[key] === 'object') {
                queue.push({
                    prop: `${prop}${prop && "."}${key}`,
                    value: value[key]
                })
            }else{
                res[`${prop}${prop && "."}${key}`] = value[key]
            }
        })
    }
    return res
}

console.log(func(entry))

使用队列的方式进行广度遍历,性能比递归遍历更好,同时大大减少爆栈的风险

commented
var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
}

// 要求转换成如下对象
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function func(obj) {
    let res = {}
    let queue = [{
        prop: "",
        value:obj
    }]

    while (queue.length) {
        let {prop,value} = queue.shift()
        Object.keys(value).forEach(key => {
            if (typeof value[key] === 'object') {
                queue.push({
                    prop: `${prop}${prop && "."}${key}`,
                    value: value[key]
                })
            }else{
                res[`${prop}${prop && "."}${key}`] = value[key]
            }
        })
    }
    return res
}

console.log(func(entry))

使用队列的方式进行广度遍历,性能比递归遍历更好,同时大大减少爆栈的风险

挺简洁的

var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
}

// 要求转换成如下对象
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function func(obj) {
    let res = {}
    let queue = [{
        prop: "",
        value:obj
    }]

    while (queue.length) {
        let {prop,value} = queue.shift()
        Object.keys(value).forEach(key => {
            if (typeof value[key] === 'object') {
                queue.push({
                    prop: `${prop}${prop && "."}${key}`,
                    value: value[key]
                })
            }else{
                res[`${prop}${prop && "."}${key}`] = value[key]
            }
        })
    }
    return res
}

console.log(func(entry))

使用队列的方式进行广度遍历,性能比递归遍历更好,同时大大减少爆栈的风险

想问一下,当函数实现了尾递归的情况下,就此题来说,队列遍历和递归遍历的性能如何比较,哪一方更具优势?

commented
var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
}

// 要求转换成如下对象
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae'
}

function func(obj) {
    let res = {}
    let queue = [{
        prop: "",
        value:obj
    }]

    while (queue.length) {
        let {prop,value} = queue.shift()
        Object.keys(value).forEach(key => {
            if (typeof value[key] === 'object') {
                queue.push({
                    prop: `${prop}${prop && "."}${key}`,
                    value: value[key]
                })
            }else{
                res[`${prop}${prop && "."}${key}`] = value[key]
            }
        })
    }
    return res
}

console.log(func(entry))

使用队列的方式进行广度遍历,性能比递归遍历更好,同时大大减少爆栈的风险

想问一下,当函数实现了尾递归的情况下,就此题来说,队列遍历和递归遍历的性能如何比较,哪一方更具优势?

说一说我的理解吧,不对的地方还请指正

结论:我认为在实现了尾递归的情况下,队列遍历的性能还是要好一点。

  • 原因:递归之所以会效率不高,是它执行的时候依赖子问题,所以在执行树上,会有很多相同的节点,我认为函数尾调用实现了将那些子问题当做中间变量保存了起来,当做该函数新的参数继续调用,那么它实现就和层次遍历所需要做的操作次数是差不多的。但是尾调用也会开辟新的函数执行环境,但N的数量达到一定程度,频繁创建和销毁函数执行环境也是需要一定时间吧,而队列遍历只要开辟一次函数执行环境。
let entry:object = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}
function handle (entry:object, arr:object, str:string):object {
  for(let index of Object.keys(entry)) {
    // console.log(entry[index])
    if(entry[index] instanceof Object) {
      handle(entry[index], arr, str.concat(`.${index}`))
    } else {

      arr[str.concat(`.${index}`).slice(1)] = entry[index]
      console.log(arr)
    }
  }

  return arr
}
let arr = handle(entry, [], '')

重在参与

function isObj(type) {
  return Object.prototype.toString.call(type) === '[object Object]';
}

function trans(item, prefix = '', result = {}) {
  for (let i in item) {
    let key = `${prefix}${i}`;
    isObj(item[i])
      ? trans(item[i], `${key}.`, result)
      : (result[key] = item[i]);
  }
  return result;
}
commented
const result = Object.create(null)

function transfer(entry, lastKey='') {
    Object.entries(entry).forEach(([key, value]) => {
        if (typeof value === 'object') {
            transfer(value, `${lastKey}.${key}`);
        } else {
            result[`${(lastKey+'.'+key).replace(/^./, '')}`] = value
        }
    })

    return result;
}
/**
 * 将深层次的对象展平
 * @param obj 要展平的对象
 * @param str 传入的键值,第一次不传,用于递归
 * @param res 要返回的对象,第一次不传
 * @example
 * flattenObj({
 *   a: {
 *     b: {
 *       c: 12
 *     }
 *   }
 * }) // return { a.b.c: 12 }
 */
function flattenObj(obj, str, res) {
  res = res || {}
  function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]'
  }
  Object.keys(obj).forEach(key => {
	let k = str ? str + '.' + key : key
    if (isObject(obj[key])) {
      return get(obj[key], k, res)
    } else {
      res[k]= obj[key]
    }
  })
  return res
}
commented

function getObj(entry) {
let out = {}
let keyStr = ''
if (!(entry instanceof Object)) {
return {}
}
Object.keys(entry).forEach((key) => {
split(keyStr, key, entry[key])
})
return out;
}
function split(keyStr, key, valueObj) {
keyStr += ${key}.
if (valueObj instanceof Object) {
Object.keys(valueObj).forEach((item) => {
if (valueObj instanceof Object) {
split(keyStr, item, valueObj[item])
}
})
} else {
out[keyStr.slice(0, keyStr.length - 1)] = valueObj
}
}

这道题是典型的DFS。这里有个技巧,就是将res作为参数传过去,
从而子函数(helper)可以对其进行修改。 这样我们可以不必依赖返回值,
也就避免了很多判断。

function helper(entry, prefix, res) {
  for (const key in entry) {
    if (entry[key] instanceof Object) {
      helper(entry[key], `${prefix}.${key}`, res);
    } else {
      res[`${prefix.slice(1)}.${key}`] = entry[key];
    }
  }
}

function format(entry) {
  const res = {};
  helper(entry, "", res);
  return res;
}

如果大家对数据结构和算法感兴趣,欢迎关注我的仓库

let entry = {
a: {
 b: {
   c: {
     dd: 'abcdd'
   }
 },
 d: {
   xx: 'adxx'
 },
 e: 'ae'
}
};
let  map = {};

function test(obj) {
  Object.keys(obj).forEach((v, k)=> {
    convertV(v, obj[v]);
  });
}

function convertV(key, value) {
  Object.keys(value).forEach((k,i) => {
    if(typeof value[k] != 'object') {
      map[key + '.' + k] = value[k];
    } else if(value[k]){
      convertV(key + '.' + k, value[k]);
    }
  });
}

test(entry);
console.log(map);
const transform = (obj, [...arr]) => {
    let res = {};
    let num = 0;
    for (k in obj) {
      if (num > 0) {
        arr.pop()
      }
      arr.push(k)
      num++;
      if (typeof obj[k] === "object") {
        Object.assign(res, transform(obj[k], arr))
      } else {
        res[arr.join(".")] = obj[k]
      }
    }
    return res
  }

回溯就完事了,感觉这种树形结构都可以暴力回溯解决,虽然效率不高

function fn(o) {
	let res = {};
	let choices = o;
	bt('', choices)
	function bt(trace, choices) {
		if (typeof choices === 'string') {
			res[trace] = choices;//如果路径触达叶端,碰到字符串类型,则获得一个结果
		} else {
                       //否则继续探索路径
			for (let k in choices) {
				trace += k + '.';//前进一步
				bt(trace, choices[k]);递归
				trace = trace.substr(0, trace.length - 2);//后退一步 回溯
			}
		}
	}
	return res;
}

let keyarr = []; const output = {};
function transform(obj) {
for (let k in obj) {
keyarr.push(k);
if (typeof obj[k] === "object") {
transform(obj[k]);
} else {
output[keyarr.join('.')] = obj[k];
keyarr = [keyarr[0]];
}
}
}
transform(entry);
console.log('output', output);

function forMat(entry) {
  let res = {}
  function recur(obj, path = []) {
    if (typeof obj == 'object' && obj != null) {
      Object.keys(obj).forEach(key => {
        recur(obj[key], path.concat(key))
      })
    } else {
      let attr = path.join('.');
      let val = obj;
      res[attr] = val;
    }
  }
  recur(entry);
  return res;
}
function forMat(entry) {
  let res = {}
  function recur(obj, path = []) {
    if (typeof obj == 'object' && obj != null) {
      Object.keys(obj).forEach(key => {
        recur(obj[key], path.concat(key))
      })
    } else {
      let attr = path.join('.');
      let val = obj;
      res[attr] = val;
    }
  }
  recur(entry);
  return res;
}
commented

本质上是递归遍历一棵树:

      function getObj(obj, inKey = '' , res = {}) {
        for (let key in obj) {
          if (typeof obj[key] === 'object') {
            getObj(obj[key], inKey==='' ? (key + '.') : inKey + key + '.', res)
          } else {
            res[ inKey + key  ] = obj[key]
          }
        }
        console.log(res, 'kevinnnnn')
        return res
      }
var entry = {
	a: {
		b: {
			c: {
				dd: 'abcdd'
			}
		},
		d: {
			xx: 'adxx'
		},
		e: 'ae'
	}
}

function transform(obj) {
	let output = {}
	fn(obj)
	return output

	function fn(obj, temp_key = '') { //temp_key--临时存放属性名
		for (let key in obj) {
			if (typeof obj[key] == "object") {
				fn(obj[key], temp_key + key + ".")
			} else {
				output[temp_key + key] = obj[key]
			}
		}
	}
}

console.log(transform(entry)) //打印测试
commented

思路:递归遍历,并用一个栈来保存路径

var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd',
            },
        },
        d: {
            xx: 'adxx',
        },
        e: 'ae',
    },
};

// 要求转换成如下对象
var output = {
    'a.b.c.dd': 'abcdd',
    'a.d.xx': 'adxx',
    'a.e': 'ae',
};

// 递归遍历,并用一个栈来保存路径
function convert(entry) {
    const stack = [];
    const output = {};

    function each(obj) {
        let keys = Object.keys(obj);
        for (let key of keys) {
            stack.push(key); // 入栈
            if (isObject(obj[key])) { // 非末节点,继续递归
                each(obj[key]);
            } else { // 末节点,添加路径到output
                output[stack.join('.')] = obj[key];
            }
            stack.pop(); // 出栈
        }
    }

    each(entry);

    return output;
}

function isObject(o) {
    return Object.prototype.toString.call(o).slice(8, -1) === 'Object';
}

console.log(JSON.stringify(convert(entry), null, 4));
// 输出:
// {
//     "a.b.c.dd": "abcdd",
//     "a.d.xx": "adxx",
//     "a.e": "ae"
// }

var res = {}
function entryObj(entry, keyi = "") {
for (var key in entry) {
if (typeof entry[key] === "object") {
entryObj(entry[key], keyi + key + ".")
} else {
console.log(keyi + key, entry[key])
res[keyi + key] = entry[key]
}

}

}
entryObj(entry)
console.log(res)

整体思路:递归深入获取属性字符串,闭包保存拼接的字符串,每次递归结束则去除遍历的属性值

function changeObj() {
  let attr = []
  const output = {}
  return function checkAttr(obj) {
    for(let k in obj) {
      if(Object.prototype.toString.call(obj[k]) == '[object Object]') {
        attr.push(k)
        checkAttr(obj[k])
        attr.pop()
      } else {
        attr.push(k)
        const prop = attr.join('.')
        output[prop] = obj[k]
        attr.pop()
      }
    }
    return output
  }
}

console.log(changeObj()({
  a: {
    b: {
      c: {
        dd: 'abcdd'
      },
      f: {
        k:'jskw',
        g:'sdaw1'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
  }))
commented
// 递归
function cook(entry, keyStr, res) {
  for (const key in entry) {
    const value = entry[key];
    if (typeof value === 'string') {
      res[keyStr + key] = value;
    } else {
      cook(value, `${keyStr + key}.`, res);
    }
  }
  return res;
}

//bfs
function bfs(entry) {
  const queue = [];
  const res = {};
  if (entry) {
    queue.push({
      keyList: '',
      value: entry
    });
    while (queue.length > 0) {
      const { keyList, value } = queue.shift();
      Object.keys(value).forEach(key => {
        const _key = `${keyList}${keyList && '.'}${key}`;
        const _value = value[key];
        if (typeof _value === 'string') {
          res[_key] = _value;
        } else {
          queue.push({
            keyList: _key,
            value: _value
          });
        }
      });
    }
  }
  return res;
}

// dfs
function dfs(entry) {
	const stack = [];
  const res = {};
  if (entry) {
    stack.push({
      keyList: '',
      value: entry
    });
    while (stack.length > 0) {
      const { keyList, value } = stack.shift();
      const keys = Object.keys(value);
      for(let i=keys.length-1;i>=0;i--){
      	const key = keys[i]
      	const _key = `${keyList}${keyList && '.'}${key}`;
        const _value = value[key];
        if (typeof _value === 'string') {
          res[_key] = _value;
        } else {
          stack.unshift({
            keyList: _key,
            value: _value
          });
        }
      }
    }
  }
  return res;
}

对象的扁平化,没有说数组和空对象怎么处理,那就按默认处理了

function flatten(input) {
    let result = {};
    let re = function(key,obj){
        if(obj instanceof Object && !(obj instanceof Array)){
            let empty = true;
            for(let index in obj){
                empty = false;
                re(key ? `${key}.${index}` : index,obj[index]);
            }
            if(empty && key){
                result[key] = {};
            }
        }else{
            result[key] = obj;
        }
    };
    re('',input);
    return result;
}
commented
function transform(target, keyList=[], result={}) {
      if(typeof target === 'string'){
        result[keyList.join('.')] = target
      }else{
        Object.keys(target).forEach((key)=>{
          transform(target[key], [...keyList, key], result)
        })
      }
      return result
}
var entry = {
	a: {
		b: {
			c: {
				dd: 'abcdd'
			}
		},
		d: {
			xx: 'adxx'
		},
		e: 'ae'
	},
	b: 1
}
console.log('trans(entry): ', trans(entry));
function trans(obj) {
	var output = {};
	temp(obj, output, '');
	function temp(obj, output = {}, key = '') {
		for (var [k, v] of Object.entries(obj)) {
			if (typeof v != 'object') {
				output[key + k] = v;
			} else {
				temp(v, output, key + k + '.');
			}
		}
	};
	return output;
}

遍历树

var entry = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  },
  hh: [{
    aa: 'aa'
  }]
}

function bar2(obj, parentKey) {
  let nodes = []
  Object.keys(obj).forEach(key => {
    let parentKeyNext = parentKey ? `${parentKey}.${key}` : key
    if(typeof obj[key] === 'object') {
      nodes = nodes.concat(bar2(obj[key], parentKeyNext))
    } else {
      nodes.push({
        parentKey: parentKeyNext,
        val: obj[key]
      })
    }
  })
  return nodes
}

console.log(bar2(entry, ''))
/*
[
  { parentKey: 'a.b.c.dd', val: 'abcdd' },
  { parentKey: 'a.d.xx', val: 'adxx' },
  { parentKey: 'a.e', val: 'ae' },
  { parentKey: 'hh.0.aa', val: 'aa' }
]

*/
function flatObj(obj,key='',result={}){
    if(typeof obj !== 'object' || obj===null){
        result[key] = obj
        return
    }

    Object.keys(obj).forEach(k=>{
        flatObj(obj[k], `${key}${key?'.':''}${k}`,result)
    })
    
    return result
}
function flagObj(obj, key = '', res = {}) {
    if (typeof obj != 'object' || !obj) {
        res[key] = obj
    } else {
        for (let k in obj) {
            flagObj(obj[k], `${key ? key + '.' : key}${k}`, res)
        }
    }
    return res
}
commented
const isObj = (a) => typeof a === 'object' && a !== null;
const simpleObj = (obj) => {
    const stack = [obj];
    let current;
    const out = {};
    const _p = Symbol('_p');
    const _pNode = Symbol('_pNode');
    while(stack.length) {
        current = stack.pop();
        if (isObj(current)) {
            Object.keys(current).reverse().forEach(key => {
                stack.push(current[key]);
                if (!isObj(current[key])) {
                    let temp = key;
                    let currentTemp = current;
                    while(currentTemp && currentTemp[_p]) {
                        temp = `${currentTemp[_p]}.${temp}`;
                        currentTemp = currentTemp[_pNode];
                    }
                    out[temp] = current[key];
                } else {
                    current[key][_pNode] = current;
                    current[key][_p] = key;
                }
            });
        }
    }
    return out;
}
var entry = {
    a: {
      b: {
        c: {
          dd: 'abcdd'
        }
      },
      d: {
        xx: 'adxx'
      },
      e: 'ae'
    }
  }
console.log(simpleObj(entry));
function transformObj(obj) {

  const newObj = {}
  const objArray = []
  const topKey = Reflect.ownKeys(obj).shift()
  const firstKey = obj[topKey]
  Reflect.ownKeys(firstKey).forEach((key) => objArray.push(JSON.stringify({ [key]: firstKey[key] })))
  const resultArray = objArray.map((item) => item.replace(/{|"|}|/g, ''))

  resultArray.forEach((item) => {
    const key = item.split(':')
    const value = key.pop()
    newObj[topKey + '.' + key.toString().replace(/,/g, '.')] = value
  })

  return newObj
}

transformObj(entry)

思路是解析为字符串再转换

commented
var entry = {
    a: {
        b: {
            c: {
                dd: 'abcdd'
            }
        },
        d: {
            xx: 'adxx'
        },
        e: 'ae'
    }
}
function change(entry, fkey = '', res = {}){
        if(typeof entry != 'object'){
            res[fkey] = entry
            return
        }
        for(let key in entry){
            if(fkey !== ''){
                change(entry[key], `${fkey}.${key}`, res)
            }else{
                change(entry[key], `${key}`, res)
            }
        }
        return res
    }

console.log(change(entry))
commented

bfs

function flatObj(entry) {
	const queue = Object.entries(entry)
	const res = {}
	while (queue.length) {
		const [key, obj] = queue.pop()
		for (const [k, v] of Object.entries(obj)) {
			if (typeof v !== 'object') {
				res[`${key}.${k}`] = v
			} else {
				queue.push([`${key}.${k}`, v])
			}
		}
	}
	return res
}

bfs的话应该queue.shift(),另外没考虑{a:1}这种情况,按你代码输出是{},简单修改下:

function flatObj(entry) {
  const queue = Object.entries(entry)
  const res = {}
  while (queue.length) {
    const [key, obj] = queue.shift()
    if (typeof obj === 'object') {
      for (const [k, v] of Object.entries(obj)) {
        queue.push([`${key}.${k}`, v])
      }
    } else {
      res[key] = obj
    }
  }
  return res
}
commented
function flatObj(obj) {
  let res = {}
  function dfs(str, obj) {
    if (typeof obj !== 'object') {
      res[str] = obj
      return
    }
    for (let i in obj) {
      let s = str === '' ? i : `${str}.${i}`
      dfs(s, obj[i])
    }
  }
  dfs('', obj)
  return res
}
function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]'
}
function parseToObj(obj, paths = []) {
  if (!isObject(obj)) {
    return paths.length > 0
      ? { [paths.join('.')]: obj }
      : obj
  }
  return Object.keys(obj).reduce((res, key) => {
    Object.assign(res, parseToObj(obj[key], paths.concat(key)))
    return res
  }, {})
}

const testObj = {
  a: {
   b: {
     c: {
       dd: 'abcdd'
     }
   },
   d: {
     xx: 'adxx'
   },
   e: 'ae'
  }
}
console.log(parseToObj(testObj))
function hadnler(entry, str = "", map = {}) {
  Object.keys(entry).forEach(item => {
    const res = entry[item]
    if (typeof res != "object") {
      map[str + item] = res
    } else {
      hadnler(res, str + item + ".", map)
    }
  })
  return map
}
      function convert(entry) {
        let obj = {};
        helper(entry, "", obj);
        return obj
      }
      function helper(entry, pKey, obj) {
        for (const key in entry) {
          if (typeof entry[key] == "string") {
            let keyname = `${pKey}${key}`;
            obj[keyname] = entry[key];
          } else {
            helper(entry[key], `${pKey}${key}.`, obj);
          }
        }
      }
commented
  const trans = (entry) => {
    let outPut = {}
    const run = (entry, name = '') => {
      const keys = Object.keys(entry)
      for(let key of keys) {
        let v = entry[key]
        let t = name ? `${name}.${key}` : key
        if(typeof v !== 'object') {
          outPut[t] = v
        }else {
          run(v, t)
        }
      }      
    }
    run(entry)
    return outPut
  }
  trans(entry)
commented
function format(entry) {
    const result = {}

    recur(entry)

    return result

    function recur(obj, path = []) {
        Object.keys(obj).forEach((key) => {
            const value = obj[key]

            if (typeof value === 'object') {
                recur(value, [...path, key])
            } else {
                const id = path.length ? `${path.join(".")}.${key}` : key
                
                result[id] = value;
            }
        })
    }
}

var entry = {
  a: {
    b: {
      c: {
        dd: "abcdd",
      },
    },
    d: {
      xx: "adxx",
    },
    e: "ae",
  },
};

console.log("debug-", format(entry));
function objTransitionStr(entry) {
  const res = {};
  const _helper = (obj, key = "") => {
    if (typeof obj !== "object") {
      res[key.slice(1)] = obj;
      return;
    }
    const keys = Object.keys(obj);
    const values = Object.values(obj);
    for (let i = 0; i < keys.length; i++) {
      _helper(values[i], `${key}.${keys[i]}`);
    }
  };
  _helper(entry);
  return res;
}
// 递归解法
var entry = {
  a: {
    b: {
      c: {
        dd: 'abcdd'
      }
    },
    d: {
      xx: 'adxx'
    },
    e: 'ae'
  }
}

// 要求转换成如下对象
var output = {
  'a.b.c.dd': 'abcdd',
  'a.d.xx': 'adxx',
  'a.e': 'ae'
}

function transform(entry) {
  let output = {};
  function _inner(target, path) {
    if (target === null || typeof target !== 'object') {
      return output[path] = target;
    }
    Reflect.ownKeys(target).forEach(key => {
      _inner(target[key], path ? `${path}.${key}` : `${key}`);
    });
  }
  _inner(entry, '');
  return output;
}

console.log(transform(entry));
function flatObj(obj) {
  var res = {}

  function dfs(obj, preKey = '') {
    Reflect.ownKeys(obj).forEach(key => {
      var keyName = `${preKey}${key}`
      if(typeof obj[key] === 'object') {
        dfs(obj[key], keyName + '.')
      } else {
        res[keyName] = obj[key]
      }
    })
  }

  dfs(obj)
  
  return res
}

flatObj(entry)
commented
/**
 * 1. 对象扁平化
 */
function flat(obj, pre = '', result = {}) {
  Object.keys(obj).forEach((v) => {
    const key = `${preKey}${v}`
    if (typeof obj[v] === 'object') {
      flat(obj[v], `${key}.`, result)
    } else {
      result[key] = obj[v]
    }
  })
  return result
}

const flatResult = flat(entry, '', {})
console.log(flatResult)

/**
 * 2. 扁平化对象重组
 */
function restore(obj) {
  let result = {}

  Object.keys(obj).forEach((v) => {
    const list = v.split('.')
    const value = obj[v]
    list.reduce((res, item, index) => {
      if (index === list.length - 1) {
        res[item] = value
      } else {
        res[item] = res[item] ? res[item] : {}
      }
      return res[item]
    }, result)
  })
  return result
}

console.log(JSON.stringify(restore(flatResult), null, 4))
commented

const find666 = (entry) => {

let map = {}
//递归方式
let func = (val, pname) => {
  for (key in val) {
    let kname = `${key}`
    if (pname) {
      kname = `${pname}.${key}`
    }
    if (typeof val[key] === 'object') {
      func(val[key], kname)
    } else {
      map[kname] = val[key]
    }
  }
}
func(entry)

}

利用构造函数

function toObject(entry, output = {}, k_name = '') {
  for (let key in entry) {
    if (entry[key].constructor == Object){
      toObject(entry[key], output, k_name ? `${k_name}.${key}` :  `${key}`);
    }else{
      output[`${k_name}.${key}`] = entry[key];
    }
  }
  return output
}
toObject(entry)
commented

回溯解决

var entry = {
a: {
b: {
  c: {
    dd: 'abcdd'
  }
},
d: {
  xx: 'adxx'
},
e: 'ae'
}
}

function trans(obj) {
    const result = {};
    for (let k in obj) {
        backtrace([k])
    }
    function backtrace(trace) {
        let o = obj;
        for (let i = 0; i < trace.length; i++) {
            o = o[trace[i]]
        }
        if (typeof o !== 'object') {
            result[trace.join(',')] = o;
            return;
        }
        for (let k in o) {
            trace.push(k);
            backtrace(trace);
            trace.pop();
        }
    }
    return result;
}
console.log(trans(entry))

参考: Rain120/Web-Study#18

function flatten(obj) {
    var res = {};

    function flat(obj, key) {
        if (obj === null || Object(obj) !== obj) {
            res[key] = obj;
        } else if (Array.isArray(obj)) {
            var len = obj.length;
            if (len < 1) {
                res[key] = [];
                return;
            }

            for (var i = 0; i < len; i++) {
                flat(obj[i], key ? `${key}[${i}]` : key + '');
            }
        } else {
            for (var k in obj) {
                flat(obj[k], key ? `${key}.${k}` : k);
            }
        }
    }

    flat(obj, '');
    return res;
}

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

flatten(obj)
commented
var entry = {
  a: {
   b: {
     c: {
       dd: 'abcdd'
     }
   },
   d: {
     xx: 'adxx'
   },
   e: 'ae'
  }
}
function flatObj(obj, preKey = '') {
  let res = {};
  for (let key in obj) {
    let value = obj[key];
    let newKey = preKey ? `${preKey}.${key}` : key;
    if (typeof obj[key] === 'object') {
      flatObj(obj[key], newKey)
    } else {
      res[newKey] = value;
    }
  }
}
console.log(flatObj(entry))

function(tree){ const res = new Map() function main(tree, preKey = ''){ const keys = Object.keys(tree) for(let i = 0; i < keys.length; i++){ if(typeof tree[keys[i]] === 'object'){ main(tree[keys[i]], preKey ? ${preKey}.${keys[i]} : keys[i]) }else{ res.set(${preKey}.${keys[i]}, tree[keys[i]]) } } } main(tree) return res }