Vue.js Internals: How computed properties work
by gongzza
HTML
<div id="app"></div>
JavaScript
// https://medium.com/@kelly.kh.woo/%EB%B2%88%EC%97%AD-vue-js-internals-how-computed-properties-work-366d22c6f0e7
// http://jsbin.com/vevupup/embed?js,console
const app = document.getElementById('app')
const log = (...args) => {
console.log(...args)
app.innerText += args + '\n'
}
const Dep = { target: null }
function defineReactive(obj, key, val) {
const deps = []
Object.defineProperty(obj, key, {
get() {
if (Dep.target && !~deps.indexOf(Dep.target)) {
deps.push(Dep.target)
}
return val
},
set(newVal) {
val = newVal
for (const dep of deps) {
dep()
}
}
})
}
function defineComputed(obj, key, computeFunc, callback) {
function onDependencyUpdated() {
log(`${key} called`)
val = computeFunc()
callback(val)
}
// Set current update callback
Dep.target = onDependencyUpdated;
// Compute the value
let val = computeFunc ();
// Reset the target so no more property adds this as dependency
Dep.target = null;
Object.defineProperty(obj, key, {
get() {
// 다른 computed가 참조할 경우 compute()를 호출해서
// 참조가 추가될 수 있도록 한다.
if (Dep.target) {
onDependencyUpdated()
}
return val
}
})
}
var person = {};
defineReactive (person, 'age', 16);
defineReactive (person, 'country', 'Brazil');
defineComputed (person, 'status', function () {
if (person.age > 18) {
return 'Adult'
}
else {
return 'Minor'
}
}, function (newValue) {
log ("CHANGED!! The person's status is now: " + newValue)
});
defineComputed (person, 'isAdult', function () {
return person.status === 'Adult'
}, function (newValue) {
log ("CHANGED!! The person's isAdult is now: " + newValue)
})
log ("Current age: " + person.age)
log ("Current status: " + person.status)
log("Current isAdult: " + person.isAdult)
// change age
log ("Changing age");
person.age = 22;
log ("Current age: " + person.age)
log ("Current status: " + person.status)
log("Current isAdult: "...