0

I want to do:

properties.email.value without triggering an error like: Can't read 'value' of 'undefined'

However, I don't want to do:

properties.email && properties.email.value and I don't want to use an helper, something like: get(properties, 'email.value').


I really want to keep the syntax properties.email.value

I can solve this by doing:

Object.defineProperty(properties, 'email', {
 get: () => properties.email && properties.email.value,
 enumerable: true,
 configurable: true
});

Now the getter is in charge of doing my safety check. Perfect.

But I also want to be able to do properties.name.value safely. But as the properties object comes from the API (json), I don't know the full list of properties possible.

So, is there a way to use this "magical" get syntax for any prop access like: properties[ANYTHING].value ?

Cyril F
  • 1,842
  • 2
  • 19
  • 35
  • I think the answer is `NO`. Because `properties[ANYTHING]` will return `undefined`. and `undefined` has no property. – Terry Wei Jun 21 '18 at 07:57
  • Yes I agree. That's why I wanted to know if there was a way to use the `Object.defineProperty` util and set a `get` method on `any` properties. But I think we can do this only with the properties already present in the object itself. There is no magical `getter` I think. – Cyril F Jun 21 '18 at 07:59
  • 1
    you could use a https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy – Nina Scholz Jun 21 '18 at 07:59
  • If you're open to use lodash, [`_.get`](https://lodash.com/docs/4.17.10#get) is your bet. – 31piy Jun 21 '18 at 08:00
  • @NinaScholz if you create an answer to this question I'll vote for you as being the answer. I have to give it a deeper look, but it seems like exactly what I'm asking for! Thanks! :D – Cyril F Jun 21 '18 at 08:03
  • Thanks @31piy that's a valid way, true, but as I mentioned: I don't want to use helpers like `get(properties, 'email.value')`. thanks – Cyril F Jun 21 '18 at 08:04
  • 1
    The feature is often referred as 'null propagation', here's a good thread on it: https://stackoverflow.com/questions/32139078/null-safe-property-access-and-conditional-assignment-in-es6-2015 – Simple.Js Jun 21 '18 at 08:07
  • what about the confusing `value` property? – Nina Scholz Jun 21 '18 at 08:10
  • I don't know what you mean by "confusing `value`", but the idea is that this API returns a `value` and `title` for each prop (so it can be rendered in a form (as input label and value) – Cyril F Jun 21 '18 at 08:15
  • @Simple.Js I like it a lot as well, thanks for sharing! – Cyril F Jun 21 '18 at 08:16
  • i mean your set sets `email`, not `value`. email is first an object, later a string. – Nina Scholz Jun 21 '18 at 08:20
  • Right, good catch. I just typed my example quickly to make my point, but you're correct. I removed it for now. (question edited) – Cyril F Jun 21 '18 at 08:31
  • I've edited the answer. Hope this answer is what you want. – Terry Wei Jun 21 '18 at 08:42

3 Answers3

3

OK, I've got something like this.

But you must create properties that way.

Hope this help :)

var properties = {
  phone : {
    value: "123456789"
  }  
}

var handler = {
  get: function(target, name) {
    return target.hasOwnProperty(name) ? target[name] : {};
  }
};

var new_properties = new Proxy(properties, handler);

console.log("phone.value = " + new_properties.phone.value);

console.log("email.value = " + new_properties.email.value);

new_properties.email = {
  value: 1
};

console.log("email.value after assign = " + new_properties.email.value);

The document reference here.

Edited

Even if the original properties object is unknown, this kind of usage works as well.

Terry Wei
  • 1,521
  • 8
  • 16
  • I choose this one as the valid answer because it fits perfectly the requirements I asked. But, to be honest, all credits goes to @NinaScholz – Cyril F Jun 22 '18 at 06:18
2

You could use a Proxy and get known properties and a custom result for unknow properties.

For changing properties, you could take the same approach and set the value.

var properties = { email: { value: 'foo@example.com' } },
    proxy = new Proxy(
        properties,
        {
            get: function(target, prop, receiver) {
                if (prop in target) {
                    return target[prop] && target[prop].value
                } else {
                    return;
                }
            },
            set: function(target, prop, value) {
                if (prop in target) {
                    target[prop].value = value;
                } else {
                    target[prop] = { value };
                }
            }
        }
    );

console.log(proxy.email);
console.log(proxy.bar);

proxy.email = '41';
console.log(proxy.email);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Your answer works, although I still want to be able to make my calls like: `proxy.email.value` and `proxy.email.title`. I simply have to udpate your `get` method with: `return target[prop] || {}` – Cyril F Jun 21 '18 at 08:52
  • 1
    for inner objects, you could use another proxy. – Nina Scholz Jun 21 '18 at 08:54
  • 1
    In the end I just end up doing: `const proxy = new Proxy(properties, { get: (target, prop) => (prop in target) ? target[prop] : {}, })` This way any `proxy.email.value` or `proxy.anything.value` won't crash. – Cyril F Jun 21 '18 at 09:39
0

I can't believe I'm doing this...

var wordlength = 7;
var alphabet="abcdefghijklmnopqrstuvwxyz";
alphabet += alphabet.toUpperCase() + "0123456789_";
var alen = alphabet.length;
var buildWord = function(number){
    if(number===0){
        return '';
    }
    return alphabet[number%alen]+buildWord(Math.floor(number/alen));
};
var total = Math.pow(alen, wordlength);
for(var i = 1; i<total; i++){
    var w = buildWord(i);
    if(isNaN(w[0]) && Object.prototype[w]===undefined){
        Object.prototype[w]={};
    }
}
binderbound
  • 791
  • 1
  • 7
  • 27
  • No.... It should do what they want. Although it doesn't support the $ sign and some other vars. Could add those in I guess. – binderbound Jun 21 '18 at 08:52
  • Technically speaking, it answers the brief. They won't get any exceptions. It just won't be very useful either. It should be fairly clear this is not a serious answer anyway. – binderbound Jun 21 '18 at 09:00