Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #39403 > unrolled thread

Referencing an object prop with a string

Started byAndrew Poulos <ap_prog@hotmail.com>
First post2021-01-31 14:42 +1100
Last post2021-02-03 19:42 +0100
Articles 11 — 4 participants

Back to article view | Back to comp.lang.javascript


Contents

  Referencing an object prop with a string Andrew Poulos <ap_prog@hotmail.com> - 2021-01-31 14:42 +1100
    Re: Referencing an object prop with a string "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-01-30 19:52 -0800
      Re: Referencing an object prop with a string "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-01-30 19:54 -0800
      Re: Referencing an object prop with a string Andrew Poulos <ap_prog@hotmail.com> - 2021-01-31 20:29 +1100
        Re: Referencing an object prop with a string H e <he12457@hotmail.com> - 2021-01-31 02:17 -0800
      Re: Referencing an object prop with a string Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2021-02-02 04:06 +0100
        Re: Referencing an object prop with a string "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-02-02 13:01 -0800
          Re: Referencing an object prop with a string Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2021-02-02 23:50 +0100
            Re: Referencing an object prop with a string "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-02-02 19:19 -0800
              Re: Referencing an object prop with a string "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-02-02 19:26 -0800
              Re: Referencing an object prop with a string Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2021-02-03 19:42 +0100

#39403 — Referencing an object prop with a string

FromAndrew Poulos <ap_prog@hotmail.com>
Date2021-01-31 14:42 +1100
SubjectReferencing an object prop with a string
Message-ID<Vt-dnSg5Kd2Iuov9nZ2dnUU7-Q3NnZ2d@westnet.com.au>
Say I have an object with lots of properties eg

let o = { a: 1, a2: 1, a3: 2,... };

when I want to get a property value I send the property name to this 
function

function getPropValue(obj, prop) {
   return obj[prop];
}

Now I find the object also has nested properties eg

let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3...}... };

I changed the function to handle nested properties with

function getPropValue(obj, prop1, prop2) {	
   return prop2 == undefined ? obj[prop1] : obj[prop1][prop2];
}

But what happens if the nesting goes deeper and deeper? It'll get messy 
fairly quickly. Is there a better to handle this?

Andrew Poulos

[toc] | [next] | [standalone]


#39404

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-01-30 19:52 -0800
Message-ID<5793bf43-6506-4351-bdca-3d59d740c5e5n@googlegroups.com>
In reply to#39403
On Saturday, January 30, 2021 at 9:42:26 PM UTC-6, Andrew Poulos wrote:
> Say I have an object with lots of properties eg 
> 
> let o = { a: 1, a2: 1, a3: 2,... }; 
> 
> when I want to get a property value I send the property name to this 
> function 
> 
> function getPropValue(obj, prop) { 
> return obj[prop]; 
> } 
> 
> Now I find the object also has nested properties eg 
> 
> let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3...}... }; 
> 
> I changed the function to handle nested properties with 
> 
> function getPropValue(obj, prop1, prop2) { 
> return prop2 == undefined ? obj[prop1] : obj[prop1][prop2]; 
> } 
> 
> But what happens if the nesting goes deeper and deeper? It'll get messy 
> fairly quickly. Is there a better to handle this? 


You can do this:

```
let walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o);

let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3} };

walk(o, 'a4.c')
```

[toc] | [prev] | [next] | [standalone]


#39405

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-01-30 19:54 -0800
Message-ID<a989f3f6-bb92-4920-9f1e-db70d79406e0n@googlegroups.com>
In reply to#39404
On Saturday, January 30, 2021 at 9:52:28 PM UTC-6, Michael Haufe (TNO) wrote:
> On Saturday, January 30, 2021 at 9:42:26 PM UTC-6, Andrew Poulos wrote: 
> > Say I have an object with lots of properties eg 
> > 
> > let o = { a: 1, a2: 1, a3: 2,... }; 
> > 
> > when I want to get a property value I send the property name to this 
> > function 
> > 
> > function getPropValue(obj, prop) { 
> > return obj[prop]; 
> > } 
> > 
> > Now I find the object also has nested properties eg 
> > 
> > let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3...}... }; 
> > 
> > I changed the function to handle nested properties with 
> > 
> > function getPropValue(obj, prop1, prop2) { 
> > return prop2 == undefined ? obj[prop1] : obj[prop1][prop2]; 
> > } 
> > 
> > But what happens if the nesting goes deeper and deeper? It'll get messy 
> > fairly quickly. Is there a better to handle this?
> You can do this: 
> 
> ``` 
> let walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o); 
> 
> let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3} }; 
> 
> walk(o, 'a4.c') 
> ```

For even more complicated structures you may want to use JsonPath:

