목차
util.js
index.jsindex.esm.js
mixin.js
웹 프론트엔드 JS 튜토리얼 VueX의 소스 코드 내용에 대한 간략한 분석

VueX의 소스 코드 내용에 대한 간략한 분석

Jul 20, 2018 pm 03:30 PM

Vuex는 Vue.js 애플리케이션용으로 특별히 개발된 상태 관리 패턴입니다. 많은 구성 요소와 복잡한 상호 작용이 포함된 단일 페이지 애플리케이션의 경우 Vuex는 구성 요소 간의 데이터 공유 및 수정을 용이하게 하는 편리하고 정확하며 예측 가능한 상태 관리 방법을 제공합니다.

파일 구조는 다음과 같습니다

  • /module/module

  • /plugins

  • helpers.js

  • index.esm.js

  • index.js

  • store.js

  • util.js

util.js

先从最简单的工具函数开始。

find函数

/**
 * Get the first item that pass the test
 * by second argument function
 *
 * @param {Array} list
 * @param {Function} f
 * @return {*}
 */
export function find (list, f) {
  return list.filter(f)[0]
}
로그인 후 복사

find函数的测试用例

it('find', () => {
  const list = [33, 22, 112, 222, 43]
  expect(find(list, function (a) { return a % 2 === 0 })).toEqual(22)
})
로그인 후 복사

解析:

  • 先用断言函数f过滤列表list,最后取过滤后列表的第一个元素。

deepCopy函数

/**
 * Deep copy the given object considering circular structure.
 * This function caches all nested objects and its copies.
 * If it detects circular structure, use cached copy to avoid infinite loop.
 *
 * @param {*} obj
 * @param {Array<Object>} cache
 * @return {*}
 */
export function deepCopy (obj, cache = []) {
  // just return if obj is immutable value
  if (obj === null || typeof obj !== &#39;object&#39;) {
    return obj
  }

  // if obj is hit, it is in circular structure
  const hit = find(cache, c => c.original === obj)
  if (hit) {
    return hit.copy
  }

  const copy = Array.isArray(obj) ? [] : {}
  // put the copy into cache at first
  // because we want to refer it in recursive deepCopy
  cache.push({
    original: obj,
    copy
  })

  Object.keys(obj).forEach(key => {
    copy[key] = deepCopy(obj[key], cache)
  })

  return copy
}
로그인 후 복사

deepCopy的测试用例

  // 普通结构
  it(&#39;deepCopy: nornal structure&#39;, () => {
    const original = {
      a: 1,
      b: &#39;string&#39;,
      c: true,
      d: null,
      e: undefined
    }
    const copy = deepCopy(original)

    expect(copy).toEqual(original)
  })
  
  // 嵌套结构
  it(&#39;deepCopy: nested structure&#39;, () => {
    const original = {
      a: {
        b: 1,
        c: [2, 3, {
          d: 4
        }]
      }
    }
    const copy = deepCopy(original)

    expect(copy).toEqual(original)
  })
  
  // 循环引用结构
  it(&#39;deepCopy: circular structure&#39;, () => {
    const original = {
      a: 1
    }
    original.circular = original

    const copy = deepCopy(original)

    expect(copy).toEqual(original)
  })
로그인 후 복사

解析:

  • 功能:支持循环引用的深克隆函数

  • 第一个if判断obj === null || typeof obj !== &#39;object&#39;判断如果不是引用类型直接返回(基本类型是值拷贝),也是递归的一个出口。

  • 第二个判断hit是判断是不是循环引用,由于是循环引用,在cache中应该有缓存到一份拷贝,直接取cache的,避免再次重复拷贝一份。

  • 什么是循环引用看测试用例第三个original.circular = original,循环引用和被引用的内容是一样的,用缓存就是避免重复的克隆(内容一样)

  • original.circular是循环引用,original是被循环引用

  • 先把cope放到cache中,是在递归的时候,如果遇到循环引用,要确保cache中有一份被循环引用的copy,但是copy必须是引用类型。

  • 为什么cope必须是引用类型?循环引用保存的是引用不是内容(这时候还没拷贝完),在递归的时候并未完成拷贝,只有递归跑完了才完成拷贝,这样未来被循环引用的内容改变时(拷贝完),循环引用的内容同步改变

  • 所以const copy = Array.isArray(obj) ? [] : {}必须是引用类型。

  • 最后Object.keys可以遍历对象和数组的所有键名(只返回实例的属性,不包含原型链和Symbol),实现递归克隆。

  • 一共两个出口,一个是基本类型,另一个是循环引用。

