国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

VueJS源碼學習——實例構造函數

jhhfft / 2637人閱讀

摘要:大概過了一遍工具類后,開始看實例的具體實現原文地址項目地址實現了的初始化函數方法會在實例創建的時候被調用初始化了實例的共有屬性如還有一堆私有屬性如等等最后再是初始化實例狀態事件生命周期等等在實現上比較有趣使用來實現對的和方法利用獲取

大概過了一遍 util 工具類后,開始看 Vue 實例的具體實現

原文地址
項目地址

init

src/instance/init.js 實現了 Vue 的 _init 初始化函數

import { mergeOptions } from "../../util/index"

let uid = 0

export default function (Vue) {

  Vue.prototype._init = function (options) {
    ...
  }
}

_init 方法會在實例創建的時候被調用:

function Vue(options) {
    this._init(options);
}

init 初始化了 Vue 實例的共有屬性如 $el, $parent, $root, $children, $refs, $els還有一堆私有屬性如_watchers, _directives, _uid, isVue, _events等等,最后再是初始化實例狀態、事件、生命周期等等

在實現 $root 上比較有趣:

this.$parent = options.parent
this.$root = this.$parent
  ? this.$parent.$root
  : this
state

src/instance/state.js

  /**
   * Accessor for `$data` property, since setting $data
   * requires observing the new object and updating
   * proxied properties.
   */

  Object.defineProperty(Vue.prototype, "$data", {
    get () {
      return this._data
    },
    set (newData) {
      if (newData !== this._data) {
        this._setData(newData)
      }
    }
  })
_setData

使用 defineProperty 來實現對 Vue.$data 的 get 和 set

  Vue.prototype._setData = function (newData) {
    newData = newData || {}
    var oldData = this._data
    this._data = newData
    var keys, key, i
    // unproxy keys not present in new data
    keys = Object.keys(oldData)
    i = keys.length
    while (i--) {
      key = keys[i]
      if (!(key in newData)) {
        this._unproxy(key)
      }
    }
    // proxy keys not already proxied,
    // and trigger change for changed values
    keys = Object.keys(newData)
    i = keys.length
    while (i--) {
      key = keys[i]
      if (!hasOwn(this, key)) {
        // new property
        this._proxy(key)
      }
    }
    oldData.__ob__.removeVm(this)
    observe(newData, this)
    this._digest()
  }

_setData 方法利用 Object.keys 獲取對象的屬性列表,在利用 key in obj來判斷是否存在屬性 key,然后決定是否 proxy 或者 unproxy

_initComputed
  /**
   * Setup computed properties. They are essentially
   * special getter/setters
   */

  function noop () {}
  Vue.prototype._initComputed = function () {
    var computed = this.$options.computed
    if (computed) {
      for (var key in computed) {
        var userDef = computed[key]
        var def = {
          enumerable: true,
          configurable: true
        }
        if (typeof userDef === "function") {
          def.get = makeComputedGetter(userDef, this)
          def.set = noop
        } else {
          def.get = userDef.get
            ? userDef.cache !== false
              ? makeComputedGetter(userDef.get, this)
              : bind(userDef.get, this)
            : noop
          def.set = userDef.set
            ? bind(userDef.set, this)
            : noop
        }
        Object.defineProperty(this, key, def)
      }
    }
  }

  function makeComputedGetter (getter, owner) {
    var watcher = new Watcher(owner, getter, null, {
      lazy: true
    })
    return function computedGetter () {
      if (watcher.dirty) {
        watcher.evaluate()
      }
      if (Dep.target) {
        watcher.depend()
      }
      return watcher.value
    }
  }

初始化計算屬性,即 computed 的實現,從文檔可以看到我們既可以使用 function 來確定怎么獲取某個值,也可以使用 get 和 set 對象來確定值的獲取和更新,底層的實現是 watcher

methods
  /**
   * Setup instance methods. Methods must be bound to the
   * instance since they might be passed down as a prop to
   * child components.
   */

  Vue.prototype._initMethods = function () {
    var methods = this.$options.methods
    if (methods) {
      for (var key in methods) {
        this[key] = bind(methods[key], this)
      }
    }
  }

  /**
   * Initialize meta information like $index, $key & $value.
   */

  Vue.prototype._initMeta = function () {
    var metas = this.$options._meta
    if (metas) {
      for (var key in metas) {
        defineReactive(this, key, metas[key])
      }
    }
  }
watcher
import { extend, warn, isArray, isObject, nextTick } from "./util/index"
import config from "./config"
import Dep from "./observer/dep"
import { parseExpression } from "./parsers/expression"
import { pushWatcher } from "./batcher"

let uid = 0

