为啥对 fetch 响应使用解构赋值会导致 .json() 方法消失?

Posted

技术标签:

【中文标题】为啥对 fetch 响应使用解构赋值会导致 .json() 方法消失?【英文标题】:Why does using a destructuring assignment on a fetch response cause the .json() method to disappear?为什么对 fetch 响应使用解构赋值会导致 .json() 方法消失? 【发布时间】:2019-07-15 23:16:37 【问题描述】:

感谢您抽出宝贵时间查看此内容。我遇到了一些意外的行为,在使用 aws lambda 时我无法弄清楚。

我正在执行 fetch,然后根据它是成功还是失败来做一些不同的事情,如果一切都是 kosher,最终我想使用 fetch.json() 方法。我正在使用 await 使我的 lambda 处理程序的内部“同步”。

当我将获取的结果分配给一个变量然后检查它时,一切都很好。但是我喜欢整洁的代码,所以我决定使用解构赋值,突然事情就开始崩溃了。

为了证明我的困惑,我包含了一个代码 sn-p,它复制了问题并显示了五种不同的东西 - 前两个有效,其余的中断。

在第三个例子中,“r”是一个空对象。其余操作员打破了它,我不明白。它是在制作一个新对象并拒绝复制属性吗?解构发生时属性不存在吗?如果是这样,为什么 ok 和 status 会正确解构?

四只是三问题的简化示例。

Five也让我很困惑,因为我能够得到json方法,但是当我尝试执行它时它会抛出一个非法调用异常。

片段如下:

const one = async () => 
  const r = await fetch('https://reqres.in/api/users?page=2');
  console.log(await r.json());


const two = async () => 
  const r = await fetch('https://reqres.in/api/users?page=2');
  const  ok  = r;
  console.log(await r.json());
  console.log(ok);


const three = async () => 
  const  ok, status, ...r  = await fetch('https://reqres.in/api/users?page=2');
  try 
    console.log(await r.json());
   catch (e) 
     console.log(e);
     console.log(ok);
     console.log(status);
     console.log(r);
  


const four = async () => 
  const  ...r  = await fetch('https://reqres.in/api/users?page=2');
  console.log(r);


const five = async () => 
  const  json  = await fetch('https://reqres.in/api/users?page=2');
  try 
    console.log(await json());
    catch (e) 
    console.log(e);
    console.log(json);
   


[one, two, three, four, five].forEach(f => f());

再次感谢您的宝贵时间。

注意:由于某种原因,SO 将异常记录为空对象,所以这里有一个小提琴:https://jsfiddle.net/ygbm6kwq/4/

编辑:在示例二中意外遗漏了一行,更新了 sn-p 和 fiddle。

【问题讨论】:

I'm using await to make the interior of my lambda handler "synchronous." await 不会使代码同步。 [one, two, three, four, five].forEach 在这里你循环了 5 个 promise,而不是 5 个 promise 的结果。 @LucaKiebel 我正在使用扩展运算符。 @Keith 这就是我将“同步”放在引号中的原因。我知道它实际上不是同步的。我试图挥手与问题无关的东西。很抱歉有任何混淆。 (当 sn-p 控制台未准确显示信息时,您可以建议问题查看者改为查看他们实际的浏览器控制台 - 尽管 sn-p 运行在另一个域) 请注意,在您的第一个示例中,如果您运行r instanceof Response,您将得到true。如果您使用扩展运算符,情况就不会如此。因为扩展运算符相当于这样做:Object.assign(, r)。而在Object.assign 的第一个参数中的那个空对象不是Response 的实例 【参考方案1】:

其余运算符打破了它,我不明白。它是在创建一个新对象并拒绝复制属性吗?

是的,正是如此。属性 rest 元素创建一个新对象并将所有剩余的可枚举 own 属性复制到其中。但是新的r 将是一个普通对象,而不是Response 实例,因此它不会继承.json() 方法。

我能够获取json方法,但是当我尝试执行它时它会抛出一个非法调用异常。

是的,这是一个方法。因此,必须在实例上调用它,并使用正确的 this 值。你可以在技术上做到

const response = await fetch('https://reqres.in/api/users?page=2');
const  json  = response;
console.log(await json.call(response));

甚至没有解构,Response.prototype.json.call(response),但这没有意义。

【讨论】:

99% 的路程。 json 不是可枚举属性,因为它是响应原型链的一部分吗? @JSager 问题不在于可枚举性(我不知道它们是否可枚举,我只是猜想它们不是),而是.json 是一个继承的 财产。 好的,谢谢。我在那里有一些阅读要做,但这澄清了这个谜。我知道我快到了,但“为什么”的最后一步让我望而却步。这就是我从不写课程的原因:)

以上是关于为啥对 fetch 响应使用解构赋值会导致 .json() 方法消失?的主要内容,如果未能解决你的问题,请参考以下文章

ES6 解构赋值

使用对象解构赋值时,为啥将属性“名称”转换为字符串? [复制]

ES6学习-4 解构赋值数组的解构赋值

ES6 变量的解构赋值

当组件中有解构赋值时,为啥默认道具不能防止 TypeError?

js对象浅拷贝有解构赋值,assign2个方法吗?