Настаивайте на сборке колес на третий день — данные реагируют

JavaScript

Кроме того, я могу построить колеса.Ты боишься, что тебя спросят на собеседовании? Стройте колесо в день, и все готово.

Аспект

  • Рукописные вопросы для письменного теста и собеседования
  • Разработка TDD
  • С видео пояснением

программа по сборке колес

(План не поспевает за изменениями, повторяется в любое время, добро пожаловать, чтобы оставить сообщение и почувствовать рыбу в любое время)

что отвечает

Сначала поговорим о том, что является отзывчивым. При изменении модели данных он может выдать ответ (например: вызвать функцию), который называется реактивным.

В частности, потребность в ViewModel в нашем MVVM заключается в том, что данные изменяются, и представление должно реагировать.

нужно

Если вы используете прецедент Jest, это похоже на это

ответ объекта

it('测试数据改变时 是否被响应', () => {
  const data = reactive({
    name: 'abc',
    age: {
      n: 5
    }
  })
  // Mock一个响应函数
  const fn = jest.fn()
  const result = fn()

  // 设置响应函数
  effect(fn)

  // 改变数据
  data.name = 'efg'

  // 确认fn生效
  expect(fn).toBeCalled()
})

Предположим, что нам нужно, чтобы функция fn могла запускаться при изменении данных, то есть соответствующий ответ.Конечно, ответ, как правило, вызывает обновление представления, конечно, может и не быть. Здесь мы используем jest, чтобы создать фиктивную функцию, чтобы определить, нужно ли делать ответ.

Окончательный код expect(fn).toBeCalled() валиден, что означает, что тест пройден, то есть сделан соответствующий ответ.

ответ массива

it('测试数组中数据改变时 是否被响应', () => {
  const data = reactive({
    ary: [
      'a'
    ]
  })
  // Mock一个响应函数
  const fn = jest.fn()

  // 设置响应函数
  effect(fn)

  // 改变多层数据
  data.ary.push('b')

  // 确认fn生效
  expect(fn).toBeCalled()
})

Глубоко вложенные ответы

it('测试多层数据中改变时 是否被响应', () => {
  const data = reactive({
    age: {
      n: 5
    }
  })
  // Mock一个响应函数
  const fn = jest.fn()

  // 设置响应函数
  effect(fn)

  // 改变多层数据
  data.age.n = 1

  // 确认fn生效
  expect(fn).toBeCalled()
})

Реализация функции

Vue обычно использует метод захвата данных. Разница заключается в том, использовать ли DefineProperty или Proxy. То есть захватывать ли одно свойство за раз или один объект за раз. Конечно, последний имеет очевидные преимущества перед первым. Это адаптивный принцип Vue3.

Proxy/Reflect был добавлен в спецификацию ES 2015. Proxy может лучше перехватывать поведение объекта, а Reflect может более элегантно манипулировать объектами. Преимущество

  • Он настраивается для всего объекта, а не для свойства объекта, поэтому нет необходимости проходить ключи.
  • Массивы поддерживаются, а это DefineProperty — нет. Это избавляет от хакерского процесса перегрузки методов массива.
  • Второй параметр Proxy может иметь 13 методов перехвата, что богаче, чем Object.defineProperty().
  • Proxy, как новый стандарт, привлек внимание и оптимизацию производительности производителей браузеров, в то время как Object.defineProperty() является существующим старым методом.
  • Вложение объектов может быть удобно выполнено с помощью рекурсии.

DefineProperty (стиль Vue2)

Ниже показана реализация vue2 путем переопределения методов получения и установки с помощью Object.defineProperty.

let effective
function effect(fun) {
    effective = fun
}

function reactive(data) {
    if (typeof data !== 'object' || data === null) {
        return data
    }


    Object.keys(data).forEach(function (key) {
        let value = data[key]
        Object.defineProperty(data, key, {
            emumerable: false,
            configurable: true,
            get: () => {
                return value
            },
            set: newVal => {
                if (newVal !== value) {
                    effective()
                    value = newVal
                }
            }
        })

    })
    return data
}

module.exports = {
    effect, reactive
}

Конечно, все еще есть два важных вопроса, с которыми нужно было разобраться. Первый - это то, что это может сделать только мелкий ответ, то есть, если это второй слой, он не будет работать.

it('测试多层数据中改变时 是否被响应', () => {
        const data = reactive({
            age: {
                n: 5
            }
        })
        // Mock一个响应函数
        const fn = jest.fn()

        // 设置响应函数
        effect(fn)

        // 改变多层数据
        data.age.n = 1

        // 确认fn生效
        expect(fn).toBeCalled()
    })

Например, следующие варианты использования не будут работать.Конечно, есть решения для рекурсивных вызовов.

Конечно, рекурсия также приносит огромные потери в производительности, запомните это в первую очередь.

Перехват функции массива (стиль Vue2)

Затем возникает проблема с массивом.Проблема с массивом может быть решена перехватом функции.

const oldArrayPrototype = Array.prototype
const proto = Object.create(oldArrayPrototype);

['push','pop','shift','unshift','splice','sort','reverse'].forEach(method => {
    
    // 函数劫持
    proto[method] = function(){
        effective()
        oldArrayPrototype[method].call(this,...arguments)
    }
})
// 数组通过数据劫持提供响应式
if(Array.isArray(data)){
    data.__proto__ = proto
}

Прокси (стиль Vue3)

В новой версии Vue3 для решения этой проблемы используется прокси-метод ES6. Две проблемы, с которыми я столкнулся раньше, намного проще. Во-первых, Proxy поддерживает массивы, то есть массивы не требуют специального кода. Нет необходимости использовать рекурсивное решение для глубокого мониторинга. Когда get является оценочным значением объекта, достаточно выполнить реактивную обработку и вернуть объект. Все думают, что этого не происходит в момент инициализации, но когда стоит настройка, конечно, производительность сильно повышается.

function reactive(data) {
    if (typeof data !== 'object' || data === null) {
        return data
    }
    const observed = new Proxy(data, {
        get(target, key, receiver) {
            // Reflect有返回值不报错
            let result = Reflect.get(target, key, receiver)

            // 多层代理
            return typeof result !== 'object' ? result : reactive(result) 
        },
        set(target, key, value, receiver) {
            effective()
            // proxy + reflect
            const ret = Reflect.set(target, key, value, receiver)
            return ret
        },

        deleteProperty(target,key){
            const ret = Reflect.deleteProperty(target,key)
            return ret
        }

    })
    return observed
}

Конечно, есть еще преимущества и недостатки, например, проблемы совместимости в настоящее время не поддерживают Proxy в IE11. Однако я считаю, что полная поддержка ES6 — это необратимая тенденция, которой нет дела.

тестовое задание

ОК задача выполнена

Обратите внимание на дядю Рана из всего стека и берите с собой делать колеса каждый день (отдыхайте по выходным, отбрасывайте 996)

  • Официальный поиск аккаунта: [Автобус] Другой интересный контент
  • Исходный адрес https://github.com/su37josephxia/wheel-awesome

❤❤❤❤ Интерпретация исходного кода Miss Anxia ❤❤❤❤❤

WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO Закрыть непосредственно пропорциональные.com/video/bv1uk...

❤❤❤❤ Интерпретация исходного кода мисс Сяоле ❤❤❤❤❤

вооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо по

В этой статье используетсяmdniceнабор текста