Home > Software engineering >  An object modified with Object.defineProperty does not cause a TypeError
An object modified with Object.defineProperty does not cause a TypeError

Time:01-07

I'm creating a utility that changes the fingerprint. The value changed with Object.defineProperty does not cause a TypeError, as it would if I were referring to the original object. Because of this feature, the security systems understand that I am changing the value.

I change the value as follows (Screen is just an example, I change many values, so I need a general solution for all of them)

const proto = Screen.prototype;
const propName = 'availHeight';
const descriptors = Object.getOwnPropertyDescriptor(Screen.prototype, 'availHeight');
const overrideDescriptors = {
    get: () => 1000
}
Object.defineProperty(proto, propName, {
    ...descriptors,
    ...overrideDescriptors
});

As it should be:

typeof Screen.prototype.availHeight; VM88:1 Uncaught TypeError: Illegal invocation at <anonymous>:1:25.

What happens when the value changes:

typeof Screen.prototype.availHeight; 'number'.

How do I fix this so that this check, as with the original value, causes a TypeError?

CodePudding user response:

An approach that might work for you would be to call the original getter (which will throw if it did originally), but to ignore the resulting value and return your own.

Because you're setting a getter, you probably shouldn't spread the existing descriptor (which will conflict if it's a data descriptor). If you want to copy over enumerability as well, extract that explicitly.

class Screen {
  get availHeight() {
    throw new Error('Bad!');
  }
}
const proto = Screen.prototype;
const propName = 'availHeight';
const originalDescriptor = Object.getOwnPropertyDescriptor(Screen.prototype, 'availHeight');
const overrideDescriptor = {
  get() {
    if (originalDescriptor.get) {
      // Call the original getter, if there was one, and possibly throw
      originalDescriptor.get.call(this);
    }
    return 1000;
  },
  enumerable: originalDescriptor.enumerable
};
Object.defineProperty(proto, propName, overrideDescriptor);
const s = new Screen();

// Throws:
s.availHeight;

The code in your comment also looks to throw as desired, run the below snippet:

class Screen {
  get availHeight() {
    throw new Error('Bad!');
  }
}
const obj = screen;
const proto = Object.getPrototypeOf(obj);
const propName = 'availHeight';
const originalDescriptor = Object.getOwnPropertyDescriptor(Screen.prototype, 'availHeight');
const overrideDescriptor = {
  get() {
    if (originalDescriptor.get) {
      // Call the original getter, if there was one, and possibly throw
      originalDescriptor.get.call(this);
    }
    return 1000;
  },
  enumerable: originalDescriptor.enumerable
};
Object.defineProperty(proto, propName, overrideDescriptor);
const s = new Screen();

// Throws:
s.availHeight;

  • Related