背景描述:

一般我们在遇到这样的JSON时:

const json = {
  user: {
    posts: [
      { title: 'A',
        comments: [ 'Hello!', 'Interesting...' ] 
      },
      { title: 'B',
        comments: [ 'Ok' ] 
      },
      { title: 'C',
        comments: []
      }
    ],
    comments: [...]
  }
}

需要取出里面的值得这样写:
json.user &&
json.user.posts &&
json.user.posts[0] &&
json.user.posts[0].comments
一般思路:对于取不确定层次的深层值,我们首先想到的是使用递归函数,我要获取的值就需要一个路径来表示,路径可以用数组来标记,如果是数组,我们还需要一个索引来指引,然后我们可以通过递归逐层取值,当路径参数path长度为0时,认为取值完毕,返回结果;
方法一:使用递归函数
function isJson(obj){
  var isjson = typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length;
  return isjson;
}
var getJSONValue = (function f(path, obj){
  //确保初始值为json
  if(arguments.length === 2 && !isJson(obj)){
    return console.log("第二个参数必须是一个JSON对象")
  }
  if(arguments.length === 2 && path.length === 0){
    return console.log("数组参数长度不能为0")
  }
  if (arguments.length < 2){
    return console.log("需要两个参数");
  }
  if(!Array.isArray(path)){
    return console.error("第一个参数请使用数组");
  }else if(arguments.length === 2 && path.length === 0){
    return console.error("数组参数长度不能为0")
  }
  //获取值
  var result = obj[path[0]];
  path.shift();
  if(!path.length){
    return result;
  }else{
    return f(path,result,false);//增加false参数以保证只在首次递归判断类型
  }
});

var value = getJSONValue(['user','posts','comments','details','1'],json);//不输出结果且阻塞下面运行,控制台报错"Cannot read property '1' of undefined"
var value = getJSONValue(['user','posts','comments',1],json);//输出结果:“Interesting”(假定上面代码没有阻塞)
  
以上方法通用性不高,限制了第二个参数必须为json才能使用,且没有容错机制,遇到错误会报错。
于是继续优化:
方法二:使用while
var getJSONValue = function(path, obj){
  if(!Array.isArray(path)){
    return console.error("第一个参数请使用数组形式");
  }
  var len = path.length;
  var i = 0;
  var str;
  while(len){
    str = path[i];
    obj = obj[str];
    // console.log('第'+(i+1)+'次取到',obj,'参数是',path[i])
    if((obj === undefined || obj === null) && len !==0){
      console.log('取值有错误,请确认传入的第'+(i+1)+'个参数“'+path[(i)]+'”是否正确')
      return null
    }
    i++;
    len--;
  }
  return obj;
};
var value = getJSONValue(['user','posts','comments','details','1'],json);//输出结果:null 控制台输出为:"取值有错误,请确认传入的第4个参数“details”是否正确"
var value1 = getJSONValue(['user','posts','comments',1],json);//输出结果:“Interesting”
方法三:使用for循环
var getJSONValue = function(path, obj){
  if(!Array.isArray(path)){
    return console.error("第一个参数请使用数组");
  }
  var len = path.length;
  for(var i = 0; i<len ;i++){
    obj = obj[path[i]];
    if(obj === undefined || obj === null){
      return null
    }
  }
  return obj
};

for使用大篇幅的底层运算描述,从而掩盖了coder的本质用意。

相比之下foreach可读性要强得多。

从而得出如下取出多层级JSON最深处的值的最优雅的方式:

方法四:使用forEach
var getJSONValue = function(path, obj){
  path.forEach(function(el){
    try{
      obj = obj[el]
    }catch(e){
      obj = null
    };
  });
  return obj
};