Reputation: 2072
Vue.js proxies its objects to catch property accesses. I seem to have found a leak in the abstraction: Object.keys
doesn't return props in the list of keys.
With the following Vue component:
function callMe() {
var comp = Vue.component("comp", {
template: "<button @click='clickMe()'>xxx</button>",
props: {
label: String,
cardId: String,
collapsible: {
type: Boolean,
default: true,
},
collapsed: Boolean,
},
data() {
console.log(Object.keys(this))
console.log(this.collapsible)
console.log(Object.keys(this).includes("collapsible"))
return { isCollapsed: this.collapsed }
},
methods: {
clickMe(){
console.log(this)
}
}
})
var vm = new Vue({
el: '#root',
template: "<comp></comp>",
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id='root'>
<button @click="clickMe()" >Click Me</button>
</div>
The console output is:
(29) ["_uid", "_isVue", "$options", "_renderProxy", "_self", "$parent", "$root", "$children", "$refs", "_watcher", "_inactive", "_directInactive", "_isMounted", "_isDestroyed", "_isBeingDestroyed", "_events", "_hasHookEvent", "_vnode", "_staticTrees", "$vnode", "$slots", "$scopedSlots", "_c", "$createElement", "$attrs", "$listeners", "_watchers", "_props", "toggleThis"]
true
false
(Interestingly, when I call the check later, the isCollapsed
item is in the list. You'll also notice that clickMe
method is also present. It seems that only props are left out.)
Why is this happening?
More generally, how does Vue's Proxy object emit a different set of keys than it can then access?
This is a problem for me because I'm trying something fancy with pug-vdom
and that internally uses Object.keys
to enumerate the variables to inject into the Pug template.
Is this a Vue bug?
Alternately, is it possible to access a list of props keys from the this
object, and export an object whose keys contain the props as well?
edit: added a runnable code snippet that demonstrates the problem.
Upvotes: 0
Views: 3295
Reputation: 2920
Object.keys()
does not iterate over prototype properties.
Also child component is inherited
from root component.
This means props & data fields must be inside __proto__
of child components.
Hence if we do Object.keys(this__proto__).includes("collapsible")
, it returns true
in child component.
If you want to access those fields from child components then use this.$props
and this.$data
.
function callMe() {
var comp = Vue.component("comp", {
template: "<button @click='clickMe()'>xxx</button>",
props: {
label: String,
cardId: String,
collapsible: {
type: Boolean,
default: true,
},
collapsed: Boolean,
},
data() {
console.log('Inside Child:',Object.keys(this))
console.log(this.collapsible)
console.log(Object.keys(this.__proto__).includes("collapsible"))
console.log(Object.keys(this).includes("collapsible"))
return { isCollapsed: this.collapsed }
},
methods: {
clickMe(){
console.log(this)
}
}
})
var vm = new Vue({
el: '#root',
template: "<comp></comp>",
props:{
jack:{
type: Boolean,
default: true
}
},
data(){
console.log('Inside parent:', this.jack)
return {}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id='root'>
<button @click="clickMe()" >Click Me</button>
</div>
Upvotes: 1