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?

huangapple go评论72阅读模式
英文:

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 pushing 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 &quot;up to date&quot; mirror of the `this.crumbs` proxy object.
// - initialized either from `sessionStorage` or as empty array.
const crumbList =
JSON.parse(sessionStorage.getItem(&#39;crumbs&#39;) ?? 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 === &#39;length&#39;) {
// - immediately put most recent `crumbList`
//   mirror into `sessionStorage`.
sessionStorage.setItem(&#39;crumbs&#39;, 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&#39;s up to date mirror state.
Object.defineProperty(this.crumbs, &#39;valueOf&#39;, {
value: function valueOf () {
return [...crumbList];
},
});
}
}
const env = new Environment;
const metricId = 6;
const concept = &#39;Back orders&#39;;
const crumb = { metricId, concept };
env.crumbs.push(crumb);
env.crumbs.push(&#39;foo&#39;);
env.crumbs.push(&#39;bar&#39;);
env.crumbs.length = 5;
env.crumbs.push(&#39;baz&#39;);
env.crumbs.push(&#39;biz&#39;);
env.crumbs.length = 9;
console.log(&#39;... after initial `push` operations and `crumbs.length` changes ...&#39;);
console.log({ &quot;current value&quot;: env.crumbs });
env.crumbs.shift();
env.crumbs.pop();
env.crumbs.pop();
console.log(&#39;... after `shift` and `pop` operations ...&#39;);
console.log({ &quot;current value&quot;: env.crumbs });
env.crumbs.splice(1, 3);
console.log(&#39;... after a final `splice` operation ...&#39;);
console.log({ &quot;current valueOf()&quot;: env.crumbs.valueOf() });
console.log({&#160;&quot;currently stored JSON&quot;: sessionStorage.getItem(&#39;crumbs&#39;) });

<!-- language: lang-css -->

.as-console-wrapper { min-height: 100%!important; top: 0; }

<!-- language: lang-html -->

&lt;script&gt;
// 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,      
};
}());
&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月30日 04:03:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360057.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定