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
}

运行avalon.define()发生的事情的更多相关文章

  1. [C# 基础知识系列]专题五:当点击按钮时触发Click事件背后发生的事情 (转载)

    当我们在点击窗口中的Button控件VS会帮我们自动生成一些代码,我们只需要在Click方法中写一些自己的代码就可以实现触发Click事件后我们Click方法中代码就会执行,然而我一直有一个疑问的—— ...

  2. Vue生命周期各阶段发生的事情

    首先,参考之前一篇vue生命周期的总结:Vue生命周期总结 接下来我们来分析下官方文档经典流程图,每个阶段到底发生了什么事情. 1.在beforeCreate和created钩子函数之间的生命周期 在 ...

  3. 安装meteor运行基本demo发生错误。

    bogon:~ paul$ curl https://install.meteor.com/ | sh % Total % Received % Xferd Average Speed Time Ti ...

  4. [Android]新版的sdk中新建一个android应用,增加的PlaceholderFragment这个静态类发生的事情

    1,首先发生的是有两个布局xml,一个activity_main.xml,一个是fragment_main.xml一开始没在意,后来仔细看了原来是新功能的fragment概念等于多个场景在这个acti ...

  5. 输入 URL 到页面完成加载过程中的所有发生的事情?

    转到浏览器中输入URL给你一个页面后,.有些事情,你每天都在使用,学的是计算机网络知道是怎么回事.DNS解析然后页面的回馈,只是要讲好还是有难度. 之前fex团队的nwind专门写过这个问题的博客: ...

  6. WinForm程序运行 Just-In-Time Exception发生时

    debug时运行正常, 但exe程序却发生Just-In-Time Exception (具体是做了异步里面更新画面内容) 解决对策: [app.config]文件: jitDebugging设为tu ...

  7. 关于 unsigned 型变量在计算过程中发生的事情

    运行环境:CentOS release 5.8 (Final) #include<stdio.h> #include<iostream> using namespace std ...

  8. 《超级IP》:伪理论,没能比现有的市场营销理论更高明,只敢勉强去解释已经发生的事情,不敢去预测未来。2星。

    超级IP是作者造出来的一个词.作者尝试把“超级IP”作为一种理论来解释2015年以来的各种网红现象.读完全书后,我的感觉是这个理论不怎么样: 1:作者完全不提现有的市场营销理论.我的问题是:现有的理论 ...

  9. 黄聪:visual studio 2017编译运行出现脚本发生错误等问题如何解决?

    升级VS2017后,编译运行程序会出现 /Community/Common7/IDE/PrivateAssemblies/plugin.vs.js 错误 先说VS2017-15.6.1跟旧版本IE的兼 ...

随机推荐

  1. 快速高效的破解MySQL本地和远程密码

    http://www.kankanews.com/ICkengine/archives/212.shtml 快速的 MySQL 本地和远程密码破解!首先需要对数据库维护人员说明的是,不必紧张,你无需修 ...

  2. iOS数据库之查找功能的实现

    首先引入文件: libsqlite3. FMDB(包含Global.m,Global.h文件) 关闭arc 用mesaSqlite创建一个数据库,引入文件中 其次: 首先,在Global.h文件中找到 ...

  3. javascript进击(八)JSON

    JSON 是存储和交换文本信息的语法.类似 XML. JSON 比 XML 更小.更快,更易解析. 什么是 JSON ? JSON 指的是 JavaScript 对象表示法(JavaScript Ob ...

  4. verilog中的task用法

    任务就是一段封装在“task-endtask”之间的程序.任务是通过调用来执行的,而且只有在调用时才执行,如果定义了任务,但是在整个过程中都没有调用它,那么这个任务是不会执行的.调用某个任务时可能需要 ...

  5. jquery无法读取json文件问题

    jquery无法读取json文件,如:user.json文件无法读取.把user.json文件的后缀名修改为aspx,文件内容不变,则可以读取~ 原理不懂!~~

  6. Socket的3次握手链接与4次断开握手

    http://blog.sina.com.cn/s/blog_810c860001018tir.html 连接握手: 1.客户端发送建立连接请求 2.服务端确认连接请求 3.客户端确认已经连接 以上3 ...

  7. java编写一个端口扫描器

    好久没写java了,学的时候,也没学习网络编程这一块,无意中看到了一本书,于是小小复习一下java,写个端口扫描器,玩玩吧,网上这种小公具有的是,就是自己无聊写着玩玩. 源代码如下: 共两个类,比较简 ...

  8. springmvc中url-pattern的大坑

    <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springfr ...

  9. @Resource注解省略name属性后的行为

    @Resource有一个name属性,该属性值为所要注入的Bean实例的id,类似于<property.../>元素的ref属性,不过在spring中允许省略name属性值,省略后在以下情 ...

  10. ArcGis for WPF(1)

    这篇文章主要是讲窗体中怎么加载一张在线地图. 第一步:首先引用ESRI.ArcGIS.Client.dll类库. 第二步:在XAML中添加如下代码: <Window x:Class=" ...