웹 프론트엔드 인터뷰 고주파 테스트 사이트 - Vue 원리(MVVM 모델 이해, 데이터 변경 심층/모니터링, 어레이 변경 모니터링, 가상 DOM에 대한 심층 이해)

시리즈 기사 디렉토리

콘텐츠 참조 링크
Vue의 기본 사용 Vue의 기본 사용법 (Vue의 가장 기본적인 지식 포인트를 마스터하기 위한 1개의 기사)
Vue 통신 및 고급 기능 Vue 구성 요소와 고급 기능 간의 통신(다양한 구성 요소, 사용자 정의 v-모델, nextTick, 슬롯 간의 통신)
뷰 고급 기능 Vue의 고급 기능(동적 구성 요소, 비동기 로딩, 연결 유지, mixin, Vuex, Vue-Router)
뷰 원칙 1 Vue 원리(MVVM 모델 이해, 데이터 변경 심층/모니터링, 어레이 변경 모니터링, 가상 DOM에 대한 심층 이해)
뷰 원칙 2 Vue 원칙(diff 알고리즘, 템플릿 컴파일, 컴포넌트 렌더링 및 업데이트, JS 구현 라우팅)
뷰 인터뷰 질문 웹 프론트엔드 인터뷰 빈도가 높은 테스트 사이트 - Vue 인터뷰 질문


1. 뷰 원칙

1. MVVM 모델 이해

컴포넌트화된

  • 구성 요소화는 페이지를 작은 기능 모듈로 분할하는 것입니다.
  • 각 기능 모듈은 독립 기능의 자체 부분에 속합니다.
  • 전체 페이지의 관리 및 유지 보수를 매우 쉽게 만듭니다.
  • asp jsp PHP는 이미 구성 요소화되어 있습니다.
  • nodejs에도 유사한 구성 요소화가 있습니다.

데이터 기반 보기

  • 기존 구성 요소는 정적으로만 렌더링되며 업데이트는 DOM 작동에 따라 달라집니다.
  • 데이터 기반 보기 - Vue MVVM
  • 데이터 기반 뷰 - React setState

MVVM 모델
여기에 이미지 설명 삽입

2. 데이터 변경 모니터링을 위한 핵심 API

  • 구성 요소 데이터의 데이터가 변경되면 뷰의 업데이트가 즉시 트리거됩니다.
  • 데이터 기반 보기 구현의 첫 번째 단계
  • 핵심 API - Object.defineProperty
  • Object.defineProperty의 몇 가지 단점으로 인해 Vue3.0은 Proxy를 사용합니다.
  • 그러나 프록시는 호환되지 않으며 폴리필할 수 없습니다.

Object.defineProperty() 기본 사용법

예: 기본 사용법

const data = {
    
    }
const name = 'zhangsan'

Object.defineProperty(data, "name", {
    
    
    get: function () {
    
    
        console.log('get')
    },
    set: function (newVal) {
    
    
        console.log('set')
        name = newVal
    }
})

console.log(data.name) // get zhangsan
data.name = 'lisi' // set

3. vue는 데이터 변경 사항을 어떻게 심층적으로 모니터링합니까?

Object.defineProperty 단점

  • 딥 모니터링은 끝까지 재귀가 필요하고 한 번에 많은 양의 계산이 필요합니다.
  • 신규/삭제된 속성 모니터링 불가(Vue.set, Vue.delete)

예: 보기가 세 번 업데이트되고 새 속성과 삭제된 속성을 모니터링할 수 없습니다.

// 触发更新视图
function updateView() {
    
    
    console.log('视图更新');
}

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
    
    
    // 深度监听
    observer(value)
    // 核心 API
    Object.defineProperty(target, key, {
    
    
        get() {
    
    
            return value
        },
        set(newValue) {
    
    
            if(newValue !== value) {
    
    
                // 深度监听
                observer(value)

                // 设置新值
                // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
                value = newValue

                // 触发更新视图
                updateView()
            }
        }
    })
}

// 监听对象属性
function observer(target) {
    
    
    if (typeof target !== 'object' || target === null) {
    
    
        // 不是对象或数组
        return target
    }

    // 重新定义各个属性(for in 也可以遍历数组)
    for (let key in target) {
    
    
        defineReactive(target, key, target[key])
    }
}

// 准备数据
const data = {
    
    
    name: 'zhangsan',
    age: 20,
    info: {
    
    
        address: '北京' // 需要深度监听
    }
}

// 监听数据
observer(data)

// 测试
data.name = 'lisi'
data.age = 21
// console.log('age', data.age)
data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set
delete data.name // 删除属性,监听不到 —— 所以有 Vue.delete
data.info.address = '上海' // 深度监听
// data.nums.push(4) // 监听数组

여기에 이미지 설명 삽입

4. vue는 어레이 변경을 어떻게 모니터합니까?

Object.defineProperty 단점

  • 딥 모니터링은 끝까지 재귀가 필요하고 한 번에 많은 양의 계산이 필요합니다.
  • 신규/삭제된 속성 모니터링 불가(Vue.set, Vue.delete)
  • 어레이를 기본적으로 모니터링할 수 없으므로 특별한 처리가 필요합니다.

예시:

// 触发更新视图
function updateView() {
    
    
    console.log('视图更新');
}

