【问题标题】:How to handle "null" and "undefined" values when destructuring function arguments解构函数参数时如何处理“null”和“undefined”值
【发布时间】:2019-04-11 18:23:09
【问题描述】:
function createElement (type, { attrs = {}, children = [] }) {
 if (Object.prototype.toString.call(arguments[1]) !== '[object Object]') { 
   throw Error('The options argument must be an object'); 
 }

 return {
  type,
  attrs,
  children
 }
}

我有一个函数,它接受两个参数:一个字符串和一个对象。在函数声明中,我通过解构解包对象的值。

当谈到确保第二个参数是一个对象时,我知道我可以做这个检查:Object.prototype.toString.call(arguments[1] !== 'object Object')

但如果nullundefined 作为参数传递,则会出现此错误:Uncaught TypeError: Cannot destructure property 'attrs' of 'undefined' or 'null'.。这是可以理解的,因为nullundefined 不能被强制转换为对象。我能做些什么来防止这种情况发生?

如果 arraynumber 等作为第二个参数传递,则不会引发错误,因为它们可以被强制转换,然后我可以在函数体中处理这些值。在处理nullundefined 时,函数中的代码永远不会执行。

// expected behaviour
createElement('div', []); // Uncaught Error: The options argument must be an object
createElement('div', function(){}); // Uncaught Error: The options argument must be an object
createElement('div', false); // Uncaught Error: The options argument must be an object
createElement('div', new Date()); // Uncaught Error: The options argument must be an object
createElement('div', 4); // Uncaught Error: The options argument must be an object

// unwanted behaviour
createElement('div', null); // Uncaught TypeError: Cannot destructure property `attrs` of 'undefined' or 'null'
createElement('div', undefined); // Uncaught TypeError: Cannot destructure property `attrs` of 'undefined' or 'null'

编辑以提供最终解决方案:阅读 cmets 后,似乎唯一的解决方案是允许引发异常或解构函数体中的代码并处理错误。这是我选择的解决方案:

createElement (type, opts) {
  if (arguments[1] !== undefined && Object.prototype.toString.call(opts) !== '[object Object]') { 
    throw Error('The options argument must be an object'); 
  }

  const { attrs = {}, children = [] } = opts || {};

  return {
    type,
    attrs,
    children
  }
}

【问题讨论】:

  • 请添加一些调用示例和想要的结果。
  • 如果你想处理错误为什么不尝试捕获?
  • 完成 - 感谢您强调这一点。
  • @JRK try/catch 将不起作用,因为在我描述的场景中,函数体中的代码永远不会执行。
  • 你为什么还要提防这个?你想抛出一个异常,对吧?

标签: javascript destructuring


【解决方案1】:

这个函数可能做你想要的(允许nullundefined第二个参数被默认):

function createElement (type, obj) {
  const arg1 = arguments[1];
  if (arg1 !== null && arg1 !== undefined &&
      Object.prototype.toString.call(arg1) !== '[object Object]') {
    throw Error('The options argument must be an object'); 
  }
  let { attrs = {}, children = [] } = obj || {}
  return {
    type,
    attrs,
    children
  }
}

此功能还可以修复您的对象测试以正常工作。

[更新]

如果你确实希望null 也抛出非对象错误,你可以使用这个:

function createElement (type, obj) {
  const arg1 = arguments[1];
  if (arg1 !== undefined &&
      Object.prototype.toString.call(arg1) !== '[object Object]') {
    throw Error('The options argument must be an object'); 
  }
  let { attrs = {}, children = [] } = obj || {}
  return {
    type,
    attrs,
    children
  }
}

【讨论】:

  • 如果您希望 null 也抛出错误,我已经更新了我的答案以提供替代答案。
  • 是的,我更喜欢这个,而不是我确定的最终解决方案。
【解决方案2】:

使用默认值。

function createElement(type, { attrs, children } = {}) {
  return {
    type,
    attrs,
    children
  }
}

console.log(createElement("foo"));
console.log(createElement("foo", undefined));

【讨论】:

  • 如果您将nullundefined 作为第二个参数传递,您将收到与我收到的相同的错误。
  • null 是,未定义 - 否。
  • 是的,你是对的。谢谢。现在留下null
  • 为了防范null,我认为您需要基于 Code Maniac 的响应,并在检查 if (obj === null) 后在函数体内进行重组。我不相信有一个巧妙的技巧可以在函数签名中处理它。但也许 StackOverflow 会证明我错了。
  • @mbojko 你可以使用this 之类的东西,但这太难了
【解决方案3】:

您可以推迟解构并提前检查。

function createElement (type, object) {
   if (!object || typeof object !== 'object' || Array.isArray(object)) { 
       throw Error('The options argument must be an object'); 
   }
   var { attrs = {}, children = [] } = object;
   return { type, attrs, children };
}

【讨论】:

  • 是的,我想我会在函数体中进行解构。但是,我尝试了您的解决方案并注意到数组仍然通过了检查,这是我不希望它们通过的。我可能会坚持使用Object.prototype.toString.call(arg1) !== '[object Object]' 作为我的一站式检查,因为它可以处理所有事情,包括nullundefined
【解决方案4】:

我会建议在函数内部解构而不是在函数定义中这样做

function createElement (type, obj) {
  let { attrs = {}, children = [] } = obj || {attrs:undefined,children:undefined}
  return {
    type,
    attrs,
    children
  }
}


console.log(createElement('some type',undefined))

【讨论】:

  • 昨晚做了一番研究,也得出了这个结论。但我也很想知道是否有另一种处理方式。我在研究不同框架使用 virtual-dom 的方式时遇到了这个功能。我注意到它们都没有以这种方式破坏函数参数。也许这就是为什么?
  • @CarlMungazi 是的,你可以做一些骇人听闻的事情,但最好保持代码干净和清晰,以便易于维护,你可以看到这些1 destructuing2 paseint while destructuring
  • 谢谢。这个答案读起来很有趣,尤其是老生常谈的答案和这个:[latitude, longitude] = ['17.0009','82.2108'].map(Number);
【解决方案5】:
In case when object is undefined use {property1,property2}={}

In case when property is undefined use {property1={},property2={}}

In your case object is undefined so below code will be used:

function createElement (type, { attrs = {}, children = [] }={}) {
 if (Object.prototype.toString.call(arguments[1]) !== '[object Object]') { 
   throw Error('The options argument must be an object'); 
 }

 return {
  type,
  attrs,
  children
 }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多