运行avalon.define()发生的事情

 
avalon.define = function(id, factory) {
    var $id = id.$id || id
    if (!$id) {
        log("warning: vm必须指定$id")
    }
    if (VMODELS[$id]) {
        log("warning: " + $id + " 已经存在于avalon.vmodels中")
    }
    if (typeof id === "object") {
        var model = modelFactory(id)
    } else {
        var scope = {
            $watch: noop
        }
        factory(scope) //得到所有定义
        model = modelFactory(scope) //偷天换日,将scope换为model
        stopRepeatAssign = true
        factory(model)
        stopRepeatAssign = false
    }
    model.$id = $id
    return VMODELS[$id] = model
}
avalon.define源代码

运行这段代码的过程中,会把id在modelFactory中进行加工

function modelFactory(source, $special, $model) {
    if (Array.isArray(source)) {
        var arr = source.concat()
        source.length = 0
        var collection = Collection(source)
        collection.pushArray(arr)
        return collection
    }
    if (typeof source.nodeType === "number") {
        return source
    }
    if (source.$id && source.$events) { //fix IE6-8 createWithProxy $val: val引发的BUG
        return source
    }
    if (!Array.isArray(source.$skipArray)) {
        source.$skipArray = []
    }
    source.$skipArray.$special = $special || {} //强制要监听的属性
    var $vmodel = {} //要返回的对象, 它在IE6-8下可能被偷龙转凤
    $model = $model || {} //vmodels.$model属性
    var $events = {} //vmodel.$events属性
    var watchedProperties = {} //监控属性
    var initCallbacks = [] //初始化才执行的函数
    for (var i in source) {
        (function(name, val) {
            $model[name] = val
            if (!isObservable(name, val, source.$skipArray)) {
                return //过滤所有非监控属性
            }
            //总共产生三种accessor
            $events[name] = []
            var valueType = avalon.type(val)
            var accessor = function(newValue) {
                var name = accessor._name
                var $vmodel = this
                var $model = $vmodel.$model
                var oldValue = $model[name]
                var $events = $vmodel.$events

                if (arguments.length) {
                    if (stopRepeatAssign) {
                        return
                    }
                    //计算属性与对象属性需要重新计算newValue
                    if (accessor.type !== 1) {
                        newValue = getNewValue(accessor, name, newValue, $vmodel)
                    }
                    if (!isEqual(oldValue, newValue)) {
                        $model[name] = newValue
                        if ($events.$digest) {
                            if (accessor.pedding)
                                return
                            accessor.pedding = true
                            setTimeout(function() {
                                notifySubscribers($events[name]) //同步视图
                                safeFire($vmodel, name, $model[name], oldValue) //触发$watch回调
                                accessor.pedding = false
                            })
                        } else {
                            notifySubscribers($events[name]) //同步视图
                            safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
                        }
                    }
                } else {
                    if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性
                        //计算属性不需要收集视图刷新函数,都是由其他监控属性代劳
                        return $model[name] = accessor.get.call($vmodel)
                    } else {
                        collectSubscribers($events[name]) //收集视图函数
                        return accessor.svmodel || oldValue
                    }
                }
            }
            //总共产生三种accessor
            if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) {
                //第1种为计算属性, 因变量,通过其他监控属性触发其改变
                accessor.set = val.set
                accessor.get = val.get
                accessor.type = 0
                initCallbacks.push(function() {
                    var data = {
                        evaluator: function() {
                            data.element = null
                            data.type = new Date - 0
                            $model[name] = accessor.get.call($vmodel)
                        },
                        element: head,
                        type: new Date - 0,
                        handler: noop,
                        args: []
                    }
                    Registry[expose] = data
                    accessor.call($vmodel)
                    delete Registry[expose]
                })
            } else if (rcomplexType.test(valueType)) {
                //第2种为对象属性,产生子VM与监控数组
                accessor.type = 2
                accessor.valueType = valueType
                initCallbacks.push(function() {
                    var svmodel = modelFactory(val, 0, $model[name])
                    accessor.svmodel = svmodel
                    svmodel.$events[subscribers] = $events[name]
                })
            } else {
                accessor.type = 1
                //第3种为监控属性,对应简单的数据类型,自变量
            }
            accessor._name = name
            /*给需要监控的属性添加set和get方法*/
            watchedProperties[name] = accessor
        })(i, source[i])
    }

    $$skipArray.forEach(function(name) {
        delete source[name]
        delete $model[name] //这些特殊属性不应该在$model中出现
    })
/* 下面方法是给属性生成如下格式:
 * var descriptorFactory = W3C ? function(obj) {
    var descriptors = {}
    for (var i in obj) {
        descriptors[i] = {
            get: obj[i],
            set: obj[i],
            enumerable: true,
            configurable: true
        }
    }
    return descriptors
} : function(a) {
    return a
}
 */
    $vmodel = defineProperties($vmodel, descriptorFactory(watchedProperties), source) //生成一个空的ViewModel
    for (var name in source) {
        if (!watchedProperties[name]) {
            $vmodel[name] = source[name]
        }
    }
    //添加$id, $model, $events, $watch, $unwatch, $fire
    $vmodel.$id = generateID()
    $vmodel.$model = $model
    $vmodel.$events = $events
    for (var i in EventBus) {
        var fn = EventBus[i]
        if (!W3C) { //在IE6-8下,VB对象的方法里的this并不指向自身,需要用bind处理一下
            fn = fn.bind($vmodel)
        }
        $vmodel[i] = fn
    }

    if (canHideOwn) {
        Object.defineProperty($vmodel, "hasOwnProperty", {
            value: function(name) {
                return name in this.$model
            },
            writable: false,
            enumerable: false,
            configurable: true
        })

    } else {
        $vmodel.hasOwnProperty = function(name) {
            return name in $vmodel.$model
        }
    }
    initCallbacks.forEach(function(cb) { //收集依赖
        cb()
    })
    return $vmodel
}
just do myself
原文地址:https://www.cnblogs.com/rookieCat/p/4633434.html