英文:
For an instance field which is an array value, how does one handle additional tasks whenever the array mutates by e.g. pushing into or splicing it?
问题
set
访问器不会在通过 push
等方式改变 Crumbs
类属性值时生效。
我尝试使用 set
语法创建一个类属性,我期望它处理额外的 sessionStorage
任务。但每次我将一个项推入数组时,set
访问器不会生效。
到目前为止,我想出的代码如下...
class Environment {
constructor() {
this.Crumbs = [];
}
set Crumbs(value) {
// debugger;
sessionStorage.setItem('_crumbs', JSON.stringify(value));
}
get Crumbs() {
// debugger;
let result = [];
if (sessionStorage.getItem('_crumbs') !== null) {
result = JSON.parse(sessionStorage.getItem('_crumbs'));
} else {
sessionStorage.setItem('_crumbs', JSON.stringify([]));
}
return result;
}
}
let env = new Environment();
let _metricId = 6;
let _concept = 'Back orders';
let _crumb = {
MetricId: _metricId,
Concept: _concept,
};
env.Crumbs.push(_crumb);
英文:
The set
accessor does not take place whenever one does mutate the Crumbs
class property value by e.g push
ing into it.
I'm trying to create a class property via set
syntax which I expect to handle an additional sessionStorage
task. But every time, I'm going to push an item into the array, the set
accessor does not take place.
The code I came up with so far is as follows ...
class Environment {
constructor() {
this.Crumbs = [];
}
set Crumbs(value) {
// debugger;
sessionStorage.setItem('_crumbs', JSON.stringify(value));
}
get Crumbs() {
// debugger;
let result = [];
if (sessionStorage.getItem('_crumbs') !== null) {
result = JSON.parse(sessionStorage.getItem('_crumbs'));
} else {
sessionStorage.setItem('_crumbs', JSON.stringify([]));
}
return result;
}
}
let env = new Environment();
let _metricId = 6;
let _concept = 'Back orders';
let _crumb = {
MetricId: _metricId,
Concept: _concept,
};
env.Crumbs.push(_crumb);
答案1
得分: 1
以下是翻译好的内容:
None of the mutating array methods will ever activate the OP's setter. This only happens for direct assignments to Crumbs
.
但是,由于 OP 希望通过任何数组操作来处理数组更改的最小努力,所以 OP 需要将 proxyfied 数组公开为 Environment
实例的 crumbs
属性。代理的 handler
配置 必须仅实现 set
陷阱,并且还需要专门处理代理的 length
属性的更改,其中可以通过存储本地/内部 crumbList
镜像来保持存储的 crumbs
值保持最新。
class Environment {
constructor() {
// - 总是与 `this.crumbs` 代理对象的“最新”镜像。
// - 从 `sessionStorage` 初始化或为空数组。
const crumbList =
JSON.parse(sessionStorage.getItem('crumbs') ?? null) ?? [];
this.crumbs = new Proxy(crumbList, {
set(obj, prop, value) {
// debugger;
// console.log({ obj, prop, value });
// 继续进行 `set`。
const result = Reflect.set(...arguments);
if (prop === 'length') {
// - 立即将最新的 `crumbList` 镜像存储到 `sessionStorage`。
sessionStorage.setItem('crumbs', JSON.stringify(crumbList));
}
return result;
}
});
// - 由于可以访问 `this.crumbs` 代理进行任何(变异)数组操作,
// 可以考虑自定义的 `valueOf` 实现,该实现返回代理对象的最新镜像状态的浅拷贝。
Object.defineProperty(this.crumbs, 'valueOf', {
value: function valueOf() {
return [...crumbList];
},
});
}
}
const env = new Environment;
const metricId = 6;
const concept = 'Back orders';
const crumb = { metricId, concept };
env.crumbs.push(crumb);
env.crumbs.push('foo');
env.crumbs.push('bar');
env.crumbs.length = 5;
env.crumbs.push('baz');
env.crumbs.push('biz');
env.crumbs.length = 9;
console.log('... 在初始 `push` 操作和 `crumbs.length` 更改后 ...');
console.log({ "current value": env.crumbs });
env.crumbs.shift();
env.crumbs.pop();
env.crumbs.pop();
console.log('... 在 `shift` 和 `pop` 操作后 ...');
console.log({ "current value": env.crumbs });
env.crumbs.splice(1, 3);
console.log('... 在最后的 `splice` 操作后 ...');
console.log({ "current valueOf()": env.crumbs.valueOf() });
console.log({"当前存储的 JSON": sessionStorage.getItem('crumbs') });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
// 用于 SO 特定堆栈片段的模拟
// 由于策略和环境不允许原始存储访问。
const sessionStorage = (function () {
// https://developer.mozilla.org/en-US/docs/Web/API/Storage
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
const storage = new Map;
function key(int) {
return [
...storage.keys()
][parseInt(int, 10)];
}
function setItem(key, value) {
return storage.set(String(key), String(value));
}
function getItem(key) {
return storage.get(String(key));
}
function removeItem(key) {
return storage.delete(String(key));
}
function clear() {
return storage.clear();
}
return {
get length() {
return storage.size;
},
key,
getItem,
setItem,
removeItem,
clear,
};
}());
</script>
英文:
None of the mutating array methods will ever activate the OP's setter. This only happens for direct assignments to Crumbs
.
But since the OP wants to go with the least effort of handling array changes by any array operation, the OP needs to expose a proxyfied array as an Environment
instance's crumbs
property. The proxy's handler
configuration has to implement just the set
trap, and moreover needs to specifically handle just the change to the proxy's length
property, where one would keep the stored crumbs
value up to date by storing the local/internal crumbList
mirror.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
class Environment {
constructor() {
// - always "up to date" mirror of the `this.crumbs` proxy object.
// - initialized either from `sessionStorage` or as empty array.
const crumbList =
JSON.parse(sessionStorage.getItem('crumbs') ?? null) ?? [];
this.crumbs = new Proxy(crumbList, {
set(obj, prop, value) {
// debugger;
// console.log({ obj, prop, value });
// proceed with `set`.
const result = Reflect.set(...arguments);
if (prop === 'length') {
// - immediately put most recent `crumbList`
// mirror into `sessionStorage`.
sessionStorage.setItem('crumbs', JSON.stringify(crumbList));
}
return result;
}
});
// - since one does access the `this.crumbs` proxy for any
// (mutating) array operation, one might think about a
// custom `valueOf` implementation which returns a shallow
// copy of the proxy object's up to date mirror state.
Object.defineProperty(this.crumbs, 'valueOf', {
value: function valueOf () {
return [...crumbList];
},
});
}
}
const env = new Environment;
const metricId = 6;
const concept = 'Back orders';
const crumb = { metricId, concept };
env.crumbs.push(crumb);
env.crumbs.push('foo');
env.crumbs.push('bar');
env.crumbs.length = 5;
env.crumbs.push('baz');
env.crumbs.push('biz');
env.crumbs.length = 9;
console.log('... after initial `push` operations and `crumbs.length` changes ...');
console.log({ "current value": env.crumbs });
env.crumbs.shift();
env.crumbs.pop();
env.crumbs.pop();
console.log('... after `shift` and `pop` operations ...');
console.log({ "current value": env.crumbs });
env.crumbs.splice(1, 3);
console.log('... after a final `splice` operation ...');
console.log({ "current valueOf()": env.crumbs.valueOf() });
console.log({ "currently stored JSON": sessionStorage.getItem('crumbs') });
<!-- language: lang-css -->
.as-console-wrapper { min-height: 100%!important; top: 0; }
<!-- language: lang-html -->
<script>
// mock for the SO specific stack snippet
// due to the policies and environment are
// not allowing an original storage access.
const sessionStorage = (function () {
// https://developer.mozilla.org/en-US/docs/Web/API/Storage
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
const storage = new Map;
function key(int) {
return [
...storage.keys()
][parseInt(int, 10)];
}
function setItem(key, value) {
return storage.set(String(key), String(value));
}
function getItem(key) {
return storage.get(String(key));
}
function removeItem(key) {
return storage.delete(String(key));
}
function clear() {
return storage.clear();
}
return {
get length() {
return storage.size;
},
key,
getItem,
setItem,
removeItem,
clear,
};
}());
</script>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论