Search code examples
javascriptnode.jsecmascript-6es6-proxy

Accesing method startsWith throw error when calling console.log() in proxy


I am learning about ES6 proxies, for this purpose I follow the guide on javascript.info, the following example, avoid reading, deleting, adding a new property and listing properties if the property name starts with an underscore, for example _password

let user = {
  username: "john.doe",
  firstname: "John",
  lastname: "doe",
  email: "john.doe@example.com",
  _password: "******"
};

user = new Proxy(user, {
  get(target, property) {
    if (property.startsWith("_")) {
      throw new Error("Access denied");
    }

    return target[property];
  },

  set(target, property, value) {
    if (value.startsWith("_")) {
      throw new Error("Access denied");
    }

    target[property] = value;

    return true;
  },

  deleteProperty(target, property) {
    if (property.startsWith("_")) {
      throw new Error("Access denied");
    }

    delete target[property];

    return true;
  },

  ownKeys(target) {
    return Object.keys(target).filter(key => !key.startsWith("_"));
  }
});

const { username, firstname, lastname, email } = user;

console.log(username, firstname, lastname, email);
console.log(JSON.stringify(user, null, 2));
console.log(user);

The call to console.log(JSON.stringify(user, null, 2)); show the expected output, because _password is omitted in the output

{
    "username": "john.doe",
    "firstname": "John",
    "lastname": "doe",
    "email": "john.doe@example.com"
}

But when calling console.log(user); I get the following error

/tmp/index.js:48
    if (property.startsWith("_")) {
                 ^

TypeError: property.startsWith is not a function

Thanks for your comments


Solution

  • When accessing symbol-keyed properties on your proxy object (like console.log does it in node.js), your trap handlers get passed the symbol as the property argument, not a property name. A symbol doesn't have the startsWith string method of course. Use

    if (typeof property == "string" && property.startsWith("_")) {
    

    instead.