предисловие
Если вы опытный разработчик Vue, то должны знать, что принцип отзывчивости Vue достигается за счет перехвата получения и набора объектов.
// src/core/observer/index.js
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
//...
},
set: function reactiveSetter (newVal) {
//...
}
})
Поэтому, когда значение присваивается реактивной переменной, функция set запускается для обновления представления.
<template>
<div >{{message}}</div>
</template>
<script>
export default {
data() {
return {
message:'hello world'
}
},
mounted() {
this.message = 'hello Vue'
}
}
</script>
Эта статья не имеет ничего общего с фреймворком Vue, но давайте подумаем о проблеме
为什么给响应式变量赋值会触发 set 函数,而不是直接赋值?
Если вы определите функцию set для свойств объекта, логика назначения по умолчанию не будет выполнена.Разве это не проблема с моим братом?
Фактически, JavaScript будет выполнять операции [[Get]] и [[Put]] соответственно при доступе к свойствам объекта или присвоении им значений. Это два встроенных поведения объектов по умолчанию, которые нельзя изменить.
Затем мы используем спецификацию ECMA, чтобы проанализировать, что JavaScript делает внутри, когда объект оценивается и назначается.
[[Get]]
Когда значение выполнения получено от объекта, выполняется операция [[Get]], которая определена в стандарте как таковая.
Судя по моему низкому уровню английского, приблизительно переведенный результат выглядит так:
- Сначала будет выполнена операция [[GetProperty]]. Ее функция состоит в том, чтобы определить, существует ли свойство объекта в текущем объекте. Если оно существует, она вернет свойство напрямую. В противном случае будет рекурсивно искать цепочку прототипов объекта. объекта и вернуть свойство после его нахождения.Возвращает значение undefined до конца цепочки прототипов.
- Если результат первого шага не определен, результат [[Get]] не определен, то есть в этом объекте нет такого свойства
- Если он не не определен, он определит, определено ли это свойство с помощью дескриптора данных, и если да, то вернет атрибут value дескриптора данных.
- Если это свойство определено с помощью дескриптора доступа, то есть функции get, функция get будет запущена, и после выполнения будет возвращен результат.
Через стандарт очевидно, что JavaScript выполняет логику при доступе к свойствам объекта.Когда это свойство не существует в текущем объекте, он будет искать по цепочке прототипов, поэтому пустые объекты также могут вызывать toString, valueOf и другие методы. , потому что все эти методы существуют в цепочке прототипов объекта, и если свойство определяет функцию get, она будет напрямую возвращать результат выполнения.
[[CanPut]]
[[Put]] немного сложнее, чем [[Get]] , как сказано в исходной спецификации.
Метод [[Put]] опирается на внутреннее поведение, называемое [[CanPut]], давайте посмотрим на его определение.
Во-первых, он определит, существует ли текущий атрибут в текущем объекте. Если да, продолжайте судить о том, имеет ли атрибут дескриптор доступа, то есть функцию set. Если функция set существует [[CanPut]], результатом будет true, в противном случае, если дескриптор доступа имеет значение false, если он не определен или недействителен. Или, когда свойство существует в текущем объекте, но дескриптор доступа не определен, тогда свойство должно быть определено с дескриптором данных, результатом [[CanPut]] является доступное для записи значение дескриптора данных, и, наконец, когда свойство не существует с текущим объектом, то же, что и [[Get]], он будет проходить по цепочке прототипов до конечной точки и повторно выполнять предыдущую логику
С точки зрения непрофессионала [[CanPut]] возвращает логическое значение, указывающее, может ли текущее свойство быть назначено.
[[Put]]
Back [[of Put]], когда значение [[CanPut]] выведет логику присваивания на false, и на основе этого параметра Throw, когда Throw равно true, выбрасывается исключение, и наоборот тишина,И этот Throw соответствует тому, включен ли строгий режим, а также проверяет, что сбой присваивания в строгом режиме вызовет ошибку
Когда значение [[CanPut]] равно true, это означает, что текущее свойство может быть назначено, и выполняется следующая логика.
- Если свойство находится в текущем объекте и имеет дескриптор данных, свойство value дескриптора данных возвращается напрямую, и запускается внутренний метод [[DefineOwnProperty]].
Как правило, присваивание свойства объекта обычно выполняет эту логику и возвращает свойство значения в качестве результирующего значения оператора присваивания, например
Присвойте номер 123 свойству a объекта obj, тогда 123 — это значение значения в дескрипторе данных свойства a, а окончательное значение, возвращаемое операцией [[Put]] — 123, что соответствует результирующее значение последней строки оператора присваивания
а также触发 [[DefineOwnProperty]] 这个内部方法
Как понимать это предложение?Поведение [[DefineOwnProperty]] в спецификации очень сложное, здесь я приведу еще один небольшой пример
Перехватывая defineProperty и getOwnPropertyDescriptor, можно обнаружить, что поведение присваивания по умолчанию вызовет эти два перехватчика.Друзья, которые заинтересованы в большем поведении, могут просмотреть их самостоятельно по ссылке внизу
-
В противном случае, если свойство находится в текущей цепочке объектов или прототипов и имеет дескриптор доступа, передайте значение в правой части выражения присваивания в качестве единственного параметра функции set и верните результат.
-
В противном случае, если свойство находится в цепочке прототипов текущего объекта и имеет дескриптор данных, создайте новое свойство для текущего объекта со значением его дескриптора данных.
{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.
, и отбросить исходный дескриптор данных, и запустить внутренний метод [[DefineOwnProperty]] и вернуть
Что это значит, рассмотрим следующее
let obj = {}
Object.defineProperty(Object.prototype, 'a', {
configurable: false,
enumerable: false,
value: "",
writable: true
})
obj.a = 1
console.log(Object.getOwnPropertyDescriptor(obj,'a'))
// {value: 1, writable: true, enumerable: true, configurable: true}
Объект OBJ не имеет атрибута A, и свойство A определено в объекте-прототипе объекта, а дескриптор данных настраивается, ENUMERABLE имеет значение FALSE, но в объекте OBJ есть свойство A, когда оно окончательно назначено, в то время как Configurable , ПЕРЕЧИСЛИМОЕ True
Суммировать
Объединив определения [[Get]] и [[Put]] в JavaScript You Don’t Know Volume 1, можно сделать следующие выводы.
Когда объекту присваивается значение, запускается операция [[Get]]. Если это свойство существует в текущем объекте, оно будет оцениваться
- Когда функция get включена, выполните функцию get и верните результат выполнения,
- Если функция get отсутствует, вернуть атрибут value дескриптора данных.
Если на текущем объекте такого свойства нет, цепочка прототипов будет искаться вверх до конца, и в процессе поиска будут повторяться два вышеуказанных шага.
При присвоении значения объекту будет срабатывать [[Put]] (не идеальный [[Set]] ), если текущий объект имеет это свойство, то судить
- Когда для записи установлено значение true, выполните операцию присваивания
- Если для записи установлено значение false, строгий режим выдаст ошибку, нестрогий режим завершится с ошибкой.
- Когда функция набора включена, выполните функцию набора
Если текущий объект не имеет этого свойства, он будет искать цепочку прототипов.Если свойство найдено в верхнем слое цепочки прототипов, оно будет оцениваться
- Когда для записи установлено значение true, свойство будет создано для текущего объекта (непрототипная цепочка), а для дескриптора данных configurable, enumerable, writable будет установлено значение true, а значением будет присвоенное значение.
- Если для записи установлено значение false, строгий режим выдаст ошибку, нестрогий режим завершится с ошибкой.
- Когда функция набора включена, выполните функцию набора
Если свойство является дескриптором данных, также будет запущена внутренняя операция [[DefineOwnProperty]]. Если определены defineProperty и getOwnPropertyDescriptor, будут запущены эти два перехватчика.
использованная литература
Сводка JavaScript, о которой вы не знали