实现监听数组方法

var ArrayProxy = Object.create(Array.prototype),
methods = ['push','pop','shift','unshift','splice','sort','reverse'];
function defProtected(obj, key, val, enumerable, configurable) {
// 如果是用户添加的方法则不监听
if (obj.hasOwnProperty(key)) return
Object.defineProperty(obj, key, {
value : val,
// 不可枚举
enumerable : !!enumerable,
// 不可配置
configurable : !!configurable
})
}
// 监听原生数组方法
methods.forEach(function (method) {
// ArrayProxy监听的对象 ,method监听的方法,第三个返回一个value
defProtected(ArrayProxy, method, function () {
// 这里面的this表示当前调用的数组
var result = Array.prototype[method].apply(this, arguments)
// 调用数组的__observer__里面的emit方法,触发更新。
this.__observer__.emit('mutate', this.__observer__.path, this, {
method: method,
args: slice.call(arguments),
result: result
})
return result
}, !hasProto)
});

我们可以看到在这段代码中并没有对数组进行get和set监听,这也是为什么在vue中给数组直接赋值不会触发更新的主要原因。

数组remove和replace方法

var hasProto = ({}).__proto__;

function def(obj, key, val, enumerable, configurable) {
if (obj.hasOwnProperty(key)) return
Object.defineProperty(obj, key, {
value : val,
enumerable : !!enumerable,
configurable : !!configurable
})
} var ArrayProxy = Object.create(Array.prototype); // 给数组添加remove和replace方法
var extensions = {
remove: function (index) {
/*
如果index是一个函数,则调用这个函数并且判断返回值,如果返回值为true则删除,false不删除 比如下面这个,删除index大于5的项
remove(function(index){
return index > 5;
}); */
if (typeof index === 'function') {
var i = this.length,
removed = []
while (i--) {
if (index(this[i])) {
removed.push(this.splice(i, 1)[0])
}
}
// 将删除的项返回,返回后为新数组
return removed.reverse()
} else {
// 这个判断是为了实现如果数组项是字符串也能删除
if (typeof index !== 'number') {
index = this.indexOf(index)
}
if (index > -1) {
return this.splice(index, 1)[0]
}
}
},
replace: function (index, data) {
if (typeof index === 'function') {
var i = this.length,
replaced = [],
replacer
while (i--) {
replacer = index(this[i])
/* 这里之所以不是直接判断if(replacer)是因为这里的目的就是实现替换功能,而如果值不是undefined说明用户有返回值而只要有返回值就应该给它替换。 */
if (replacer !== undefined) {
replaced.push(this.splice(i, 1, replacer)[0])
}
}
return replaced.reverse()
} else {
if (typeof index !== 'number') {
index = this.indexOf(index)
}
if (index > -1) {
return this.splice(index, 1, data)[0]
}
}
}
} for (var method in extensions) {
// 给ArrayProxy原型添加remove,replace方法,并且监听
def(ArrayProxy, method, extensions[method], !hasProto)
}

实现监听对象方法

/**
* 根据类型观察对象,入口
*/
function watch (obj, path, observer) {
var type = typeOf(obj)
if (type === 'Object') {
watchObject(obj, path, observer)
} else if (type === 'Array') {
watchArray(obj, path, observer)
}
} /**
* 监听对象变化,但不监听对象中开头为$和_的属性和方法,入口
*/
function watchObject (obj, path, observer) {
for (var key in obj) {
var keyPrefix = key.charAt(0)
if (keyPrefix !== '$' && keyPrefix !== '_') {
bind(obj, key, path, observer)
}
}
} /**
* 监听数组方法,并将其原型挂载到ArrayProxy上,入口
* ArrayProxy方法实现了一些变异的数组方法以及扩展,这是实现对数组方法监听的基础
*/
function watchArray (arr, path, observer) {
def(arr, '__observer__', observer)
observer.path = path
if (hasProto) {
arr.__proto__ = ArrayProxy
} else {
for (var key in ArrayProxy) {
def(arr, key, ArrayProxy[key])
}
}
} /*
* 具体实现对象监听的方法
*/
function bind (obj, key, path, observer) {
var val = obj[key],
watchable = isWatchable(val),
values = observer.values,
fullKey = (path ? path + '.' : '') + key
values[fullKey] = val
// 触发set事件
observer.emit('set', fullKey, val)
Object.defineProperty(obj, key, {
enumerable: true,
get: function () {
// only emit get on tip values
if (depsOb.active && !watchable) {
observer.emit('get', fullKey)
}
return values[fullKey]
},
set: function (newVal) {
values[fullKey] = newVal
ensurePaths(key, newVal, values)
observer.emit('set', fullKey, newVal)
// 被赋值,监听新对象
watch(newVal, fullKey, observer)
}
})
watch(val, fullKey, observer)
} /**
* 只监听数组和对象
*/
function isWatchable (obj) {
var type = typeOf(obj)
return type === 'Object' || type === 'Array'
}