<https://goessner.net/articles/JsonPath/>

There are packages available:

<https://www.npmjs.com/search?q=jsonpath>

[toc] | [prev] | [next] | [standalone]


#39407

FromAndrew Poulos <ap_prog@hotmail.com>
Date2021-01-31 20:29 +1100
Message-ID<bZydnbkx9McK5Yv9nZ2dnUU7-XXNnZ2d@westnet.com.au>
In reply to#39404
On 31/01/2021 2:52 pm, Michael Haufe (TNO) wrote:
> On Saturday, January 30, 2021 at 9:42:26 PM UTC-6, Andrew Poulos wrote:
>> Say I have an object with lots of properties eg
>>
>> let o = { a: 1, a2: 1, a3: 2,... };
>>
>> when I want to get a property value I send the property name to this
>> function
>>
>> function getPropValue(obj, prop) {
>> return obj[prop];
>> }
>>
>> Now I find the object also has nested properties eg
>>
>> let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3...}... };
>>
>> I changed the function to handle nested properties with
>>
>> function getPropValue(obj, prop1, prop2) {
>> return prop2 == undefined ? obj[prop1] : obj[prop1][prop2];
>> }
>>
>> But what happens if the nesting goes deeper and deeper? It'll get messy
>> fairly quickly. Is there a better to handle this?
> 
> 
> You can do this:
> 
> ```
> let walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o);
> 
> let o = { a: 1, a2: 1, a3: 2, a4: {a: 1, b: 2, c: 3} };
> 
> walk(o, 'a4.c')

Thanks that looks to be a simple solution.

Andrew Poulos

[toc] | [prev] | [next] | [standalone]


#39409

FromH e <he12457@hotmail.com>
Date2021-01-31 02:17 -0800
Message-ID<eec52782-8d9d-4dfe-b441-1b9b8404762dn@googlegroups.com>
In reply to#39407
R
e
c
u
r
s
i
o
n

is
the

k
e
y.





Khrichtjan Robham

y12983 ma il co m (mail . com)

372 6861327

[toc] | [prev] | [next] | [standalone]


#39420

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2021-02-02 04:06 +0100
Message-ID<806120824.0ifERbkFSE@PointedEars.de>
In reply to#39404
Michael Haufe (TNO) wrote:

> let walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o);

This does not work if the property name contains `.'.  The approach to use 
Array.prototype.reduce() is an elegant one, though, and can be applied to 
supporting a path array (too), which solves that problem:

  let walk = (o, path) => path.reduce((o, k) => o && o[k], o);
 
-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#39423

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-02-02 13:01 -0800
Message-ID<ddc05c02-03b1-4600-8236-5453b413a54an@googlegroups.com>
In reply to#39420
On Monday, February 1, 2021 at 9:07:06 PM UTC-6, Thomas 'PointedEars' Lahn wrote:
> Michael Haufe (TNO) wrote: 
> 
> > let walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o);
> This does not work if the property name contains `.'. The approach to use 
> Array.prototype.reduce() is an elegant one, though, and can be applied to 
> supporting a path array (too), which solves that problem: 
> 
> let walk = (o, path) => path.reduce((o, k) => o && o[k], o); 

I wonder if a variant of JSONPath could be promoted into the language proper. I tried in the early ES5 days to convince the committee but there were bigger fish to fry at the time.

With Symbols and the spread operator, it may be harder to get a proposal through.

At least Slice Notation has a change of succeeding:

<https://github.com/tc39/proposal-slice-notation>

[toc] | [prev] | [next] | [standalone]


#39424

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2021-02-02 23:50 +0100
Message-ID<2081055.NgBsaNRSFp@PointedEars.de>
In reply to#39423
Michael Haufe (TNO) wrote:

> On Monday, February 1, 2021 at 9:07:06 PM UTC-6, Thomas 'PointedEars' Lahn
> wrote:
>> Michael Haufe (TNO) wrote:
>> > let walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o);
>> This does not work if the property name contains `.'. The approach to use
>> Array.prototype.reduce() is an elegant one, though, and can be applied to
>> supporting a path array (too), which solves that problem:
>> 
>> let walk = (o, path) => path.reduce((o, k) => o && o[k], o);
> 
> I wonder if a variant of JSONPath could be promoted into the language
> proper.

Yes, I am not particularly fond of Stefan Goessners syntax choices either.
While I could perhaps live with “@” instead of “.”, coming from the command 
shell I find “..” to access *subordered* items very counter-intuitive (I 
also did with E4X).  Why did he not propose and implement the familiar XPath 
syntax?  For example, I see no good reason to propose ”$” instead of “/”.

