github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/instance/internal/state.js (about)

     1  import Watcher from '../../watcher'
     2  import { compileAndLinkProps } from '../../compiler/index'
     3  import Dep from '../../observer/dep'
     4  import {
     5    observe,
     6    defineReactive
     7  } from '../../observer/index'
     8  
     9  import {
    10    warn,
    11    query,
    12    hasOwn,
    13    isReserved,
    14    isPlainObject,
    15    bind
    16  } from '../../util/index'
    17  
    18  export default function (Vue) {
    19    /**
    20     * Accessor for `$data` property, since setting $data
    21     * requires observing the new object and updating
    22     * proxied properties.
    23     */
    24  
    25    Object.defineProperty(Vue.prototype, '$data', {
    26      get () {
    27        return this._data
    28      },
    29      set (newData) {
    30        if (newData !== this._data) {
    31          this._setData(newData)
    32        }
    33      }
    34    })
    35  
    36    /**
    37     * Setup the scope of an instance, which contains:
    38     * - observed data
    39     * - computed properties
    40     * - user methods
    41     * - meta properties
    42     */
    43  
    44    Vue.prototype._initState = function () {
    45      this._initProps()
    46      this._initMeta()
    47      this._initMethods()
    48      this._initData()
    49      this._initComputed()
    50    }
    51  
    52    /**
    53     * Initialize props.
    54     */
    55  
    56    Vue.prototype._initProps = function () {
    57      var options = this.$options
    58      var el = options.el
    59      var props = options.props
    60      if (props && !el) {
    61        process.env.NODE_ENV !== 'production' && warn(
    62          'Props will not be compiled if no `el` option is ' +
    63          'provided at instantiation.',
    64          this
    65        )
    66      }
    67      // make sure to convert string selectors into element now
    68      el = options.el = query(el)
    69      this._propsUnlinkFn = el && el.nodeType === 1 && props
    70        // props must be linked in proper scope if inside v-for
    71        ? compileAndLinkProps(this, el, props, this._scope)
    72        : null
    73    }
    74  
    75    /**
    76     * Initialize the data.
    77     */
    78  
    79    Vue.prototype._initData = function () {
    80      var dataFn = this.$options.data
    81      var data = this._data = dataFn ? dataFn() : {}
    82      if (!isPlainObject(data)) {
    83        data = {}
    84        process.env.NODE_ENV !== 'production' && warn(
    85          'data functions should return an object.',
    86          this
    87        )
    88      }
    89      var props = this._props
    90      // proxy data on instance
    91      var keys = Object.keys(data)
    92      var i, key
    93      i = keys.length
    94      while (i--) {
    95        key = keys[i]
    96        // there are two scenarios where we can proxy a data key:
    97        // 1. it's not already defined as a prop
    98        // 2. it's provided via a instantiation option AND there are no
    99        //    template prop present
   100        if (!props || !hasOwn(props, key)) {
   101          this._proxy(key)
   102        } else if (process.env.NODE_ENV !== 'production') {
   103          warn(
   104            'Data field "' + key + '" is already defined ' +
   105            'as a prop. To provide default value for a prop, use the "default" ' +
   106            'prop option; if you want to pass prop values to an instantiation ' +
   107            'call, use the "propsData" option.',
   108            this
   109          )
   110        }
   111      }
   112      // observe data
   113      observe(data, this)
   114    }
   115  
   116    /**
   117     * Swap the instance's $data. Called in $data's setter.
   118     *
   119     * @param {Object} newData
   120     */
   121  
   122    Vue.prototype._setData = function (newData) {
   123      newData = newData || {}
   124      var oldData = this._data
   125      this._data = newData
   126      var keys, key, i
   127      // unproxy keys not present in new data
   128      keys = Object.keys(oldData)
   129      i = keys.length
   130      while (i--) {
   131        key = keys[i]
   132        if (!(key in newData)) {
   133          this._unproxy(key)
   134        }
   135      }
   136      // proxy keys not already proxied,
   137      // and trigger change for changed values
   138      keys = Object.keys(newData)
   139      i = keys.length
   140      while (i--) {
   141        key = keys[i]
   142        if (!hasOwn(this, key)) {
   143          // new property
   144          this._proxy(key)
   145        }
   146      }
   147      oldData.__ob__.removeVm(this)
   148      observe(newData, this)
   149      this._digest()
   150    }
   151  
   152    /**
   153     * Proxy a property, so that
   154     * vm.prop === vm._data.prop
   155     *
   156     * @param {String} key
   157     */
   158  
   159    Vue.prototype._proxy = function (key) {
   160      if (!isReserved(key)) {
   161        // need to store ref to self here
   162        // because these getter/setters might
   163        // be called by child scopes via
   164        // prototype inheritance.
   165        var self = this
   166        Object.defineProperty(self, key, {
   167          configurable: true,
   168          enumerable: true,
   169          get: function proxyGetter () {
   170            return self._data[key]
   171          },
   172          set: function proxySetter (val) {
   173            self._data[key] = val
   174          }
   175        })
   176      }
   177    }
   178  
   179    /**
   180     * Unproxy a property.
   181     *
   182     * @param {String} key
   183     */
   184  
   185    Vue.prototype._unproxy = function (key) {
   186      if (!isReserved(key)) {
   187        delete this[key]
   188      }
   189    }
   190  
   191    /**
   192     * Force update on every watcher in scope.
   193     */
   194  
   195    Vue.prototype._digest = function () {
   196      for (var i = 0, l = this._watchers.length; i < l; i++) {
   197        this._watchers[i].update(true) // shallow updates
   198      }
   199    }
   200  
   201    /**
   202     * Setup computed properties. They are essentially
   203     * special getter/setters
   204     */
   205  
   206    function noop () {}
   207    Vue.prototype._initComputed = function () {
   208      var computed = this.$options.computed
   209      if (computed) {
   210        for (var key in computed) {
   211          var userDef = computed[key]
   212          var def = {
   213            enumerable: true,
   214            configurable: true
   215          }
   216          if (typeof userDef === 'function') {
   217            def.get = makeComputedGetter(userDef, this)
   218            def.set = noop
   219          } else {
   220            def.get = userDef.get
   221              ? userDef.cache !== false
   222                ? makeComputedGetter(userDef.get, this)
   223                : bind(userDef.get, this)
   224              : noop
   225            def.set = userDef.set
   226              ? bind(userDef.set, this)
   227              : noop
   228          }
   229          Object.defineProperty(this, key, def)
   230        }
   231      }
   232    }
   233  
   234    function makeComputedGetter (getter, owner) {
   235      var watcher = new Watcher(owner, getter, null, {
   236        lazy: true
   237      })
   238      return function computedGetter () {
   239        if (watcher.dirty) {
   240          watcher.evaluate()
   241        }
   242        if (Dep.target) {
   243          watcher.depend()
   244        }
   245        return watcher.value
   246      }
   247    }
   248  
   249    /**
   250     * Setup instance methods. Methods must be bound to the
   251     * instance since they might be passed down as a prop to
   252     * child components.
   253     */
   254  
   255    Vue.prototype._initMethods = function () {
   256      var methods = this.$options.methods
   257      if (methods) {
   258        for (var key in methods) {
   259          this[key] = bind(methods[key], this)
   260        }
   261      }
   262    }
   263  
   264    /**
   265     * Initialize meta information like $index, $key & $value.
   266     */
   267  
   268    Vue.prototype._initMeta = function () {
   269      var metas = this.$options._meta
   270      if (metas) {
   271        for (var key in metas) {
   272          defineReactive(this, key, metas[key])
   273        }
   274      }
   275    }
   276  }