0

I am playing around with using JavaScript getters and inheritance, and I ran into this interesting behavior. The comments at the end of the lines are the order in which the statements are printing.

function createFruit(size) {
   return {
      get size() {
         console.log('getting size'); // 2, 4
         return size;
      },
   };
}

function createApple(color) {
   let apple = {
      get color() {
         return color;
      },
   };

   return Object.assign(Object.create(apple), createFruit(2));
}


let small = createFruit(1);
console.log('calling getSize fruit'); // 1
console.log(small.size); // 3

let green = createApple('green');
console.log(green.color); // 5
console.log('calling getSize apple'); // 6
console.log(green.size); // 7
   

Output:

calling getSize fruit
getting size
1
getting size
green
calling getSize apple
2

The parts are confused about are the order that four, six, and seven print. I was under the understanding that getters in JavaScript are lazy, meaning they are only called when needed. I don't need to get the size of green until the final line, but the getter is being called when the apple is being constructed. Why is this happening? And how can I rewrite my code to avoid this behavior?

As a side note, please let me know if the general pattern I'm using is a bad way to do this.

6
  • During creation you're using assign, which will loop over the properties and assign them. Have a look at the polyfill of assign: developer.mozilla.org/en/docs/Web/JavaScript/Reference/… Commented Mar 13, 2017 at 20:57
  • Oh okay The behavior makes sense then. Would it be best to use .getSize() instead of get size() then? Seems like I would have to introduce a lot more code to enable using the size getter, then. Commented Mar 13, 2017 at 21:04
  • Not really sure what you're asking, do you mean just have a method called getSize as opposed to using a getter? Commented Mar 13, 2017 at 21:14
  • Yeah, that's what I meant. Sorry for being unclear. Commented Mar 13, 2017 at 21:15
  • To what end? Seems like it wouldn't really make any difference. Commented Mar 13, 2017 at 21:22

1 Answer 1

3

Object.assign does not copy property attributes like getter functions, it uses them to evaluate the property value and copy that onto the target. So during the createApple call, the getter is invoked and a non-getter size property is created on the apple object.

How can I rewrite my code to avoid this behavior?

Don't use Object.assign with objects that contain accessory properties as source arguments. You can write

function createApple(color) {
  return Object.defineProperties(createFruit(2), {
    color: {
      get() {
        return color;
      }
    }
  });
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.