export default function Watcher (vm, expOrFn, cb, options) {
  // mix in options
  if (options) {
    extend(this, options)
  }
  var isFn = typeof expOrFn === "function"
  this.vm = vm
  vm._watchers.push(this)
  this.expression = isFn ? expOrFn.toString() : expOrFn
  this.cb = cb
  this.id = ++uid // uid for batching
  this.active = true
  this.dirty = this.lazy // for lazy watchers
  this.deps = Object.create(null)
  this.newDeps = null
  this.prevError = null // for async error stacks
  // parse expression for getter/setter
  if (isFn) {
    this.getter = expOrFn
    this.setter = undefined
  } else {
    var res = parseExpression(expOrFn, this.twoWay)
    this.getter = res.get
    this.setter = res.set
  }
  this.value = this.lazy
    ? undefined
    : this.get()
  // state for avoiding false triggers for deep and Array
  // watchers during vm._digest()
  this.queued = this.shallow = false
}

/**
 * Add a dependency to this directive.
 *
 * @param {Dep} dep
 */

Watcher.prototype.addDep = function (dep) {
  var id = dep.id
  if (!this.newDeps[id]) {
    this.newDeps[id] = dep
    if (!this.deps[id]) {
      this.deps[id] = dep
      dep.addSub(this)
    }
  }
}

/**
 * Evaluate the getter, and re-collect dependencies.
 */

Watcher.prototype.get = function () {
  this.beforeGet()
  var scope = this.scope || this.vm
  var value
  try {
    value = this.getter.call(scope, scope)
  } catch (e) {
    if (
      process.env.NODE_ENV !== "production" &&
      config.warnExpressionErrors
    ) {
      warn(
        "Error when evaluating expression "" +
        this.expression + "". " +
        (config.debug
          ? ""
          : "Turn on debug mode to see stack trace."
        ), e
      )
    }
  }
  // "touch" every property so they are all tracked as
  // dependencies for deep watching
  if (this.deep) {
    traverse(value)
  }
  if (this.preProcess) {
    value = this.preProcess(value)
  }
  if (this.filters) {
    value = scope._applyFilters(value, null, this.filters, false)
  }
  if (this.postProcess) {
    value = this.postProcess(value)
  }
  this.afterGet()
  return value
}

/**
 * Set the corresponding value with the setter.
 *
 * @param {*} value
 */

