Those are two separate static expressions, and because a static expression runs once, this would be the result:
doPop(); // "c"
doPop(); // "c"
doPop(); // "c"
doPush(); // 4
doPush(); // 4
doPush(); // 4
The same as if you defined it like this:
const doPop = () => {
return @( ["a", "b", "c"].pop() ) // expression inside parens runs once, evaluating to "c"
}
const doPush = () => {
return @( ["a", "b", "c"].push("d") ) // expression inside parens runs once, evaluating to 4
}
It would be different if we did this:
const doPop = () => {
return @( ["a", "b", "c"] ).pop() // static expression was the array only, the pop() always runs on each call
}
const doPush = () => {
return @( ["a", "b", "c"] ).push("d") // static expression was the array only, the push() always runs on each call
}
Output:
doPop(); // "c"
doPop(); // "b"
doPop(); // "a"
doPop(); // undefined
doPush(); // 4
doPush(); // 5
doPush(); // 6
I would prefer the syntax not to change semantics of the declared objects, so I'd you wanted a constant array you would need to be explicit about that:
function foo() {
return thing ?? @Object.freeze([])
}
or with static syntax:
function foo() {
return thing ?? static Object.freeze([])
}
Yeah it is, that array can be mutated and it is a different reference each time.
Sure, all the discussed use cases can be achieved today. F.e.:
globalThis.defaultArray = []
function foo() {
return thing ?? defaultArray
}
This is about nice sugar. Plus this new syntax has an advantage: the static expressions or variables are lexically scoped, whereas a const
or global var is polluting the outer scope. The sugar keeps things more concise without affecting outer scope.