// 重新定义数组原型
const oldArrayProperty = Array.prototype

// 创建新对象,原型指向 oldArrayProperty,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
    
    
    arrProto[methodName] = function () {
    
    
        updateView() // 触发视图更新
        oldArrayProperty[methodName].call(this, ...arguments)
        // 相当于 Array.prototype.push.call(this, ...arguments)
    }
})

// 重新定义属性,监听起来
function defineReactive(target, key, value) {
    
    
    // 深度监听
    observer(value)
    // 核心 API
    Object.defineProperty(target, key, {
    
    
        get() {
    
    
            return value
        },
        set(newValue) {
    
    
            if(newValue !== value) {
    
    
                // 深度监听
                observer(value)

                // 设置新值
                // 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
                value = newValue

                // 触发更新视图
                updateView()
            }
        }
    })
}

// 监听对象属性
function observer(target) {
    
    
    if (typeof target !== 'object' || target === null) {
    
    
        // 不是对象或数组
        return target
    }

    // 如果是数组,就把 arrProto 赋值给数组的原型
    if (Array.isArray(target)) {
    
    
        target.__proto__ = arrProto
    }

    // 重新定义各个属性(for in 也可以遍历数组)
    for (let key in target) {
    
    
        defineReactive(target, key, target[key])
    }
}

// 准备数据
const data = {
    
    
    name: 'zhangsan',
    age: 20,
    info: {
    
    
        address: '北京' // 需要深度监听
    },
    nums: [10, 20, 30]
}

// 监听数据
observer(data)

// 测试 - 监听数组
data.nums.push(4) // 监听数组

여기에 이미지 설명 삽입

5. 가상 DOM

  • vdom은 vue 및 react를 구현하기 위한 중요한 초석입니다.
  • diff 알고리즘은 vdom의 핵심이자 가장 중요한 부분입니다.
  • DOM 조작은 매우 성능 집약적입니다.
  • jQuery를 사용하기 전에 DOM 작업의 타이밍을 직접 제어하고 수동으로 조정할 수 있습니다.
  • Vue 및 React는 VDOM을 사용하는 데이터 기반 보기입니다.

(1) 솔루션: VDOM

  • 특정 복잡성으로 인해 계산 수를 줄이기가 어렵습니다.
  • 계산, 더 많은 것을 JS 계산으로 옮길 수 있습니까? JS는 매우 빠르게 실행되기 때문에
  • vdom - JS로 DOM 구조 시뮬레이션, 최소한의 변경 사항 계산, DOM 조작

(2) JS로 DOM 구조 시뮬레이션

예: JS는 DOM 구조를 시뮬레이션합니다.

HTML 코드

<div id="div1" class="container">
    <p>vdom</p>
    <ul style="font-size: 20px">
        <li>a</li>
    </ul>
</div>

JS 코드

{
    
    
    tag: 'div',
    props: {
    
    
        className: 'container',
        id: 'div1'
    }
    children: [
        {
    
    
            tag: 'p',
            children: 'vdom'
        },
        {
    
    
            tag: 'ul',
            props: {
    
    style: 'font-size: 20px'}
            children: [
                {
    
    
                    tag: 'li',
                    children: 'a'
                }
            ]
        }
    ]
}

(3) snabbdom을 통한 vdom 학습

  • 배우고 사용하기 쉬운 간단하고 강력한 vdom 라이브러리
  • Vue는 vdom 및 diff의 구현을 나타냅니다.
  • snabbdom 참조 링크

예시:

<div id="container"></div>
<button id="btn-change">change</button>

<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.js"></script>


const snabbdom = window.snabbdom

// 定义 patch
const patch = snabbdom.init([
    snabbdom_class,
    snabbdom_props,
    snabbdom_style,
    snabbdom_eventlisteners
])

// 定义 h
const h = snabbdom.h

const container = document.getElementById('container')

// 生成 vnode
const vnode = h('ul#list', {
    
    }, [
    h('li.item', {
    
    }, 'Item 1'),
    h('li.item', {
    
    }, 'Item 2')
])
patch(container, vnode)

document.getElementById('btn-change').addEventListener('click', () => {
    
    
    // 生成 newVnode
    const newVnode = h('ul#list', {
    
    }, [
        h('li.item', {
    
    }, 'Item 1'),
        h('li.item', {
    
    }, 'Item B'),
        h('li.item', {
    
    }, 'Item 3')
    ])
    patch(vnode, newVnode)

    // vnode = newVnode // patch 之后,应该用新的覆盖现有的 vnode ,否则每次 change 都是新旧对比
})

변경하기 전에:

여기에 이미지 설명 삽입
변경 후:
여기에 이미지 설명 삽입

(4) vdom 요약

  • JS(vnode)로 DOM 구조 시뮬레이션
  • 이전 vnode와 새 vnode를 비교하고 가장 작은 업데이트 범위를 얻은 다음 마지막으로 DOM을 업데이트합니다.
  • 데이터 기반 보기 모드에서 DOM 작업을 효과적으로 제어

不积跬步无以至千里 不积小流无以成江海

팔로우하고 길을 잃지 말고 업데이트를 계속하려면 클릭하십시오 ...

추천

출처blog.csdn.net/qq_45902692/article/details/126516912