当前位置: 首页 > news >正文

getter方法的作用 vuex_vuex原来这么简单,带你了解vuex!

点击 上方蓝字 关注我们 c1010b956989bb32ff07068a800c0c0c.png

该文内容比较干,请耐心看。。。

5eb295f853937ee35ff444713ae6ed98.png

1.vuex的原理 每个组件在beforeCreate的生命周期中都混入(Vuex.mixin)同一个Store实例作为属性$store。
<template>  
    num1 {{$store.state.num1}}
template 我们看上面的代码,其实$store.state.num1源码是这样的
class Store {  get state() {    return this._vm.data.$$state  }}
vm.$store._vm._data.$$state.num1 //其实就是这个vm.$store._vm._data.$$state //这个部分是响应式的
如何实现响应式呢?其实很简单就是new Vue() 2.Vuex的源码解读---原理 我们可以看下源码。
function resetStoreVM (store, state, hot) {  // 省略若干代码  store._vm = new Vue({    data: {      $$state:state    },    computed  })  //省略代码}
这里的state就是我们定义的state,这里的computed就是处理后的getters,而class Store 上的函数都是围绕修改 vm.$store._vm.data.$$state和computed(getter) 服务的。 3.Vuex是如何安装的源码 我们要了解到Vuex对象其实就是Vue的一个插件,我们用Vue.use(Vuex)来使用它。 我们来看看Vue.use的源码:
function initUse(Vue) {  Vue.use = function (plugin) {    var installedPlugins = (this._installedPlugins||(this._installedPlugins = []))    // 如果已经存在,则直接返回this(Vue)    if (installedPlugins.indexOf(plugin)>-1) {      return this    }    // additional parameters    var args = toArray(arguments, 1)    // 把this 数组第一项    args.unshift(this)    if (typeof plugin.install === 'function') {      plugin.install.apply(plugin, args)    }else if (typeof plugin === 'function') {      plugin.apply(null, args)    }    // 添加到已安装的插件    installedPlugins.push(plugin)    return this  }}
我们来看一下plugin.install是个什么东东,也就是Vuex中install函数
export function install (_Vue) {  if (Vue && _Vue) {    return  }  Vue = _Vue  applyMixin (Vue)}
我们需要继续看一下,applyMixin这个函数做了什么,我们可以猜测一下,Vuex的原理就是让每个组件都具有同一个$store 。所以,applyMixin 应该负责初始化,将每个组件在beforeCreae的时候注入同一个store
export defalut function (Vue) {  const version = Number(Vue.version.split('.')[0])  if (version >= 2) {    Vue.mixin({beforeCreate: vuexInit})  }else {    // 1.x 的版本。忽略  }  //Vuex init hook ,inject into each instnce init hook list  function vuexInit () {    const options = this.$options    if (options.store) {      this.$store = typeof options.store === 'function'      ? options.store(): options.store    }else if (options.parent && options.parent.$store) {      this.$store = options.parent.$store    }  }}
下面我们可以验证一下,对不对!
const vm = new Vue({  el: '#app',  store,  render: h=>h(App)})console.log(vm.$store === vm.$children[0].$store) // trueconsole.log(vm.$vm === vm.$children[0].children[0].$store) //trueconsole.log(vm.$vm === vm.$children[0].children[1].$store) //true
答案呼之欲出了。 4.Vuex的构造函数源码解读
export class Store {  constructor(options = {}) {    // 暂时省略代码  }  if (!Vue && typeof window !== 'undefined' && window.Vue) {    install (window.Vue)  }}
这里可以从我们定义的new Vuex (options) 取出 plugins 和  strict 参数
const { plugins = [], strict = false} = options // 插件默认是空数组,// 严格模式默认是false
我们都知道Vuex的actions、mutations、getters等变量,这就要求在声明Store实例对象的是后需要声明一些内部变量来存放它们。
// store internal state// store 实例对象 内部的 statethis._committing = false// 用来存放处理后的用户自定义的actoinsthis._actions = Object.create(null)// 用来存放 actions 订阅this._actionSubscribers = []// 用来存放处理后的用户自定义的mutationsthis._mutations = Object.create(null)// 用来存放处理后的用户自定义的 gettersthis._wrappedGetters = Object.create(null)// 模块收集器,构造模块树形结构this._modules = new ModuleCollection(options)// 用于存储模块命名空间的关系this._modulesNamespaceMap = Object.create(null)// 订阅this._subscribers = []// 用于使用 $watch 观测 gettersthis._watcherVM = new Vue()// 用来存放生成的本地 getters 的缓存this._makeLocalGettersCache = Object.create(null)
这里使用 Object.create(null) 的原因是因为它没有原型链,也就是Object.create(null).__proto__ 是undefined。 在构造函数中,我们来看两个方法commit 和 dispach ,我们需要保证两个函数里面的this 是store实例。
// bind commit and dispatch to selfconst store = thisconst { dispatch, commit } = thisthis.dispatch = function boundDispatch (type, payload) {  return dispatch.call(store, type, payload)}this.commit = function boundCommit (type, payload, options) {  return commit.call(store, type, payload, options)}
还有两个比较重要的初始化,一个是模块初始化,一个是初始化store._vm响应式并且注册_wrappedGetters 作为 computed的属性
// 严格模式,默认是falsethis.strict = strict// 根模块的stateconst state = this._modules.root.state// init root module.// this also recursively registers all sub-modules// and collects all module getters inside this._wrappedGettersinstallModule(this, state, [], this._modules.root)// initialize the store vm, which is responsible for the reactivity// (also registers _wrappedGetters as computed properties)resetStoreVM(this, state)
installModule (this, state, [], this._modules.root) 初始化根模块,并且递归注册所有的子模块,并且收集所有模块的getters放在this._wrappedGetters里 installModule 函数
function installModule (store, rootState, path, module, hot) {  // 是根模块  const isRoot = !path.length  // 命名空间 字符串  const namespace = store._modules.getNamespace(path)  if (module.namespaced) {    // 省略代码:模块命名空间map对象中已经有了,开发环境报错提示重复    // module 赋值给 _modulesNamespaceMap[namespace]    store._modulesNamespaceMap[namespace] = module  }  // ... 后续代码 移出来 待读解释}
注册state
// set state// 不是根模块且不是热重载if (!isRoot && !hot) {  // 获取父级的state  const parentState = getNestedState(rootState, path.slice(0, -1))  // 模块名称  // 比如 cart  const moduleName = path[path.length - 1]  // state 注册  store._withCommit(() => {    // 省略代码:非生产环境 报错 模块 state 重复设置    Vue.set(parentState, moduleName, module.state)  })}
最后得到响应式的数据,实例Store.state 比如
{  // 省略若干属性和方法  // 这里的 state 是只读属性   state: {    cart: {      checkoutStatus: null,      items: []    } }}const local = module.context = makeLocalContext(store, namespace, path)
module.context 这个赋值主要是给 helpers 中 mapState、mapGetters、mapMutations、mapActions四个辅助函数使用的。
生成本地的dispatch、commit、getters和state。
主要作用就是抹平差异化,不需要用户再传模块参数 。

遍历注册 mutation

module.forEachMutation((mutation, key) => {  const namespacedType = namespace + key  registerMutation(store, namespacedType, mutation, local)})/** * 注册 mutation * @param {Object} store 对象 * @param {String} type 类型 * @param {Function} handler 用户自定义的函数 * @param {Object} local local 对象 */function registerMutation (store, type, handler, local) {  // 收集的所有的mutations找对应的mutation函数,没有就赋值空数组  const entry = store._mutations[type] || (store._mutations[type] = [])  // 最后 mutation  entry.push(function wrappedMutationHandler (payload) {    /**     * mutations: {     *    pushProductToCart (state, { id }) {     *        console.log(state);     *    }     * }     * 也就是为什么用户定义的 mutation 第一个参数是state的原因,第二个参数是payload参数     */    handler.call(store, local.state, payload)  })}

遍历注册 action

module.forEachAction((action, key) => {  const type = action.root ? key : namespace + key  const handler = action.handler || action  registerAction(store, type, handler, local)})/*** 注册 mutation* @param {Object} store 对象* @param {String} type 类型* @param {Function} handler 用户自定义的函数* @param {Object} local local 对象*/function registerAction (store, type, handler, local) {  const entry = store._actions[type] || (store._actions[type] = [])  // payload 是actions函数的第二个参数  entry.push(function wrappedActionHandler (payload) {    /**     * 也就是为什么用户定义的actions中的函数第一个参数有     *  { dispatch, commit, getters, state, rootGetters, rootState } 的原因     * actions: {     *    checkout ({ commit, state }, products) {     *        console.log(commit, state);     *    }     * }     */    let res = handler.call(store, {      dispatch: local.dispatch,      commit: local.commit,      getters: local.getters,      state: local.state,      rootGetters: store.getters,      rootState: store.state    }, payload)    /**     * export function isPromise (val) {        return val && typeof val.then === 'function'      }     * 判断如果不是Promise Promise 化,也就是为啥 actions 中处理异步函数        也就是为什么构造函数中断言不支持promise报错的原因        vuex需要Promise polyfill        assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)     */    if (!isPromise(res)) {      res = Promise.resolve(res)    }    // devtool 工具触发 vuex:error    if (store._devtoolHook) {      // catch 捕获错误      return res.catch(err => {        store._devtoolHook.emit('vuex:error', err)        // 抛出错误        throw err      })    } else {      // 然后函数执行结果      return res    }  })}

遍历注册 getter

module.forEachGetter((getter, key) => {  const namespacedType = namespace + key  registerGetter(store, namespacedType, getter, local)})/** * 注册 getter * @param {Object} store  Store实例 * @param {String} type 类型 * @param {Object} rawGetter  原始未加工的 getter 也就是用户定义的 getter 函数 * @examples  比如 cartProducts: (state, getters, rootState, rootGetters) => {} * @param {Object} local 本地 local 对象 */function registerGetter (store, type, rawGetter, local) {  // 类型如果已经存在,报错:已经存在  if (store._wrappedGetters[type]) {    if (process.env.NODE_ENV !== 'production') {      console.error(`[vuex] duplicate getter key: ${type}`)    }    return  }  // 否则:赋值  store._wrappedGetters[type] = function wrappedGetter (store) {    /**     * 这也就是为啥 getters 中能获取到  (state, getters, rootState, rootGetters)  这些值的原因     * getters = {     *      cartProducts: (state, getters, rootState, rootGetters) => {     *        console.log(state, getters, rootState, rootGetters);     *      }     * }     */    return rawGetter(      local.state, // local state      local.getters, // local getters      store.state, // root state      store.getters // root getters    )  }}

resetStoreVM 函数

function resetStoreVM (store, state, hot) {  // 存储一份老的Vue实例对象 _vm  const oldVm = store._vm  // bind store public getters  // 绑定 store.getter  store.getters = {}  // reset local getters cache  // 重置 本地getters的缓存  store._makeLocalGettersCache = Object.create(null)  // 注册时收集的处理后的用户自定义的 wrappedGetters  const wrappedGetters = store._wrappedGetters  // 声明 计算属性 computed 对象  const computed = {}  // 遍历 wrappedGetters 赋值到 computed 上  forEachValue(wrappedGetters, (fn, key) => {    // use computed to leverage its lazy-caching mechanism    // direct inline function use will lead to closure preserving oldVm.    // using partial to return function with only arguments preserved in closure environment.    /**     * partial 函数     * 执行函数 返回一个新函数        export function partial (fn, arg) {          return function () {            return fn(arg)          }        }     */    computed[key] = partial(fn, store)    // getter 赋值 keys    Object.defineProperty(store.getters, key, {      get: () => store._vm[key],      // 可以枚举      enumerable: true // for local getters    })  })  // use a Vue instance to store the state tree  // suppress warnings just in case the user has added  // some funky global mixins  // 使用一个 Vue 实例对象存储 state 树  // 阻止警告 用户添加的一些全局mixins  // 声明变量 silent 存储用户设置的静默模式配置  const silent = Vue.config.silent  // 静默模式开启  Vue.config.silent = true  store._vm = new Vue({    data: {      $$state: state    },    computed  })  // 把存储的静默模式配置赋值回来  Vue.config.silent = silent  // enable strict mode for new vm  // 开启严格模式 执行这句  // 用 $watch 观测 state,只能使用 mutation 修改 也就是 _withCommit 函数  if (store.strict) {    enableStrictMode(store)  }  // 如果存在老的 _vm 实例  if (oldVm) {    // 热加载为 true    if (hot) {      // dispatch changes in all subscribed watchers      // to force getter re-evaluation for hot reloading.      // 设置  oldVm._data.$$state = null      store._withCommit(() => {        oldVm._data.$$state = null      })    }    // 实例销毁    Vue.nextTick(() => oldVm.$destroy())  }}

好了上面就是我们剖析的构造函数部分了。我们来看一些Vuex.store的一些api实现。

Vuex.Store的实例方法

commit

提交 mutation

commit (_type, _payload, _options) {  // check object-style commit  // 统一成对象风格  const {    type,    payload,    options  } = unifyObjectStyle(_type, _payload, _options)  const mutation = { type, payload }  // 取出处理后的用户定义 mutation  const entry = this._mutations[type]  // 省略 非生产环境的警告代码 ...  this._withCommit(() => {    // 遍历执行    entry.forEach(function commitIterator (handler) {      handler(payload)    })  })  // 订阅 mutation 执行  this._subscribers.forEach(sub => sub(mutation, this.state))  // 省略 非生产环境的警告代码 ...}

commit 支持多种方式,比如:

store.commit('increment', {  count: 10})// 对象提交方式store.commit({  type: 'increment',  count: 10})

unifyObjectStyle函数将参数统一,返回 { type, payload, options }。

dispatch

分发 action

dispatch (_type, _payload) {  // check object-style dispatch  // 获取到type和payload参数  const {    type,    payload  } = unifyObjectStyle(_type, _payload)  // 声明 action 变量 等于 type和payload参数  const action = { type, payload }  // 入口,也就是 _actions 集合  const entry = this._actions[type]  // 省略 非生产环境的警告代码 ...  try {    this._actionSubscribers      .filter(sub => sub.before)      .forEach(sub => sub.before(action, this.state))  } catch (e) {    if (process.env.NODE_ENV !== 'production') {      console.warn(`[vuex] error in before action subscribers: `)      console.error(e)    }  }  const result = entry.length > 1    ? Promise.all(entry.map(handler => handler(payload)))    : entry[0](payload)  return result.then(res => {    try {      this._actionSubscribers        .filter(sub => sub.after)        .forEach(sub => sub.after(action, this.state))    } catch (e) {      if (process.env.NODE_ENV !== 'production') {        console.warn(`[vuex] error in after action subscribers: `)        console.error(e)      }    }    return res  })}

replaceState

替换store的根状态,仅用状态合并或者时光旅行调试。

replaceState (state) {  this._withCommit(() => {    this._vm._data.$$state = state  })}

watch

响应式地侦听 fn 的返回值,当值改变时调用回调函数。

/** * 观测某个值 * @param {Function} getter 函数 * @param {Function} cb 回调 * @param {Object} options 参数对象 */watch (getter, cb, options) {  if (process.env.NODE_ENV !== 'production') {    assert(typeof getter === 'function', `store.watch only accepts a function.`)  }  return this._watcherVM.$watch(() => getter(this.state, this.getters), cb, options)}

subscribe

订阅 store 的 mutation

subscribe (fn) {  return genericSubscribe(fn, this._subscribers)}// 收集订阅者function genericSubscribe (fn, subs) {  if (subs.indexOf(fn) < 0) {    subs.push(fn)  }  return () => {    const i = subs.indexOf(fn)    if (i > -1) {      subs.splice(i, 1)    }  }}

subscribeAction

订阅 store 的 action

subscribeAction (fn) {  const subs = typeof fn === 'function' ? { before: fn } : fn  return genericSubscribe(subs, this._actionSubscribers)}

registerModule

注册一个动态模块

/** * 动态注册模块 * @param {Array|String} path 路径 * @param {Object} rawModule 原始未加工的模块 * @param {Object} options 参数选项 */registerModule (path, rawModule, options = {}) {  // 如果 path 是字符串,转成数组  if (typeof path === 'string') path = [path]  // 省略 非生产环境 报错代码  // 手动调用 模块注册的方法  this._modules.register(path, rawModule)  // 安装模块  installModule(this, this.state, path, this._modules.get(path), options.preserveState)  // reset store to update getters...  // 设置 resetStoreVM  resetS

unregisterModule

卸载一个动态模块

/** * 注销模块 * @param {Array|String} path 路径 */unregisterModule (path) {  // 如果 path 是字符串,转成数组  if (typeof path === 'string') path = [path]  // 省略 非生产环境 报错代码 ...  // 手动调用模块注销  this._modules.unregister(path)  this._withCommit(() => {    // 注销这个模块    const parentState = getNestedState(this.state, path.slice(0, -1))    Vue.delete(parentState, path[path.length - 1])  })  // 重置 Store  resetStore(this)}

hotUpdate

热替换新的 action 和 mutation

// 热加载hotUpdate (newOptions) {  // 调用的是 ModuleCollection 的 update 方法,最终调用对应的是每个 Module 的 update  this._modules.update(newOptions)  // 重置 Store  resetStore(this, true)}

组件绑定的辅助函数

mapState 

为组件创建计算属性以返回Vuex store中的状态。

export const mapState = normalizeNamespace((namespace, states) => {  const res = {}  // 非生产环境 判断参数 states  必须是数组或者是对象  if (process.env.NODE_ENV !== 'production' && !isValidMap(states)) {    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object')  }  normalizeMap(states).forEach(({ key, val }) => {    res[key] = function mappedState () {      let state = this.$store.state      let getters = this.$store.getters      // 传了参数 namespace      if (namespace) {        // 用 namespace 从 store 中找一个模块。        const module = getModuleByNamespace(this.$store, 'mapState', namespace)        if (!module) {          return        }        state = module.context.state        getters = module.context.getters      }      return typeof val === 'function'        ? val.call(this, state, getters)        : state[val]    }    // 标记为 vuex 方便在 devtools 显示    // mark vuex getter for devtools    res[key].vuex = true  })  return res})

normalizeNamespace 标准化统一命名空间

function normalizeNamespace (fn) {  return (namespace, map) => {    // 命名空间没传,交换参数,namespace 为空字符串    if (typeof namespace !== 'string') {      map = namespace      namespace = ''    } else if (namespace.charAt(namespace.length - 1) !== '/') {      // 如果是字符串,最后一个字符不是 / 添加 /      // 因为 _modulesNamespaceMap 存储的是这样的结构。      /**       * _modulesNamespaceMap:          cart/: {}          products/: {}        }       * */      namespace += '/'    }    return fn(namespace, map)  }}// 校验是否是map 是数组或者是对象。function isValidMap (map) {  return Array.isArray(map) || isObject(map)}/** * Normalize the map * 标准化统一 map,最终返回的是数组 * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ] * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ] * @param {Array|Object} map * @return {Object} */function normalizeMap (map) {  if (!isValidMap(map)) {    return []  }  return Array.isArray(map)    ? map.map(key => ({ key, val: key }))    : Object.keys(map).map(key => ({ key, val: map[key] }))}

module.context 这个赋值主要是给 helpers 中 mapState、mapGetters、mapMutations、mapActions四个辅助函数使用的。

getModuleByNamespace

function getModuleByNamespace (store, helper, namespace) {  // _modulesNamespaceMap 这个变量在 class Store installModule 函数中赋值的  const module = store._modulesNamespaceMap[namespace]  if (process.env.NODE_ENV !== 'production' && !module) {    console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)  }  return module}

mapGetters

为组件创建计算属性以返回 getter 的返回值

export const mapGetters = normalizeNamespace((namespace, getters) => {  const res = {}  // 省略代码:非生产环境 判断参数 getters 必须是数组或者是对象  normalizeMap(getters).forEach(({ key, val }) => {    // The namespace has been mutated by normalizeNamespace    val = namespace + val    res[key] = function mappedGetter () {      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {        return      }      // 省略代码:匹配不到 getter      return this.$store.getters[val]    }    // mark vuex getter for devtools    res[key].vuex = true  })  return res})

mapActions

创建组件方法分发 action

export const mapActions = normalizeNamespace((namespace, actions) => {  const res = {}  // 省略代码: 非生产环境 判断参数 actions  必须是数组或者是对象  normalizeMap(actions).forEach(({ key, val }) => {    res[key] = function mappedAction (...args) {      // get dispatch function from store      let dispatch = this.$store.dispatch      if (namespace) {        const module = getModuleByNamespace(this.$store, 'mapActions', namespace)        if (!module) {          return        }        dispatch = module.context.dispatch      }      return typeof val === 'function'        ? val.apply(this, [dispatch].concat(args))        : dispatch.apply(this.$store, [val].concat(args))    }  })  return res})

mapMutations

创建组件方法提交 mutation。 mapMutations 和 mapActions 类似,只是 dispatch 换成了 commit

let commit = this.$store.commitcommit = module.context.commitreturn typeof val === 'function'        ? val.apply(this, [commit].concat(args))        : commit.apply(this.$store, [val].concat(args))

createNamespacedHelpers

创建基于命名空间的组件绑定辅助函数

export const createNamespacedHelpers = (namespace) => ({  // bind(null) 严格模式下,napState等的函数 this 指向就是 null  mapState: mapState.bind(null, namespace),  mapGetters: mapGetters.bind(null, namespace),  mapMutations: mapMutations.bind(null, namespace),  mapActions: mapActions.bind(null, namespace)})

以上就是我对vuex的简单分析,如果有需要可以贴一份分析过的代码。

   扫描关注

老陈说前端

想象不到的干货

194fdee413d2b9252a5e98afa71d92b2.png   

相关文章:

  • python property方法,在python类中列出@property装饰的方法
  • springsecurity实现原理_不用 Spring Security 可否?试试这个小而美的安全框架
  • python异步_异步-同步-在一个python事件循环中异步调用
  • springboot打包成war_经常出现的13道SpringBoot相关的面试问题(含答案)
  • springsecurity不拦截某个接口_Spring Security (一):Simple Demo
  • enityframework 已连接的当前状态为打开。_Http 持久连接与 HttpClient 连接池,有哪些不为人知的关系?...
  • 脚本录制软件python 按键精灵 tc_从10种脚相看你的财运
  • 用eviews计算产出弹性_深圳竞价优化|投放都和产出差不多了,还有人在投竞价...
  • qq登录界面句柄_天天玩QQ!知道登录界面那两个人是谁吗?网友:不是情侣?...
  • led数字字体_led显示屏知识大全
  • python设置单元格宽度_ms-word – Python-docx,如何在表中设置单元格宽度?
  • c++判断整数翻转溢出_CBC字节翻转攻击解析
  • python调用数据库存储过程_Mysql学习---使用Python执行存储过程
  • python实现中值滤波_Python 实现中值滤波、均值滤波
  • bigdecimal不保留小数_深入理解 BigDecimal
  • [译] 怎样写一个基础的编译器
  • 【Linux系统编程】快速查找errno错误码信息
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • css布局,左右固定中间自适应实现
  • JS变量作用域
  • storm drpc实例
  • Swift 中的尾递归和蹦床
  • vue学习系列(二)vue-cli
  • 产品三维模型在线预览
  • 初识MongoDB分片
  • 创建一种深思熟虑的文化
  • 从PHP迁移至Golang - 基础篇
  • 基于组件的设计工作流与界面抽象
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 通过npm或yarn自动生成vue组件
  • 王永庆:技术创新改变教育未来
  • 用Canvas画一棵二叉树
  • 最简单的无缝轮播
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • ​520就是要宠粉,你的心头书我买单
  • #HarmonyOS:基础语法
  • #微信小程序:微信小程序常见的配置传旨
  • (27)4.8 习题课
  • (C语言)逆序输出字符串
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (第61天)多租户架构(CDB/PDB)
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .net wcf memory gates checking failed
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .pyc文件是什么?