创建一个用来观察对象的observe类,这个类会附加在被观察的对象上,并且把被观察对象的属性值转换成getter/setter,同时,收集依赖和分发更新,实现代码如下:

/*
* not type checking this file because flow doesn't play well with
* dynamically accessing methods on Array prototype
*/ var arrayProto = Array.prototype;
var arrayMethods = Object.create(arrayProto);[
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
.forEach(function (method) {
// cache original method
var original = arrayProto[method];
def(arrayMethods, method, function mutator () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ]; var result = original.apply(this, args);
var ob = this.__ob__;
var inserted;
switch (method) {
case 'push':
case 'unshift':
inserted = args;
break
case 'splice':
inserted = args.slice(2);
break
}
if (inserted) { ob.observeArray(inserted); }
// notify change
ob.dep.notify();
return result
});
}); /* */ var arrayKeys = Object.getOwnPropertyNames(arrayMethods); /**
* By default, when a reactive property is set, the new value is
* also converted to become reactive. However when passing down props,
* we don't want to force conversion because the value may be a nested value
* under a frozen data structure. Converting it would defeat the optimization.
*/
var observerState = {
shouldConvert: true
}; /**
* Observer class that are attached to each observed
* object. Once attached, the observer converts target
* object's property keys into getter/setters that
* collect dependencies and dispatches updates.
*/
var Observer = function Observer (value) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
def(value, '__ob__', this);
if (Array.isArray(value)) {
var augment = hasProto
? protoAugment
: copyAugment;
augment(value, arrayMethods, arrayKeys);
this.observeArray(value);
} else {
this.walk(value);
}
}; /**
* Walk through each property and convert them into
* getter/setters. This method should only be called when
* value type is Object.
*/
Observer.prototype.walk = function walk (obj) {
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i], obj[keys[i]]);
}
}; /**
* Observe a list of Array items.
*/
Observer.prototype.observeArray = function observeArray (items) {
for (var i = 0, l = items.length; i < l; i++) {
observe(items[i]);
}
}; // helpers /**
* Augment an target Object or Array by intercepting
* the prototype chain using __proto__
*/
function protoAugment (target, src, keys) {
/* eslint-disable no-proto */
target.__proto__ = src;
/* eslint-enable no-proto */
} /**
* Augment an target Object or Array by defining
* hidden properties.
*/
/* istanbul ignore next */
function copyAugment (target, src, keys) {
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
def(target, key, src[key]);
}
} /**
* Attempt to create an observer instance for a value,
* returns the new observer if successfully observed,
* or the existing observer if the value already has one.
*/
function observe (value, asRootData) {
if (!isObject(value) || value instanceof VNode) {
return
}
var ob;
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__;
} else if (
observerState.shouldConvert &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value);
}
if (asRootData && ob) {
ob.vmCount++;
}
return ob
} /**
* Define a reactive property on an Object.
*/
function defineReactive (
obj,
key,
val,
customSetter,
shallow
) {
var dep = new Dep(); var property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) {
return
} // cater for pre-defined getter/setters
var getter = property && property.get;
var setter = property && property.set; var childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if ("development" !== 'production' && customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
dep.notify();
}
});
} /**
* Set a property on an object. Adds the new property and
* triggers change notification if the property doesn't
* already exist.
*/
function set (target, key, val) {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
return val
}
if (hasOwn(target, key)) {
target[key] = val;
return val
}
var ob = (target).__ob__;
if (target._isVue || (ob && ob.vmCount)) {
"development" !== 'production' && warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.'
);
return val
}
if (!ob) {
target[key] = val;
return val
}
defineReactive(ob.value, key, val);
ob.dep.notify();
return val
} /**
* Delete a property and trigger change if necessary.
*/
function del (target, key) {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.splice(key, 1);
return
}
var ob = (target).__ob__;
if (target._isVue || (ob && ob.vmCount)) {
"development" !== 'production' && warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
'- just set it to null.'
);
return
}
if (!hasOwn(target, key)) {
return
}
delete target[key];
if (!ob) {
return
}
ob.dep.notify();
} /**
* Collect dependencies on array elements when the array is touched, since
* we cannot intercept array element access like property getters.
*/
function dependArray (value) {
for (var e = (void 0), i = 0, l = value.length; i < l; i++) {
e = value[i];
e && e.__ob__ && e.__ob__.dep.depend();
if (Array.isArray(e)) {
dependArray(e);
}
}
} /* */

