Why Can't I Access a Property of an Integer with a Single Dot

Why can't I access a property of an integer with a single dot?

The period is part of the number, so the code will be interpreted the same as:

(3.)toFixed(5)

This will naturally give a syntax error, as you can't immediately follow the number with an identifier.

Any method that keeps the period from being interpreted as part of the number would work. I think that the clearest way is to put parentheses around the number:

(3).toFixed(5)

Using integer keys with dot notation to access property in javascript objects

In case of dot notation to access a value, the property key must be a valid identifier

In this code, property must be a valid JavaScript identifier, i.e. a
sequence of alphanumerical characters, also including the underscore
("_") and dollar sign ("$"), that cannot start with a number. For
example, object.$1 is valid, while object.1 is not.

You can use bracket notation in this case

obj['1']

Spec: Property Accessors

Access numeric properties of an object using dot notation

Your question seems to be about why we can’t access array and array-like elements using the dot notation like this:

const v = a.0;

It’s described in the ECMAScript specification:

The dot notation is explained by the following syntactic conversion:

MemberExpression . IdentifierName

And identifiers may not start with a digit as described here:


IdentifierName ::

IdentifierStart

IdentifierName IdentifierPart

IdentifierStart ::

UnicodeLetter

$

_

\ UnicodeEscapeSequence


As for the reasoning, having identifier names just being made of digits would have made it difficult to write number literals. An exception could probably have been designed just for array access but that would have made the language more complex and departing from the common C family syntax without any real gain.

Can't access object property, even though it shows up in a console log

The output of console.log(anObject) is misleading; the state of the object displayed is only resolved when you expand the Object tree displayed in the console, by clicking on >. It is not the state of the object when you console.log'd the object.

Instead, try console.log(Object.keys(config)), or even console.log(JSON.stringify(config)) and you will see the keys, or the state of the object at the time you called console.log.

You will (usually) find the keys are being added after your console.log call.

Why don't number literals have access to Number methods?

You can access it the same way, it's a different parsing issue here, to do it, use a slightly different syntax:

(1).toString()

Numbers can have decimals, so the syntax for ending in a decimal is a bit ambiguous when you go to parse the code, use parenthesis to be valid. It's a bit clearer when you see that this is also valid:

(1.).toString()

However with just 1.toString() it's trying to parse as a number with a decimal, and it fails.

Access to the number as an object

You need another dot to distinguish the first decimal separator from a dot as a property accessor.

console.log(2..constructor);

Why can't I dot-reference a hashtable key's value property if the property name is an integer

Note: This answer originally incorrectly claimed that $table.6 doesn't work, due to the hashtable key being integer-typed, but it works just fine, because the 6 in the .6 "property" access is parsed as an integer as well.

As Gyula Kokas' helpful answer points out, you're seeing problematic behavior in PowerShell's parser, present as of PowerShell 7.2, discussed in detail in GitHub issue #14036. The behavior is unrelated to hashtables per se:

  • What follows ., the member-access operator, is parsed as a number if it looks like a number literal, such as 6, 6l (a [long]) or even 6.0(!, a [double]).

    • See below for how that number is then used.
  • Any attempt to use another property access then triggers the error you saw:

    $foo.6.bar # !! Error "Missing property name after reference operator."
    • In fact, following a property name that starts with a digit with a letter causes the error too - even though 6a can not interpreted as a number literal.

      $foo.6a # !! Same error.

As an aside: PowerShell even allows you to use variable references, and even expressions (enclosed in (...)) as property names (e.g., $propName = 'Length'; 'foo'.$propName or ('foo'.('L' + 'ength')

Workarounds:

  • As you've demonstrated, enclosing the first property access in (...) - ($table.6).Count works, and so does $table.(6).Count

  • You've also demonstrated $table[6].Count, which works for hashtables.

  • For accessing an object's actual property, $obj.'6'.Count would work too (given that property names are always strings), as it would with hashtables with string keys (e.g. @{ '6'= 'six' }.'6'.Length)


Considerations specific to hashtables:

As a syntactic convenience, PowerShell allows property-access syntax ($obj.someProperty) to also be used to access the entries of a hashtable, in which case the property "name" is taken as the key of an entry in the hashtable.

The type-native syntax to access hashtable entries is index syntax ($hash[$someKey]).

While property names (referring to members of a .NET type) are invariably strings:

  • a hashtable's keys can be of any type.
  • on accessing an entry, the lookup key must not only have the right value, but must also be of the exact same type as the key stored in the hashtable.

Perhaps surprisingly, when defining a hashtable, unquoted keys situationally become either strings or numbers:

  • If the unquoted word can be interpreted as a number literal (e.g., 6), it is parsed as such, and you end up with a numeric key; in the case of 6, it will be [int]-typed key, because the usual number-literal typing applies (e.g., 1.0 would become a [double] key (not advisable, because binary floating-point values do not always have exact decimal representations), and 2147483648 would become a [long]).

  • Otherwise (e.g., NameServers), the key is [string]-typed.

    • Caveat: If the name starts with a digit (but isn't a number literal; e.g. 6a), an error occurs; use quoting ('6a') as a workaround - see GitHub issue #15925

That is, even though strings in expressions normally require quoting, for convenience you may omit the quoting when defining keys in hashtable literals - but the rules for recognizing number literals still apply.

Explicitly typing hashtable keys:

  • To ensure that a given key is interpreted as a [string], quote it (e.g., '6')

  • Generally, you may also use a cast to type your keys explicitly. (e.g. [long] 6) or, in number literals, the usual number-type suffix characters, such as L for [long] (e.g. 6L) - see this answer for an overview of the supported suffixes, whose number has grown significantly in PowerShell (Core) 7+.

An example, based on your hashtable:

It follows from the above that your 6 key is of type [int] (and would have to be defined as '6' in your hashtable literal if you wanted it to be a string).

Because the 6 in $name.6 is also parsed as an [int], the lookup succeeds, but note that it wouldn't succeed if different numeric types were at play:

# !! Output is $null, because the entry key is of type [long], 
# !! whereas the lookup key is [int].
@{ 6L = '[long] 6' }.6

Considerations specific to property access:

With actual property access (accessing a native member of a .NET type), the fact that names that look like numbers are actually parsed as numbers first - before, of necessity, being converted to strings - can result in surprising behavior:

# !! Output is $null, because the 6L after "." is parsed as a 
# !! ([long]) number first, and then converted to a string, which
# !! results in "6" being used.
([pscustomobject] @{ '6L' = 'foo' }).6L

# OK - The quoting forces 6L to be a string.
([pscustomobject] @{ '6L' = 'foo' }).'6L' # -> 'foo'


Related Topics



Leave a reply



Submit