spread operator issues with property accessors (getters)

我只是一个虾纸丫 提交于 2020-01-13 09:19:06

问题


I'm having a hard time understanding why there are some issues with the following code https://jsfiddle.net/q4w6e3n3/3/

Note: All examples are tested in chrome version 52.0.2743.116 just in case this helps

const model = {
  someVal: 'some val',
};


const obs = {
  ...model,
  get accessor() {
    return this.someVal;
  },
}

// Expected: '>>> some val'
// Actual: '>>> undefined'
console.log('>>>', obs.accessor);

But the following similar snippet works https://jsfiddle.net/q4w6e3n3/5/

const model = {
  someVal: 'some val',
};


const obs = {
  get accessor() {
    return this.someVal;
  },
  ...model,
}

// Expected: '>>> some val'
// Actual: '>>> some val'
console.log('>>>', obs.accessor);

using the babel REPL I was able to see that Object.assign is used if available in the transpiled code When I used it directly instead of the object spread I get the same issue, and also works if put the model variable to the end instead of at the beginning.

Is this a bug? or is it intended behavior?

Also why does the following snippet work as well?:

const model = {
  someVal: 'some val',
};


const obs = {
  someVal: model.someVal,
  get accessor() {
    return this.someVal;
  },
}

// Expected: '>>> some val'
// Actual: '>>> some val'
console.log('>>>', obs.accessor);

https://jsfiddle.net/q4w6e3n3/6/

I would expect it to have the same issues but works as a charm are getters this keyword somehow bound to the object they were added to?


回答1:


Object.assign won't copy accessors. So when your splat is before your getter babel and its various voodoos uses Object.assign and the accessor isn't copied onto the first object from the second, well kind of, voodoo again. When your splat is after the getter, then it assigns the splatted properties onto the object with the getter, and the getter is preserved.

See here: MDN - Object.assign

Relevant code excerpt:

**Copying Accessors**
var obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

var copy = Object.assign({}, obj); 
console.log(copy); 
// { foo: 1, bar: 2 }, the value of copy.bar is obj.bar's getter's return value.

// This is an assign function that copies full descriptors
function completeAssign(target, ...sources) {
  sources.forEach(source => {
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});
    // by default, Object.assign copies enumerable Symbols too
    Object.getOwnPropertySymbols(source).forEach(sym => {
      let descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }


来源:https://stackoverflow.com/questions/39515321/spread-operator-issues-with-property-accessors-getters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!