vuejs源码摘抄(二)的更多相关文章

  1. vuejs源码摘抄

    订阅功能的部分实现代码如下: /* */ var uid = 0; /** * A dep is an observable that can have multiple * directives s ...

  2. vueJs 源码解析 (三) 具体代码

    vueJs 源码解析 (三) 具体代码 在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm.compiler.watcher 这三要素,那么今天我们就从这三 ...

  3. VueJs 源码解析 (四) initRender.Js

    vueJs 源码解析 (四) initRender.Js 在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm.compiler.watcher 这三要素,那 ...

  4. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  5. Netty 源码(二)NioEventLoop 之 Channel 注册

    Netty 源码(二)NioEventLoop 之 Channel 注册 Netty 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) 一 ...

  6. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  7. Zookeeper 源码(二)序列化组件 Jute

    Zookeeper 源码(二)序列化组件 Jute 一.序列化组件 Jute 对于一个网络通信,首先需要解决的就是对数据的序列化和反序列化处理,在 ZooKeeper 中,使用了Jute 这一序列化组 ...

  8. 一点一点看JDK源码(二)java.util.List

    一点一点看JDK源码(二)java.util.List liuyuhang原创,未经允许进制转载 本文举例使用的是JDK8的API 目录:一点一点看JDK源码(〇) 1.综述 List译为表,一览表, ...

  9. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

随机推荐

  1. js 任意元素解绑任意事件的兼容代码

    hmtl代码: <input type="button" value="按钮" id="btn"/> <input typ ...

  2. js innerText、textContent、innerHTML的区别和各自用法

    //自定义函数 function my$(id) { return document.getElementById(id); } //点击按钮设置div中的文本内容 my$("btn&quo ...

  3. Maven学习笔记(二)—— 整合SSH框架

    一.知识点准备 1.1 什么是依赖传递? 我们只添加一个struts2-core的依赖,结果会发现所有关于struts2的依赖都进来了. 因为我们的项目依赖struts2-core-2.3.24.ja ...

  4. 009 Android Fragment动态用法(实现动态菜单栏)设置控件为满屏状态

    ·1.MainActivity采用线性布局 2.在app--->res--->layout,右击new--->xml---->layout xml FILE <1> ...

  5. 【算法笔记】B1032 挖掘机技术哪家强

    1032 挖掘机技术哪家强 (20 分) 为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛.现请你根据比赛结果统计出技术最强的那个学校. 输入格式: 输入在第 1 行给出不超过 1 ...

  6. vue项目用webpack打包后跨域问题

    在app.js的最开始加上 app.all('*', (req, res, next) => { res.header("Access-Control-Allow-Origin&quo ...

  7. dataTable 加了竖向滚动条导致列头样式错位的问题 / 亲测可用,不好用你打我,用好了记得点推荐

    tab在没有显示之前,容器是没有高度宽度的,而dt在自动计算高度和宽度时是获取的外部容器的高度和宽度,当切换tab时,dt获取不到这个高度宽度,导致列头都挤在一起,是用下面代码解决此问题 $('a[d ...

  8. Oracle 11g 记录DML错误数据

    [From] https://oracle-base.com/articles/10g/dml-error-logging-10gr2 需要记录下大量DML操作中出错的具体record,看到有两种方案 ...

  9. C++ GUI Qt4编程(12)-6.1FindFileDialog

    1. 主要介绍了QGridLayout, QHBoxLayout, QVBoxLayout3种布局管理器的使用方法. 2. 在linux中,继承自QDialog的对话框,没有最大化.最小化.关闭按钮, ...

  10. PIE SDK克里金插值法

    1.算法功能简介 克里金插值法基于一般最小二乘法的随机插值技术没用方差图作为权重函数,被应用于任何点数据估计其在地表上分布的现象,被称为空间自协方差最佳插值法,是一种最优内插法也是一种最常用的空间插值 ...