Behavior inconsistent in SFC
Version
3.2.26
Reproduction link
Steps to reproduce
Consider the two pieces of code as below:
<script>
export default {
data(){
return {
msg:"data"
};
},
setup(){
var obj = {
msg:"setup"
};
return obj
}
}
</script>
<template>
<h1>{{ msg }}</h1>
</template>
and
<script>
export default {
data(){
return {
msg:"data"
};
},
setup(){
// The only difference from the first piece of code.
return {
msg:"setup"
}
}
}
</script>
<template>
<h1>{{ msg }}</h1>
</template>
What is expected?
The two pieces of code should behave exactly the same. Both render the msg
from setup
, which would be "setup".
What is actually happening?
The first code would render "data". The second code would render "setup". It's wired.
Is it a bug or did I miss something? This inconsistent behavior only happens in SFC.
That is indeed very weird, but - you should never have keys with the same name between data/setup/computed etc.
so this is a curious side effect that is not relevant when writing correct code.
Edit: the reason for the behaviour lies in the bindings analysis that the compiler does for optimization - you can see this at the top of the compiler output in the JS tab of the playground:
/* Analyzed bindings: {
"msg": "setup-maybe-ref"
} */
This is an optimization that tries to understand where bindings in the template come from. For bindings it can detect, it creates a "shortcut", which means we don't have to go through the instance proxy's more expensive lookup:
// $setup, $data, .... etc are shortcut to the objects returned by these options.
function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("h1", null, _toDisplayString($setup.msg), 1 /* TEXT */))
}
now, if you do this in setup, you can see that the binding analytics detect "msg" for data, not setup-maybe-ref, because the compiler can't interpret the return value of setup clearly:
/* Analyzed bindings: {
"msg": "data"
} */
setup(){
var obj = {
msg:"setup"
};
return obj
}
// consequently, now message is read from `$data.msg:
function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("h1", null, _toDisplayString($data.msg), 1 /* TEXT */))
}
I'm inclined to close this as a side-effect of a compiler optimization, a side-effect which only manifests if you have colliding property names, which is not allowed anyway.