读vue-0.6-observer.js源码的更多相关文章

  1. vue.js源码精析

    MVVM大比拼之vue.js源码精析 VUE 源码分析 简介 Vue 是 MVVM 框架中的新贵,如果我没记错的话作者应该毕业不久,现在在google.vue 如作者自己所说,在api设计上受到了很多 ...

  2. 从template到DOM(Vue.js源码角度看内部运行机制)

    写在前面 这篇文章算是对最近写的一系列Vue.js源码的文章(https://github.com/answershuto/learnVue)的总结吧,在阅读源码的过程中也确实受益匪浅,希望自己的这些 ...

  3. 从Vue.js源码角度再看数据绑定

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...

  4. 【转】从Vue.js源码看异步更新DOM策略及nextTick

    在使用vue.js的时候,有时候因为一些特定的业务场景,不得不去操作DOM,比如这样: <template> <div> <div ref="test" ...

  5. Vue.js源码——事件机制

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...

  6. Vue.js 源码分析(一) 代码结构

    关于Vue vue是一个兴起的前端js库,是一个精简的MVVM.MVVM模式是由经典的软件架构MVC衍生来的,当View(视图层)变化时,会自动更新到ViewModel(视图模型),反之亦然,View ...

  7. Vue.js 源码构建(三)

    Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下. 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.json 文件,它是对项目的描述文 ...

  8. vue源码分析—Vue.js 源码构建

    Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下.(Rollup 中文网和英文网) 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.j ...

  9. 2018-11-23 手工翻译Vue.js源码:尝试重命名标识符与文本

    续前文: 手工翻译Vue.js源码第一步:14个文件重命名 对core/instance/索引中的变量, 方法进行重命名如下(题图): import { 混入初始化 } from './初始化' im ...

  10. vue.js源码学习分享(一)

    今天看了vue.js源码  发现非常不错,想一边看一遍写博客和大家分享 /** * Convert a value to a string that is actually rendered. *转换 ...

随机推荐

  1. sql语句-单表查询

    一:单表查询 CREATE TABLE `Score`( `s_id` ), `c_id` ), `s_score` ), PRIMARY KEY(`s_id`,`c_id`) ); ); ); ); ...

  2. 学习pyyaml

    网上查了一圈,觉得较好的yaml教程有: YAML 语言教程 :http://www.ruanyifeng.com/blog/2016/07/yaml.html. 另外,在github的pyyaml库 ...

  3. virtual关键字

    出于多态的考虑,为了覆盖, 子类同名覆盖函数(函数名.参数.返回值都相同) virtual void print(): 这也许会使人联想到函数的重载,但稍加对比就会发现两者是完全不同的:(1)重载的几 ...

  4. Latex命令

    .tex代码中 |   在pdf文档中 空一行  代表回车,下一行空两格 // 代表回车,下一行顶格

  5. SWPU-ACM集训队周赛之组队赛(3-11) C题题解

    点这里去看题 模拟,注意细节 #include<stdio.h> #include<string.h> int main() { ]; //q[]储存正负信息 scanf(&q ...

  6. 带权单源最短路[稀疏图](Dijkstra)

    因为是稀疏图,所以应当选择邻接表来存储 构造一个邻接表 这只是我的构造方法,有很多种更好的构造方法,大家可以自己去构造 typedef int vertex; typedef int WeightTy ...

  7. React Native学习方法论

    这是我技术公众号的第一篇文章,也是React Native系列文章的第一篇,对我的文章感兴趣的可以加我微信16230091进行关注. 本文表面上讲React Native(以下简称RN),实际上对于学 ...

  8. Android一些日常的错误

    一.加载.so出现的一些问题 1. so文件 放进了优先级低的ABI目录 问题:如果你的项目中,有其他优先级更好的ABI目录,但是你把ABI文件方法放到了优先级低的目录,最后导致你的ABI文件无法被加 ...

  9. Android网络请求与数据解析,使用Gson和GsonFormat解析复杂Json数据

    版权声明:未经博主允许不得转载 一:简介 [达叔有道]软件技术人员,时代作者,从 Android 到全栈之路,我相信你也可以!阅读他的文章,会上瘾!You and me, we are family ...

  10. python中stack在实际中的简单应用之平衡符号

    很多书籍都在讲stack的概念和使用方法,等我们把概念熟悉后,发现不知道在什么场景下使用 该结构体,这里就列几个实用的例子,让大家了解一下stack在实际中的用处和厉害之处. 由于stack中的特点是 ...