读vue-0.6-observer.js源码
实现监听数组方法
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源码的更多相关文章
- vue.js源码精析
MVVM大比拼之vue.js源码精析 VUE 源码分析 简介 Vue 是 MVVM 框架中的新贵,如果我没记错的话作者应该毕业不久,现在在google.vue 如作者自己所说,在api设计上受到了很多 ...
- 从template到DOM(Vue.js源码角度看内部运行机制)
写在前面 这篇文章算是对最近写的一系列Vue.js源码的文章(https://github.com/answershuto/learnVue)的总结吧,在阅读源码的过程中也确实受益匪浅,希望自己的这些 ...
- 从Vue.js源码角度再看数据绑定
写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...
- 【转】从Vue.js源码看异步更新DOM策略及nextTick
在使用vue.js的时候,有时候因为一些特定的业务场景,不得不去操作DOM,比如这样: <template> <div> <div ref="test" ...
- Vue.js源码——事件机制
写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出.文章的原地址:https://github.com/an ...
- Vue.js 源码分析(一) 代码结构
关于Vue vue是一个兴起的前端js库,是一个精简的MVVM.MVVM模式是由经典的软件架构MVC衍生来的,当View(视图层)变化时,会自动更新到ViewModel(视图模型),反之亦然,View ...
- Vue.js 源码构建(三)
Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下. 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.json 文件,它是对项目的描述文 ...
- vue源码分析—Vue.js 源码构建
Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下.(Rollup 中文网和英文网) 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.j ...
- 2018-11-23 手工翻译Vue.js源码:尝试重命名标识符与文本
续前文: 手工翻译Vue.js源码第一步:14个文件重命名 对core/instance/索引中的变量, 方法进行重命名如下(题图): import { 混入初始化 } from './初始化' im ...
- vue.js源码学习分享(一)
今天看了vue.js源码 发现非常不错,想一边看一遍写博客和大家分享 /** * Convert a value to a string that is actually rendered. *转换 ...
随机推荐
- centOS7搭建nexus私服
1.保证JDK,MAVEN已安装,firewalld服务安装 PS:yum install firewalld 2.官网下载:https://www.sonatype.com/download-oss ...
- highcharts echarts比较
1,highcharts底层是svg echarts底层是canvas 2,svg和canvas的区别 canvas 依赖分辨率 不支持事件处理器 弱的文本渲染能力 能够以 .png 或 .jpg 格 ...
- Django 载入静态文件地址
1,Django框架中有专门存放静态文件的目录. 项目中的CSS.图片.js都是静态文件 配置静态文件 在settings 文件中定义静态内容 2,这些静态文件,他们统一存放在项目目录,templat ...
- form表单保存和取出
function saveConfig() { var configName = document.title; if (!localStorage) return; var Config = {}; ...
- Hibernate 和 Mybatis 两者相比的优缺点
1.开发上手难度 hibernate的真正掌握(封装的功能和特性非常多)要比Mybatis来得难. 在真正产品级应用上要用Hibernate,不仅对开发人员的要求高,hibernate往往还不适合(多 ...
- Anton 上课题
Anton 上课题 Anton likes to play chess. Also he likes to do programming. No wonder that he decided to a ...
- WPF中TreeView的+-号和连线style的一种实现
最近又开始跟WPF打交道,项目里面用到了TreeView这个控件.然后需要有一个连线的外观就像是这样 二话不说,百度了一下,找到一个实现, 通道. 把代码拷贝到项目里面,跑了一下,看上去还不错.但是这 ...
- 第二十四节:Java语言基础-讲解数组的综合应用
数组的综合应用 // 打印数组 public static void printArray(int[] arr) { for(int x=0;x<arr.length;x++) { if(x!= ...
- JavaScript的BOM编程,事件-第4章
目标 BOM编程 window和document对象 window对象的属性和方法 document对象的属性和方法 JavaScript中对象的分类 浏览器对象:window对象 window对象, ...
- spring框架学习笔记3:使用注解代替配置文件
1.导入context约束:spring-context-4.2.xsd 2.design模式打开xml配置文件,右键edit namespaces,点击add添加 完成后应该是这样: 配置文件中这样 ...