Watcher.prototype.set = function (value) {
  var scope = this.scope || this.vm
  if (this.filters) {
    value = scope._applyFilters(
      value, this.value, this.filters, true)
  }
  try {
    this.setter.call(scope, scope, value)
  } catch (e) {
    if (
      process.env.NODE_ENV !== "production" &&
      config.warnExpressionErrors
    ) {
      warn(
        "Error when evaluating setter "" +
        this.expression + """, e
      )
    }
  }
  // two-way sync for v-for alias
  var forContext = scope.$forContext
  if (forContext && forContext.alias === this.expression) {
    if (forContext.filters) {
      process.env.NODE_ENV !== "production" && warn(
        "It seems you are using two-way binding on " +
        "a v-for alias (" + this.expression + "), and the " +
        "v-for has filters. This will not work properly. " +
        "Either remove the filters or use an array of " +
        "objects and bind to object properties instead."
      )
      return
    }
    forContext._withLock(function () {
      if (scope.$key) { // original is an object
        forContext.rawValue[scope.$key] = value
      } else {
        forContext.rawValue.$set(scope.$index, value)
      }
    })
  }
}

/**
 * Prepare for dependency collection.
 */

Watcher.prototype.beforeGet = function () {
  Dep.target = this
  this.newDeps = Object.create(null)
}

/**
 * Clean up for dependency collection.
 */

Watcher.prototype.afterGet = function () {
  Dep.target = null
  var ids = Object.keys(this.deps)
  var i = ids.length
  while (i--) {
    var id = ids[i]
    if (!this.newDeps[id]) {
      this.deps[id].removeSub(this)
    }
  }
  this.deps = this.newDeps
}

/**
 * Subscriber interface.
 * Will be called when a dependency changes.
 *
 * @param {Boolean} shallow
 */

Watcher.prototype.update = function (shallow) {
  if (this.lazy) {
    this.dirty = true
  } else if (this.sync || !config.async) {
    this.run()
  } else {
    // if queued, only overwrite shallow with non-shallow,
    // but not the other way around.
    this.shallow = this.queued
      ? shallow
        ? this.shallow
        : false
      : !!shallow
    this.queued = true
    // record before-push error stack in debug mode
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== "production" && config.debug) {
      this.prevError = new Error("[vue] async stack trace")
    }
    pushWatcher(this)
  }
}

/**
 * Batcher job interface.
 * Will be called by the batcher.
 */

Watcher.prototype.run = function () {
  if (this.active) {
    var value = this.get()
    if (
      value !== this.value ||
      // Deep watchers and Array watchers should fire even
      // when the value is the same, because the value may
      // have mutated; but only do so if this is a
      // non-shallow update (caused by a vm digest).
      ((isArray(value) || this.deep) && !this.shallow)
    ) {
      // set new value
      var oldValue = this.value
      this.value = value
      // in debug + async mode, when a watcher callbacks
      // throws, we also throw the saved before-push error
      // so the full cross-tick stack trace is available.
      var prevError = this.prevError
      /* istanbul ignore if */
      if (process.env.NODE_ENV !== "production" &&
          config.debug && prevError) {
        this.prevError = null
        try {
          this.cb.call(this.vm, value, oldValue)
        } catch (e) {
          nextTick(function () {
            throw prevError
          }, 0)
          throw e
        }
      } else {
        this.cb.call(this.vm, value, oldValue)
      }
    }
    this.queued = this.shallow = false
  }
}

/**
 * Evaluate the value of the watcher.
 * This only gets called for lazy watchers.
 */

Watcher.prototype.evaluate = function () {
  // avoid overwriting another watcher that is being
  // collected.
  var current = Dep.target
  this.value = this.get()
  this.dirty = false
  Dep.target = current
}

/**
 * Depend on all deps collected by this watcher.
 */

Watcher.prototype.depend = function () {
  var depIds = Object.keys(this.deps)
  var i = depIds.length
  while (i--) {
    this.deps[depIds[i]].depend()
  }
}

/**
 * Remove self from all dependencies" subcriber list.
 */

Watcher.prototype.teardown = function () {
  if (this.active) {
    // remove self from vm"s watcher list
    // we can skip this if the vm if being destroyed
    // which can improve teardown performance.
    if (!this.vm._isBeingDestroyed) {
      this.vm._watchers.$remove(this)
    }
    var depIds = Object.keys(this.deps)
    var i = depIds.length
    while (i--) {
      this.deps[depIds[i]].removeSub(this)
    }
    this.active = false
    this.vm = this.cb = this.value = null
  }
}

/**
 * Recrusively traverse an object to evoke all converted
 * getters, so that every nested property inside the object
 * is collected as a "deep" dependency.
 *
 * @param {*} val
 */

function traverse (val) {
  var i, keys
  if (isArray(val)) {
    i = val.length
    while (i--) traverse(val[i])
  } else if (isObject(val)) {
    keys = Object.keys(val)
    i = keys.length
    while (i--) traverse(val[keys[i]])
  }
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/85145.html

相關文章

  • VueJS源碼學習——項目結構&目錄

    摘要:所以整個的核心,就是如何實現這三樣東西以上摘自囧克斯博客的一篇文章從版本開始這個時候的項目結構如下源碼在里面,為打包編譯的代碼,為打包后代碼放置的位置,為測試代碼目錄。節點類型摘自資源另一位作者關于源碼解析 本項目的源碼學習筆記是基于 Vue 1.0.9 版本的也就是最早的 tag 版本,之所以選擇這個版本,是因為這個是最原始沒有太多功能拓展的版本,有利于更好的看到 Vue 最開始的骨...

    ad6623 評論0 收藏0
  • JS每日一題: 請簡述一下vuex實現原理

    摘要:給的實例注入一個的屬性,這也就是為什么我們在的組件中可以通過訪問到的各種數據和狀態源碼位置,是怎么實現的源碼位置是對的的初始化,它接受個參數,為當前實例,為的,為執行的回調函數,為當前模塊的路徑。 20190221 請簡述一下vuex實現原理 對vuex基礎概念有不懂的可以點這里 vuex實現原理我們簡單過一遍源碼 地址 https://github.com/vuejs/vuex 首...

    JohnLui 評論0 收藏0
  • 如何實現全屏遮罩(附Vue.extend和el-message源碼學習

    摘要:如何優雅的動態添加這里我們需要用到的實例化,首先我們來看的思路,貼一段源碼使用基礎構造器,創建一個子類。因為作為一個的擴展構造器,所以基礎的功能還是需要保持一致,跟構造器一樣在構造函數中初始化。 [Vue]如何實現全屏遮罩(附Vue.extend和el-message源碼學習) 在做個人項目的時候需要做一個類似于電子相冊瀏覽的控件,實現過程中首先要實現全局遮罩,結合自己的思路并閱讀了(...

    malakashi 評論0 收藏0
  • 如何實現全屏遮罩(附Vue.extend和el-message源碼學習

    摘要:如何優雅的動態添加這里我們需要用到的實例化,首先我們來看的思路,貼一段源碼使用基礎構造器,創建一個子類。因為作為一個的擴展構造器,所以基礎的功能還是需要保持一致,跟構造器一樣在構造函數中初始化。 [Vue]如何實現全屏遮罩(附Vue.extend和el-message源碼學習) 在做個人項目的時候需要做一個類似于電子相冊瀏覽的控件,實現過程中首先要實現全局遮罩,結合自己的思路并閱讀了(...

    Zack 評論0 收藏0

發表評論

0條評論

jhhfft

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<