vue-computed的简单实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <input id="index--input" value="">
</div>
data: <p id="index--p"></p>
computed: <p id="index--computed"></p>
</body>
<script type="text/javascript">

    function Deb() {
        this.subs = []
        this.addSub = function (cb) {
            this.subs.push(cb)
        }
        this.notify = function (value) {
            this.subs.forEach(cb => {
                cb(value)
            })
        }
    }
    function defineReactive(obj, key, value) {
        let deb = new Deb()
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get() {
                console.log('get method called')
                if(window.cb){
                    deb.addSub(window.cb)
                }
                return value
            },
            set(v) {
                console.log('set method called')
                if(v === value){
                    return
                }else {
                    value = v
                    deb.notify(v)
                }
            }
        })
    }

    function observer(obj) {
        for(let key in obj){
            let value = obj[key]
            if(typeof value === 'object'){
                observer(value)
            }
            defineReactive(obj, key, value)
        }
    }

    function Watcher(obj, key, cb) {
        window.cb = cb
        let value = obj[key]
        window.cb = null
    }

    obj = {
        name: 'jack',
        age: 23,
        value: '',
        address: {
            country: 'usa',
            county: 'newYork'
        }
    }

    observer(obj)
    new Watcher(obj, 'value', function (value) {
        document.getElementById('index--p').innerHTML = value
    })

    // simple computed
    function defineComputed(obj, key, constructor) {
        let value = null
        let computed = true
        let deb = new Deb()
        let callback = function () {
            computed = false
            deb.notify(obj[key])
            console.log(value)
        }
        window.cb = callback
        value = constructor.call(obj)
        window.cb = null
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get() {
                if(window.computedCallback){
                    deb.addSub(window.computedCallback)
                }
                console.log('computed')
                if(!computed){
                    console.log('dependencies changed, evaluating...')
                    value = constructor.call(obj)
                    computed = true
                }
                return value
            },
            set(v) {

            }
        })
    }
    function computedWatcher(obj, key, callback) {
        window.computedCallback = callback
        let value = obj[key]
        window.computedCallback = null
    }
    defineComputed(obj, 'detail', function () {
        return `${this.name}-${this.age}-${this.value}`
    })
    new computedWatcher(obj, 'detail', function (value) {
        console.log('computed property changed')
        document.getElementById('index--computed').innerHTML = value
    })
    window.onload = function () {
        window.addEventListener('input', function (event) {
            obj.value = event.target.value
        })
    }
</script>
</html>