跳至內容
Astera Technology

匯入成員為何改了物件原型?

以自有資料屬性建立物件,來源成員名稱照作資料保留。

下載完整個案資料及參考答案 ↓

先核來源與已訂規則

本例原 JSON 有自有 __proto__ 成員。用 Object.assign 填普通空物件,會走目標設值行為,可能改它的原型。更正以 Object.fromEntries 建自有資料屬性。

已填假設輸入
紀錄輸入 JSON
原例輸入{"raw":"{\"__proto__\":{\"mark\":\"changed\"},\"label\":\"A\"}"}
下載可編輯 CSV ↓

比較兩條實際路徑

錯目標丟自有成員,卻繼承 changed 標記。更正有 __proto__、label 自有鍵,沒有繼承標記;例子只涉及新建本地目標。

錯誤與更正路徑的輸出
路徑輸出 JSON
錯誤路徑{"ownKeys":["label"],"prototypeMark":"changed","ownData":[["label","A"]]}
更正路徑{"ownKeys":["__proto__","label"],"prototypeMark":null,"ownData":[["__proto__",{"mark":"changed"}],["label","A"]]}
下載可編輯 CSV ↓
本地 Node.js 程序:22.23.3 或 24.14.1
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};

import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
    const parsed=JSON.parse(i.raw);const object=corrected?Object.fromEntries(Object.entries(parsed)):Object.assign({},parsed);
    return {ownKeys:Object.keys(object),prototypeMark:Object.getPrototypeOf(object).mark??null,ownData:Object.entries(object)};
  };
const cases=[{"label":"misleading base","input":{"raw":"{\"__proto__\":{\"mark\":\"changed\"},\"label\":\"A\"}"},"expected":{"ownKeys":["label"],"prototypeMark":"changed","ownData":[["label","A"]]},"corrected":false},{"label":"corrected base","input":{"raw":"{\"__proto__\":{\"mark\":\"changed\"},\"label\":\"A\"}"},"expected":{"ownKeys":["__proto__","label"],"prototypeMark":null,"ownData":[["__proto__",{"mark":"changed"}],["label","A"]]},"corrected":true},{"label":"constructor remains own data","input":{"raw":"{\"constructor\":\"C\"}"},"expected":{"ownKeys":["constructor"],"prototypeMark":null,"ownData":[["constructor","C"]]},"corrected":true},{"label":"text proto member remains data","input":{"raw":"{\"__proto__\":\"P\"}"},"expected":{"ownKeys":["__proto__"],"prototypeMark":null,"ownData":[["__proto__","P"]]},"corrected":true}];
for(const test of cases){
  const actual=run(test.input,test.corrected);
  assert.deepEqual(actual,test.expected,test.label);
  console.log(test.label,actual);
}
下載可執行例子 ↓

下次載入前核邊界

constructor 及文字值 __proto__,在更正路徑都照作自有資料。

可編輯邊界紀錄及預期輸出
情況輸入 JSON預期輸出 JSON
自有 constructor 成員{"raw":"{\"constructor\":\"C\"}"}{"ownKeys":["constructor"],"prototypeMark":null,"ownData":[["constructor","C"]]}
proto 成員為文字值{"raw":"{\"__proto__\":\"P\"}"}{"ownKeys":["__proto__"],"prototypeMark":null,"ownData":[["__proto__","P"]]}
下載可編輯 CSV ↓

已收來源的 __proto__ 應否消失?

查看參考答案

不應,此約定要保成自有成員,同時不讓它取代物件原型。

相關資源