JSON.stringify() 丢失嵌套属性我知道原因但不知道答案

JSON.stringify() losing nested properties I know the cause but don't know the answer

我有 2 个对象:

const subscription = {
 endpoint: "dfksjfklsjkld",
 keys: {
    pkey: "dfsfsdfsf",
    auth: "dfsdfsdfsd"
 }
};

const extra = {
  email: "dfsdfs",
  ip:"231342.342.342.34"
};

我想将 extra 对象放入订阅中,所以它看起来像:

subsciption = {
 endpoint: ......
 keys: {...},
 extra: {
    email:....,
    ip: .....
 }
}

然后我需要将其作为 http 请求的主体发送:

const response = await fetch(url, {
  method: "PUT", 
  mode: "no-cors",
  cache: "no-cache",
  credentials: "same-origin", 
  headers: {
    "Content-Type": "application/json",
  },
  redirect: "follow", 
  referrerPolicy: "no-referrer", 
  body: JSON.stringify(subscription), 
});

但是我发现无论我做什么,我总是在JSON.stringify()的过程中丢失额外的属性内部订阅。

我知道原因:因为extra对象中的属性是不可枚举的。

到目前为止,我已经尝试过:

1.use 点差:

newSub = {
  ...subscription,
  ...extra
}

但是newSub的内容会和extra一模一样,subscription的属性都丢失了

2.add toJSON函数到我生成额外对象的地方

getExtra() : {    
.......
return {
      city: ipObject.city,
      country: ipObject.country_name,
      ip: ipObject.ip,
      lat: ipObject.latitude,
      lng: ipObject.longitude,
      org: ipObject.org,
      postal: ipObject.postal,
      region: ipObject.region,
      toJSON: () => {
        return this;
      }
    };    
}

完全没有效果。

我在这里附上我的代码:

async function updateSubscription() {
  try {
    const allowed = await askForPermission();
    if (!allowed) return;

    let subscription = await getSubscription();
    if (!subscription) return;

    // email
    const email = getEmail();
    if (!email || !validateEmail(email)) {
      alert("huh...so how are you going to receive notifications?");
      return;
    }

    // ip
    let ipObject = await getIP();
    let extra = {};
    if (ipObject) {
      ipObject.email = email;
      extra = ipObject;
    } else {
      extra.email = email;
    }

    console.log("extra: ", extra);

    // var newSubscription = Object.assign({}, subscription, {extra});
    // const newSubscription = {
    //   ...subscription,
    //   extra
    // };
    let newSubscription = subscription;
    newSubscription["extra"] = extra;
    console.log("new subscription1: ", newSubscription);
    console.log("new subscription1 stringified: ", JSON.stringify(newSubscription));

    const successful = await saveRegistration(newSubscription);

    if (successful) alert("you have successfully subscribed to the DC monitor");
    else alert("shit happens, try it later");
  } catch (err) {
    console.log("updateSubscription() failed: ", err);
  }
}

async function getSubscription() {
  console.log("try to get subscription");
  try {
    const swRegistration = await navigator.serviceWorker.ready;
    const pushSubscription = await swRegistration.pushManager.getSubscription();
    console.log("pushSubscription: ", pushSubscription);
    return pushSubscription;
  } catch (error) {
    console.log("getSubscription() error: ", error);
    return null;
  }
}

更新

1.Tried 1 种方法:

var newSubscription = Object.assign({}, subscription, {extra});
console.log("subscription: ", newSubscription);
console.log("subscription stringified: ", JSON.stringify(newSubscription));

这里是输出截图:

2.Also这个:

 const newSubscription = {
      ...subscription,
      extra
    };
    console.log("new subscription: ", newSubscription);
    console.log("new subscription stringified: ", JSON.stringify(newSubscription));

这是输出的屏幕截图:

3.with字符串索引方式:

let newSubscription = subscription;
    newSubscription["extra"] = extra;
    console.log("new subscription1: ", newSubscription);
    console.log("new subscription1 stringified: ", JSON.stringify(newSubscription));

如果变异 subscription 没问题,你可以使用:

subscription['extra'] = extra;

如果你想要一个新对象,你可以使用:

const subscriptionObject = Object.assign({}, subscription, { extra });

编辑: 由于您使用的是 Push APIPushSubscription 中的属性不可枚举。所以 subscription 对象的行为不像普通对象,这就是建议的方法没有奏效的原因。

但是,您可以先使用 PushSubscription.toJSON() 序列化推送订阅以将其序列化为“普通”对象,然后使用建议的技术之一:

subscriptionObject = Object.assign({}, subscription.toJSON(), { extra });

你试过了吗

newSub = {
  ...subscription, extra
}

在这种情况下你不需要额外传播。

sub = JSON.stringify(newSub) should result in: "{"endpoint":"dfksjfklsjkld","keys":{"pkey":"dfsfsdfsf","auth":"dfsdfsdfsd"},"extra":{"email":"dfsdfs","ip":"231342.342.342.34"}}"

你为什么不使用像 属性

这样的简单赋值
let subscription = {..}
const extra = {..}

然后

subscription.extra = extra;

它应该有效

这有点 hacky,但看起来我们不知道 PushSubscription 对象是如何实现的,它可能不会像您期望的那样工作...

...但是它似乎使用自己的方法(根据其 API)正确转换为 JSON,因此您可能想尝试这样的操作:

const newSub = { ...JSON.parse(subscription.toJSON()), extra };

因此,将其转换为 JSON(使用 Push API 中的 toJSON 方法)并返回“正常”javascript 对象,-然后-添加 extra 属性。