forEachValue

/**
 * forEach for object
 */
export function forEachValue (obj, fn) {
  Object.keys(obj).forEach(key => fn(obj[key], key))
}
로그인 후 복사

测试用例

  it(&#39;forEachValue&#39;, () => {
    let number = 1

    function plus (value, key) {
      number += value
    }
    const origin = {
      a: 1,
      b: 3
    }

    forEachValue(origin, plus)
    expect(number).toEqual(5)
  })
로그인 후 복사

解析:

  • 一个遍历对象的函数(支持对象和数组)

  • fn(value, key)但是回调函数第一个参数是值,第二个参数是键值

isObject

export function isObject (obj) {
  return obj !== null && typeof obj === &#39;object&#39;
}
로그인 후 복사

测试用例

  it(&#39;isObject&#39;, () => {
    expect(isObject(1)).toBe(false)
    expect(isObject(&#39;String&#39;)).toBe(false)
    expect(isObject(undefined)).toBe(false)
    expect(isObject({})).toBe(true)
    expect(isObject(null)).toBe(false)
    expect(isObject([])).toBe(true)
    expect(isObject(new Function())).toBe(false)
  })
로그인 후 복사

解析:

  • 判断是不是对象,这里没有判断是不是原生对象,数组也是通过的。

  • 由于typeof null === 'object'要先判断是不是null

isPromise

export function isPromise (val) {
  return val && typeof val.then === &#39;function&#39;
}
로그인 후 복사

测试用例

  it(&#39;isPromise&#39;, () => {
    const promise = new Promise(() => {}, () => {})
    expect(isPromise(1)).toBe(false)
    expect(isPromise(promise)).toBe(true)
    expect(isPromise(new Function())).toBe(false)
  })
로그인 후 복사

解析:

  • 判断是不是Promise

  • 首先判断val不是undefined,然后才可以判断val.then,避免报错

  • 判断依据是val.then是不是函数

assert

export function assert (condition, msg) {
  if (!condition) throw new Error(`[vuex] ${msg}`)
}
로그인 후 복사

