vue.js源码学习分享,九

/*  */

var arrayKeys = Object.getOwnPropertyNames(arrayMethods);//获取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,
  isSettingProps: false
};

/**
 * Observer class that are attached to each observed//观察者类被绑定到每一个观察对象,一旦绑定,这个观察者使目标对象的属性键转换到getter/setter方法,收集依赖和发送的更新
 * 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);//给value定义一个‘——ob——’属性,属性的值为这个Observer对象 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//walk方法穿过每一个属性并且把他们转换到getter或者setter方法。这个方法应当仅在value的类型为对象时候调用 * 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$$1(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//增加一个目标对象或者数组通过用__proto__截取原型链 * the prototype chain using __proto__ */ function protoAugment (target, src) { /* 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不是对象,那么就到此结束 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$$1 ( obj, key, val, customSetter ) { var dep = new Dep(); var property = Object.getOwnPropertyDescriptor(obj, key); if (property && property.configurable === false) { return } // cater for pre-defined getter/setters//满足预定义的 getter/setters var getter = property && property.get; var setter = property && property.set; var childOb = 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 = 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 (obj, key, val) { if (Array.isArray(obj)) { obj.length = Math.max(obj.length, key); obj.splice(key, 1, val); return val } if (hasOwn(obj, key)) { obj[key] = val; return } var ob = obj.__ob__; if (obj._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 } if (!ob) { obj[key] = val; return } defineReactive$$1(ob.value, key, val); ob.dep.notify(); return val } /** * Delete a property and trigger change if necessary. */ function del (obj, key) { if (Array.isArray(obj)) { obj.splice(key, 1); return } var ob = obj.__ob__; if (obj._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(obj, key)) { return } delete obj[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); } } }