| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- var _ = require('../util')
- var config = require('../config')
- var Dep = require('./dep')
- var arrayMethods = require('./array')
- var arrayKeys = Object.getOwnPropertyNames(arrayMethods)
- require('./object')
- /**
- * 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.
- *
- * @param {Array|Object} value
- * @constructor
- */
- function Observer (value) {
- this.value = value
- this.dep = new Dep()
- _.define(value, '__ob__', this)
- if (_.isArray(value)) {
- var augment = config.proto && _.hasProto
- ? protoAugment
- : copyAugment
- augment(value, arrayMethods, arrayKeys)
- this.observeArray(value)
- } else if (_.isPlainObject(value)) {
- this.walk(value)
- }
- }
- // Static methods
- /**
- * 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.
- *
- * @param {*} value
- * @param {Vue} [vm]
- * @return {Observer|undefined}
- * @static
- */
- Observer.create = function (value, vm) {
- var ob
- if (
- value &&
- value.hasOwnProperty('__ob__') &&
- value.__ob__ instanceof Observer
- ) {
- ob = value.__ob__
- } else if (
- _.isObject(value) &&
- !Object.isFrozen(value) &&
- !value._isVue
- ) {
- ob = new Observer(value)
- }
- if (ob && vm) {
- ob.addVm(vm)
- }
- return ob
- }
- // Instance methods
- /**
- * Walk through each property and convert them into
- * getter/setters. This method should only be called when
- * value type is Object. Properties prefixed with `$` or `_`
- * and accessor properties are ignored.
- *
- * @param {Object} obj
- */
- Observer.prototype.walk = function (obj) {
- var keys = Object.keys(obj)
- var i = keys.length
- while (i--) {
- this.convert(keys[i], obj[keys[i]])
- }
- }
- /**
- * Try to carete an observer for a child value,
- * and if value is array, link dep to the array.
- *
- * @param {*} val
- * @return {Dep|undefined}
- */
- Observer.prototype.observe = function (val) {
- return Observer.create(val)
- }
- /**
- * Observe a list of Array items.
- *
- * @param {Array} items
- */
- Observer.prototype.observeArray = function (items) {
- var i = items.length
- while (i--) {
- this.observe(items[i])
- }
- }
- /**
- * Convert a property into getter/setter so we can emit
- * the events when the property is accessed/changed.
- *
- * @param {String} key
- * @param {*} val
- */
- Observer.prototype.convert = function (key, val) {
- var ob = this
- var childOb = ob.observe(val)
- var dep = new Dep()
- Object.defineProperty(ob.value, key, {
- enumerable: true,
- configurable: true,
- get: function () {
- if (Dep.target) {
- dep.depend()
- if (childOb) {
- childOb.dep.depend()
- }
- if (_.isArray(val)) {
- for (var e, i = 0, l = val.length; i < l; i++) {
- e = val[i]
- e && e.__ob__ && e.__ob__.dep.depend()
- }
- }
- }
- return val
- },
- set: function (newVal) {
- if (newVal === val) return
- val = newVal
- childOb = ob.observe(newVal)
- dep.notify()
- }
- })
- }
- /**
- * Add an owner vm, so that when $add/$delete mutations
- * happen we can notify owner vms to proxy the keys and
- * digest the watchers. This is only called when the object
- * is observed as an instance's root $data.
- *
- * @param {Vue} vm
- */
- Observer.prototype.addVm = function (vm) {
- (this.vms || (this.vms = [])).push(vm)
- }
- /**
- * Remove an owner vm. This is called when the object is
- * swapped out as an instance's $data object.
- *
- * @param {Vue} vm
- */
- Observer.prototype.removeVm = function (vm) {
- this.vms.$remove(vm)
- }
- // helpers
- /**
- * Augment an target Object or Array by intercepting
- * the prototype chain using __proto__
- *
- * @param {Object|Array} target
- * @param {Object} proto
- */
- function protoAugment (target, src) {
- target.__proto__ = src
- }
- /**
- * Augment an target Object or Array by defining
- * hidden properties.
- *
- * @param {Object|Array} target
- * @param {Object} proto
- */
- function copyAugment (target, src, keys) {
- var i = keys.length
- var key
- while (i--) {
- key = keys[i]
- _.define(target, key, src[key])
- }
- }
- module.exports = Observer
|