测试用例:

  it(&#39;assert&#39;, () => {
    expect(assert.bind(null, false, &#39;Hello&#39;)).toThrowError(&#39;[vuex] Hello&#39;)
  })
로그인 후 복사

解析:

  • 断言函数,断言不通过抛出一个自定义错误信息的Error

index.jsindex.esm.js

index.js

import { Store, install } from &#39;./store&#39;
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from &#39;./helpers&#39;

export default {
  Store,
  install,
  version: &#39;__VERSION__&#39;,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}
로그인 후 복사

index.esm.js

import { Store, install } from &#39;./store&#39;
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from &#39;./helpers&#39;

export default {
  Store,
  install,
  version: &#39;__VERSION__&#39;,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

export {
  Store,
  install,
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}
로그인 후 복사

解析:

  • 区别就是index.esm.jsindex.js多了个一个导入模式

  • import Vuex, { mapState } from &#39;index.esm.js&#39;:有两种方式导入

  • import Vuex from &#39;index.js&#39;:只有一种方式导入

mixin.js

export default function (Vue) {
  const version = Number(Vue.version.split(&#39;.&#39;)[0])

  if (version >= 2) {
    Vue.mixin({ beforeCreate: vuexInit })
  } else {
    // override init and inject vuex init procedure
    // for 1.x backwards compatibility.
    const _init = Vue.prototype._init
    Vue.prototype._init = function (options = {}) {
      options.init = options.init
        ? [vuexInit].concat(options.init)
        : vuexInit
      _init.call(this, options)
    }
  }

  /**
   * Vuex init hook, injected into each instances init hooks list.
   */

  function vuexInit () {
    const options = this.$options
    // store injection
    if (options.store) {
      this.$store = typeof options.store === &#39;function&#39;
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}
로그인 후 복사

解析:

  • 为什么每个组件都拥有(store属性,也即每个组件都能拿到)store

  • Vue2直接用mixin和钩子函数beforeCreate,Vue1用外观(装饰者)模式重写Vue._init函数。

  • vuexInit

  • /plugins

    helpers.js 🎜🎜🎜 🎜index.esm.js🎜🎜🎜🎜index.js🎜🎜🎜🎜store.js🎜🎜🎜🎜util.js🎜🎜

util.js

🎜가장 간단한 유틸리티 기능으로 시작하세요. 🎜🎜🎜find function🎜🎜rrreee🎜find function의 테스트 사례🎜rrreee🎜분석: 🎜🎜🎜🎜먼저 assert function f를 사용하여 list list를 필터링하고 마지막으로 필터링된 목록의 첫 번째 요소입니다. 🎜🎜🎜🎜deepCopy 기능🎜🎜rrreee🎜deepCopy 테스트 사례🎜rrreee🎜분석: 🎜🎜🎜🎜기능: 순환 참조를 지원하는 딥 클로닝 기능🎜🎜🎜🎜첫 번째 if 판단 obj = == null || typeof obj !== 'object' 참조 유형이 아닌 경우 직접 반환되며(기본 유형은 값 복사) 재귀의 출구이기도 합니다.
🎜🎜🎜🎜두 번째 판단 hit은 순환 참조이므로 캐시에 캐시된 복사본이 있어야 합니다. 다시는 반복하지 않으려면 복사본을 만드세요. 🎜🎜🎜🎜순환 참조란 무엇인가요? 세 번째 테스트 사례 original.circular = 원본을 참조하세요. 순환 참조와 참조된 콘텐츠는 반복 복제를 피하기 위해 사용됩니다. 동일)🎜 🎜🎜🎜original.circular는 순환 참조, original은 순환 참조 🎜🎜🎜🎜먼저 cope에 넣어주세요 >캐시, 반복 시 순환 참조가 발생하는 경우 캐시에서 순환 참조되는 <code>사본이 있는지 확인하세요. 그러나 사본은 다음과 같아야 합니다. 참조 유형. 🎜🎜🎜🎜왜 cope가 참조 유형이어야 합니까? 순환 참조는 내용이 아닌 참조를 저장합니다(현재 복사가 완료되지 않았습니다). 이 경우 재귀가 완료된 후에만 복사가 완료됩니다. 앞으로 는 순환참조됩니다의 내용이 변경되면(복사가 완료되면) <code>순환참조의 내용도 동시에 변경됩니다🎜🎜🎜🎜so const copy = Array.isArray(obj) ? [] : {} code>는 참조 유형이어야 합니다. 🎜🎜🎜🎜마지막으로 <code>Object.keys는 객체 및 배열의 ​​모든 키 이름을 순회하여(프로토타입 체인 및 기호를 제외한 인스턴스의 속성만 반환) 재귀 복제를 구현할 수 있습니다. 🎜🎜🎜🎜출구는 총 2개 있는데, 하나는 기본형이고 다른 하나는 순환참조형입니다. 🎜🎜🎜🎜forEachValue🎜🎜rrreee🎜테스트 사례🎜rrreee🎜분석: 🎜🎜🎜🎜객체를 순회하는 함수(객체 및 배열 지원)🎜🎜🎜🎜fn(value, key) code>그러나 콜백 함수의 첫 번째 매개변수는 값이고 두 번째 매개변수는 키 값입니다🎜🎜🎜🎜isObject🎜🎜rrreee🎜Test case🎜rrreee🎜분석: 🎜🎜🎜🎜인지 확인 객체, 여기에는 아무것도 없습니다. 그것이 네이티브 객체인지 확인하기 위해 배열도 전달됩니다. 🎜🎜🎜🎜typeof null === 'object'는 먼저 null인지 여부를 확인해야 하기 때문입니다🎜🎜🎜🎜isPromise🎜🎜rrreee🎜테스트 사례🎜rrreee🎜분석: 🎜🎜🎜🎜 Promise🎜🎜🎜 🎜먼저 val이 정의되지 않은 것이 아니라고 판단한 다음 val.then을 판단하여 오류 보고를 방지할 수 있습니다🎜🎜🎜🎜판단의 기준은 val.then이 함수인지 여부입니다🎜🎜🎜🎜assert 🎜🎜rrreee🎜테스트 사례: 🎜rrreee🎜Analytic: 🎜🎜🎜🎜Assert 함수, 사용자 정의 오류 메시지를 발생시켜 주장하지 않음 Error🎜🎜<h4> <code>index.jsindex.esm.js code> 🎜index.js🎜rrreee🎜index.esm.js🎜rrreee🎜분석: 🎜🎜🎜🎜The 차이점은 index.esm.jsindex.js🎜🎜🎜🎜import Vuex, 'index.esm.js의 { mapState }보다 가져오기 모드가 하나 더 있다는 것입니다. ': 두 가지가 있습니다 가져오는 방법은 한 가지뿐입니다 🎜🎜🎜🎜'index.js'에서 Vuex를 가져옵니다: 가져오는 방법은 한 가지뿐입니다 🎜🎜mixin.jsrrreee🎜분석: 🎜🎜 🎜🎜모든 컴포넌트에 🎜(store 속성, 즉 모든 컴포넌트가 이를 얻을 수 있음)🎜store🎜🎜🎜🎜Vue2는 beforeCreate에 mixin 및 Hook 기능을 직접 사용합니다. , Vue1은 모양(데코레이터) 모드를 사용하여 Vue를 다시 작성합니다. 🎜🎜🎜🎜vuexInit는 컴포넌트🎜🎜🎜🎜🎜(옵션은 `new Vue(options)`의 옵션입니다.)🎜옵션이 있습니다. 가게🎜
  • beforeCreateVue의 순환 후크이므로 this는 현재 구성 요소 인스턴스를 가리킵니다. 따라서 this.$store스토어를 현재 컴포넌트에 직접 삽입할 수 있습니다beforeCreateVue的周期钩子,this指向当前组件实例,所以this.$store可以把store直接注入当前组件

  • 所有组件都是继承于一个全局Vue的,全局mixin组件周期钩子beforeCreate,这样每个组件都能自动注入store,也即每个组件都能直接通过$store拿到全局Vuenew Vue({ el: 'app', store, router })store


  • 相关推荐:

    谈谈我对vuex的理解

    모든 컴포넌트는 글로벌 Vue, 글로벌 믹스인 컴포넌트 사이클에서 상속됩니다. HookbeforeCreate, 그러면 각 구성 요소가 저장소에 자동으로 삽입될 수 있습니다. 즉, 각 구성 요소는 전역 Vuenew Vue({ el: 'app ', store, router } )스토어

    #🎜🎜##🎜🎜#관련 추천: #🎜🎜##🎜🎜#<a href="http://www.php.cn/js-tutorial-368383.html" target="_self"><code>Vuex에 대한 나의 이해 코드>#🎜🎜##🎜🎜##🎜🎜##🎜🎜#vuex(상태 관리)의 Vue.js#🎜🎜##🎜🎜#

    위 내용은 VueX의 소스 코드 내용에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

    핫 AI 도구

    Undresser.AI Undress

    Undresser.AI Undress

    사실적인 누드 사진을 만들기 위한 AI 기반 앱

    AI Clothes Remover

    AI Clothes Remover

    사진에서 옷을 제거하는 온라인 AI 도구입니다.

    Undress AI Tool

    Undress AI Tool

    무료로 이미지를 벗다

    Clothoff.io

    Clothoff.io

    AI 옷 제거제

    AI Hentai Generator

    AI Hentai Generator

    AI Hentai를 무료로 생성하십시오.

    인기 기사

    R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 최고의 그래픽 설정
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
    4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

    뜨거운 도구

    메모장++7.3.1

    메모장++7.3.1

    사용하기 쉬운 무료 코드 편집기

    SublimeText3 중국어 버전

    SublimeText3 중국어 버전

    중국어 버전, 사용하기 매우 쉽습니다.

    스튜디오 13.0.1 보내기

    스튜디오 13.0.1 보내기

    강력한 PHP 통합 개발 환경

    드림위버 CS6

    드림위버 CS6

    시각적 웹 개발 도구

    SublimeText3 Mac 버전

    SublimeText3 Mac 버전

    신 수준의 코드 편집 소프트웨어(SublimeText3)

    내 자신의 JavaScript 라이브러리를 어떻게 작성하고 게시합니까? 내 자신의 JavaScript 라이브러리를 어떻게 작성하고 게시합니까? Mar 18, 2025 pm 03:12 PM

    기사는 JavaScript 라이브러리 작성, 게시 및 유지 관리, 계획, 개발, 테스트, 문서 및 홍보 전략에 중점을 둡니다.

    브라우저에서 성능을 위해 JavaScript 코드를 최적화하려면 어떻게해야합니까? 브라우저에서 성능을 위해 JavaScript 코드를 최적화하려면 어떻게해야합니까? Mar 18, 2025 pm 03:14 PM

    이 기사는 브라우저에서 JavaScript 성능을 최적화하기위한 전략에 대해 설명하고 실행 시간을 줄이고 페이지로드 속도에 미치는 영향을 최소화하는 데 중점을 둡니다.

    프론트 엔드 열 용지 영수증에 대한 차량 코드 인쇄를 만나면 어떻게해야합니까? 프론트 엔드 열 용지 영수증에 대한 차량 코드 인쇄를 만나면 어떻게해야합니까? Apr 04, 2025 pm 02:42 PM

    프론트 엔드 개발시 프론트 엔드 열지대 티켓 인쇄를위한 자주 묻는 질문과 솔루션, 티켓 인쇄는 일반적인 요구 사항입니다. 그러나 많은 개발자들이 구현하고 있습니다 ...

    브라우저 개발자 도구를 사용하여 JavaScript 코드를 효과적으로 디버그하려면 어떻게해야합니까? 브라우저 개발자 도구를 사용하여 JavaScript 코드를 효과적으로 디버그하려면 어떻게해야합니까? Mar 18, 2025 pm 03:16 PM

    이 기사는 브라우저 개발자 도구를 사용하여 효과적인 JavaScript 디버깅, 중단 점 설정, 콘솔 사용 및 성능 분석에 중점을 둡니다.

    Java의 컬렉션 프레임 워크를 효과적으로 사용하려면 어떻게해야합니까? Java의 컬렉션 프레임 워크를 효과적으로 사용하려면 어떻게해야합니까? Mar 13, 2025 pm 12:28 PM

    이 기사는 Java의 컬렉션 프레임 워크의 효과적인 사용을 탐구합니다. 데이터 구조, 성능 요구 및 스레드 안전을 기반으로 적절한 컬렉션 (목록, 세트, ​​맵, 큐)을 선택하는 것을 강조합니다. 효율적인 수집 사용을 최적화합니다

    소스 맵을 사용하여 조정 된 JavaScript 코드를 디버그하는 방법은 무엇입니까? 소스 맵을 사용하여 조정 된 JavaScript 코드를 디버그하는 방법은 무엇입니까? Mar 18, 2025 pm 03:17 PM

    이 기사는 소스 맵을 사용하여 원래 코드에 다시 매핑하여 미니어링 된 JavaScript를 디버그하는 방법을 설명합니다. 소스 맵 활성화, 브레이크 포인트 설정 및 Chrome Devtools 및 Webpack과 같은 도구 사용에 대해 설명합니다.

    Chart.js : Pie, Donut 및 Bubble Charts를 시작합니다 Chart.js : Pie, Donut 및 Bubble Charts를 시작합니다 Mar 15, 2025 am 09:19 AM

    이 튜토리얼은 Chart.js를 사용하여 파이, 링 및 버블 차트를 만드는 방법을 설명합니다. 이전에는 차트 유형의 차트 유형을 배웠습니다. JS : 라인 차트 및 막대 차트 (자습서 2)와 레이더 차트 및 극지 지역 차트 (자습서 3)를 배웠습니다. 파이 및 링 차트를 만듭니다 파이 차트와 링 차트는 다른 부분으로 나뉘어 진 전체의 비율을 보여주는 데 이상적입니다. 예를 들어, 파이 차트는 사파리에서 남성 사자, 여성 사자 및 젊은 사자의 비율 또는 선거에서 다른 후보자가받는 투표율을 보여주는 데 사용될 수 있습니다. 파이 차트는 단일 매개 변수 또는 데이터 세트를 비교하는 데만 적합합니다. 파이 차트의 팬 각도는 데이터 포인트의 숫자 크기에 의존하기 때문에 원형 차트는 값이 0 인 엔티티를 그릴 수 없습니다. 이것은 비율이 0 인 모든 엔티티를 의미합니다

    누가 더 많은 파이썬이나 자바 스크립트를 지불합니까? 누가 더 많은 파이썬이나 자바 스크립트를 지불합니까? Apr 04, 2025 am 12:09 AM

    기술 및 산업 요구에 따라 Python 및 JavaScript 개발자에 대한 절대 급여는 없습니다. 1. 파이썬은 데이터 과학 및 기계 학습에서 더 많은 비용을 지불 할 수 있습니다. 2. JavaScript는 프론트 엔드 및 풀 스택 개발에 큰 수요가 있으며 급여도 상당합니다. 3. 영향 요인에는 경험, 지리적 위치, 회사 규모 및 특정 기술이 포함됩니다.

    See all articles