> I tried in the early ES5 days to convince the committee but there
> were bigger fish to fry at the time.

ACK.
 
> With Symbols and the spread operator, it may be harder to get a proposal
> through.

What exactly do you mean?

One problem I see is that there is not really a need for it anymore (or is 
there?): You can write now (and at least *execute* much more efficiently)

  obj?.store?.book?.filter((book) => book.price < 10)
    .map((book) => book.title) || []

instead of

  jsonPath(obj, '$.store.book[?(@.price < 10)].title')

Which reminds me of LINQ which solves similar problems. 
 
> At least Slice Notation has a change of succeeding:
> 
> <https://github.com/tc39/proposal-slice-notation>

Yes, I think that would be a useful and unproblematic addition.

I would even like a[-1] as in Python (seriously, is there a use-case for 
properties named named “-1” in an *array*?).  I added support for using 
negative indexes to access elements from the end of an array in 
JSX:array.js:BigArray with Proxy, and BigArray.prototype.get() to do it
in a backwards-compatible way, about 5 years ago:

<https://github.com/PointedEars/JSX/blob/e6eb05cb945df7b7304d572ccbac90ae9a632286/array.js#L491-L1158>

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#39425

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-02-02 19:19 -0800
Message-ID<a6cd17cf-36d2-4724-9ca7-f512f7c4c03en@googlegroups.com>
In reply to#39424
On Tuesday, February 2, 2021 at 4:50:26 PM UTC-6, Thomas 'PointedEars' Lahn wrote:
> Michael Haufe (TNO) wrote: 

> > I wonder if a variant of JSONPath could be promoted into the language 
> > proper.
> Yes, I am not particularly fond of Stefan Goessners syntax choices either. 
> While I could perhaps live with “@” instead of “.”, coming from the command 
> shell I find “..” to access *subordered* items very counter-intuitive (I 
> also did with E4X). Why did he not propose and implement the familiar XPath 
> syntax? For example, I see no good reason to propose ”$” instead of “/”.

I don't think either could be used:

'$' is a variable name already so that could not become a reserved work

 '/' could be used as a prefix operator but with the existence of 
multi-line comments: '/* ... */'
single line comments: '// ...' 
and '/' as an infix division I think that would be hard to sell.

Additionally, if '/' is used as the root, it seems to want '//' as the descendant selector
like xpath. This would conflict with single line comments.

Maybe '#' as root?

> > With Symbols and the spread operator, it may be harder to get a proposal 
> > through.
> What exactly do you mean? 

JSONPath uses '..' as the descendant selector. The existing spread operator is '...'

With destructuring it just looks wrong. In the below example I want c to be assigned the value of c.c1.c2:

```
let {a, b, c: c..c2, ...rest} = {a: 10, b: 20, c: {c1: {c2: 30}}, d: 40, e: 50};
```

What if c2 is a Symbol?

```
let {a, b, c: c..[c2], ...rest} = {a: 10, b: 20, c: {c1: {[c2]: 30}}, d: 40, e: 50};
``` 

obj..[symbolName] seems a bit terse...

> One problem I see is that there is not really a need for it anymore (or is 
> there?): You can write now (and at least *execute* much more efficiently) 
> 
> obj?.store?.book?.filter((book) => book.price < 10) 
> .map((book) => book.title) || [] 
> 
> instead of 
> 
> jsonPath(obj, '$.store.book[?(@.price < 10)].title') 
> 
> Which reminds me of LINQ which solves similar problems.

I think a descendent operator/method is the primary missing feature.

obj.descendants('book')
obj..book

> > At least Slice Notation has a change of succeeding: 
> > 
> > <https://github.com/tc39/proposal-slice-notation>
> Yes, I think that would be a useful and unproblematic addition. 
> 
> I would even like a[-1] as in Python

Doesn't work in bracket notation but at least it works with slice:

```
let xs = ['a', 'b', 'c']
xs.slice(-1) // 'c'
```

I guess you could use proxy to support the bracket form.

This was a little challenging but seems to work:

```
function adapt(Base) {
    const handler = {
        get(target, prop) {
            if (!isNaN(prop)) {
                prop = parseInt(prop, 10);
                if (prop < 0) {
                    prop += target.length;
                }
            }
            return target[prop];
        }
    }

    return class extends Base {
        constructor(...args) {
            return new Proxy(super(...args), handler);
        }
    };
}

class List extends adapt(Array) {}

let xs = new List('a','b','c')

xs[-2] // "b" 
```

> (seriously, is there a use-case for 
> properties named named “-1” in an *array*?).

I'm too lazy to check but this reminded me that there was a bug/feature 
in an earlier version of Firefox that had '-1' and '-2' defined on the arguments object.
The values of those positions were information like argument length and something else
I forget.

> I added support for using 
> negative indexes to access elements from the end of an array in 
> JSX:array.js:BigArray with Proxy, and BigArray.prototype.get() to do it 
> in a backwards-compatible way, about 5 years ago: 
> 
> <https://github.com/PointedEars/JSX/blob/e6eb05cb945df7b7304d572ccbac90ae9a632286/array.js#L491-L1158>

Any interest in modernizing to post ES6+?

[toc] | [prev] | [next] | [standalone]


#39426

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-02-02 19:26 -0800
Message-ID<f275f2c8-8d54-4df3-875c-01de563146aan@googlegroups.com>
In reply to#39425
On Tuesday, February 2, 2021 at 9:19:18 PM UTC-6, Michael Haufe (TNO) wrote:

> I guess you could use proxy to support the bracket form. 
> 
> This was a little challenging but seems to work: 
> 
> [...]
>

Of course Google Groups broke the indenting... Here is a gist of the same:

<https://gist.github.com/mlhaufe/e742bc99954dd3282bee6ba54a6d439c>

One would think I'd stop being a masochist with this terrible interface.

[toc] | [prev] | [next] | [standalone]


#39427

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2021-02-03 19:42 +0100
Message-ID<2637940.BEx9A2HvPv@PointedEars.de>
In reply to#39425
Michael Haufe (TNO) wrote:

> […] Thomas 'PointedEars' Lahn wrote:
>> Michael Haufe (TNO) wrote:
>> > I wonder if a variant of JSONPath could be promoted into the language
>> > proper.
>> Yes, I am not particularly fond of Stefan Goessners syntax choices
>> either. While I could perhaps live with “@” instead of “.”, coming from
>> the command shell I find “..” to access *subordered* items very
>> counter-intuitive (I also did with E4X). Why did he not propose and
>> implement the familiar XPath syntax? For example, I see no good reason to
>> propose ”$” instead of “/”.
> 
> I don't think either could be used:
> 
> '$' is a variable name already so that could not become a reserved work

ISTM that he defined “$” to only signify the root element if it occurred as 
first character in the path.
 
>  '/' could be used as a prefix operator but with the existence of
> multi-line comments: '/* ... */'
> single line comments: '// ...'
> and '/' as an infix division I think that would be hard to sell.

We are talking about literals here.
 
> Additionally, if '/' is used as the root, it seems to want '//' as the
> descendant selector like xpath. This would conflict with single line
> comments.

See above.
 
> Maybe '#' as root?

That’s even worse than “@” :-D  “@” I can at least associate with “here”.
 
>> One problem I see is that there is not really a need for it anymore (or
>> is there?): You can write now (and at least *execute* much more
>> efficiently)
>> 
>> obj?.store?.book?.filter((book) => book.price < 10)
>> .map((book) => book.title) || []
>> 
>> instead of
>> 
>> jsonPath(obj, '$.store.book[?(@.price < 10)].title')
>> 
>> Which reminds me of LINQ which solves similar problems.
> 
> I think a descendent operator/method is the primary missing feature.
> 
> obj.descendants('book')
> obj..book

AISB, I find “..” counter-intuitive.
 
>> > At least Slice Notation has a change of succeeding:
>> > 
>> > <https://github.com/tc39/proposal-slice-notation>
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> Yes, I think that would be a useful and unproblematic addition.
>> 
>> I would even like a[-1] as in Python
   ^^^^^^^^^^^^^^^^^
> Doesn't work in bracket notation but at least it works with slice:

*facepalm*
 
> ```
> let xs = ['a', 'b', 'c']
> xs.slice(-1) // 'c'
> ```
> 
> I guess you could use proxy to support the bracket form. […]

That is what I did and said.  Just not with classes.  See below :-D
 
>> (seriously, is there a use-case for
>> properties named named “-1” in an *array*?).
> 
> I'm too lazy to check but this reminded me that there was a bug/feature
> in an earlier version of Firefox that had '-1' and '-2' defined on the
> arguments object. The values of those positions were information like
> argument length and something else I forget.

OK, but that is not an *array*.  And a broken implementation (now likely 
fixed) is not a good argument against the syntax.
 
>> I added support for using
>> negative indexes to access elements from the end of an array in
>> JSX:array.js:BigArray with Proxy, and BigArray.prototype.get() to do it
                         ^^^^^^^^^^
>> in a backwards-compatible way, about 5 years ago:
>> 
>> 
<https://github.com/PointedEars/JSX/blob/e6eb05cb945df7b7304d572ccbac90ae9a632286/array.js#L491-L1158>
> 
> Any interest in modernizing to post ES6+?

Yes.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web