предисловие
Не так давно он проходил в Торонто с 14 по 16 ноября.VueConf TO 2018
Конгресс, особенно дождь, речное издание под названиемVue3.0 Updates
программная речь,Vue3.0
План и направление обновления проработаны (заинтересованные партнеры могут ознакомиться с полнымPPT), что указывает на то, что он был заброшенObject.defineProperty
, и решил использовать более быстрый нативныйProxy
!!
Это удалит предыдущийVue2.x
на основеObject.defineProperty
Есть много ограничений в реализации: не могу слушатьДобавление и удаление свойств,Изменения индекса и длины массиваи может поддерживатьMap
,Set
,WeakMap
а такжеWeakSet
!
Как "инженер фронтенда" надо иметь волну АмвейProxy
!!
Что такое прокси?
MDNОписывается так-Proxy
Объекты используются для определения пользовательского поведения для основных операций (таких как поиск свойств, присвоение, перечисление, вызовы функций и т. д.).
Официальные описания всегда настолько лаконичны, что не имеют смысла...
По сути, он обеспечивает перехват перед операцией целевого объекта, который может фильтровать и переписывать внешние операции, а также модифицировать поведение некоторых операций по умолчанию, так что мы можем не напрямую оперировать самим объектом, а оперировать самим объектом.прокси-объектКосвенно управлять объектом для достижения ожидаемой цели ~
Какой? Все еще не ясно? Давайте посмотрим на пример, с первого взгляда все будет понятно~
let obj = {
a : 1
}
let proxyObj = new Proxy(obj,{
get : function (target,prop) {
return prop in target ? target[prop] : 0
},
set : function (target,prop,value) {
target[prop] = 888;
}
})
console.log(proxyObj.a); // 1
console.log(proxyObj.b); // 0
proxyObj.a = 666;
console.log(proxyObj.a) // 888
В приведенном выше примере мы определили объект заранееobj
, пройти черезProxy
Конструктор генерируетproxyObj
объект, и егоset
(написать) иget
(Читать) поведение переработано.
Когда мы получаем доступ к свойству, которое изначально существовало в объекте, оно возвращает соответствующее значение в исходном свойстве.Если мы пытаемся получить доступ к свойству, которое не существует, оно возвращает0
, то есть посещаемproxyObj.a
когда исходный объектa
свойство, поэтому он возвращает1
, когда мы пытаемся получить доступ к объектам, которые не существуют вb
собственность, не вернетсяundefined
, но вернулся0
, когда мы пытаемся установить новое значение свойства, оно всегда возвращает888
, так что даже если у нас естьproxyObj.a
назначить как666
, но не подействует, все равно вернется888
!
грамматика
ES6
изначально предоставленныйProxy
Синтаксис очень прост, использование выглядит следующим образом:
let proxy = new Proxy(target, handler);
параметрtarget
используетсяProxy
Обернутый целевой объект (может быть объект любого типа, включая собственные массивы, функции или даже другой прокси), параметрыhandler
Это также объект, свойствами которого являются функции, определяющие поведение агента при выполнении операции, то есть пользовательское поведение.
Proxy
Основное использование такое же, как указано выше, разницаhandler
разные предметы,handler
может быть пустым объектом{}
, это означает, чтоproxy
Операция над целевым объектомtarget
операции, то есть:
let obj = {}
let proxyObj = new Proxy(obj,{})
proxyObj.a = 1;
proxyObj.fn = function () {
console.log('it is a function')
}
console.log(proxyObj.a); // 1
console.log(obj.a); // 1
console.log(obj.fn()) // it is a function
Но следует отметить, что,handler
не можемУстановить какnull
, выдаст ошибку --Cannot create proxy with a non-object as target or handler
!
хочуProxy
Это работает, мы не можем оперировать объектом исходного объекта, то есть целевым объектомtarget
(Приведенный выше примерobj
object ), должен быть нацелен наProxy
пример (приведенный выше примерproxyObj
объект) для работы, иначе ожидаемый эффект не будет достигнут.Согласно примеру в начале, мы установилиget
метод после попытки продолжить с исходного объектаobj
читать несуществующее свойство вb
, результат все равно возвращаетсяundefined
:
console.log(proxyObj.b); // 0
console.log(obj.b); // undefined
Для операций, которые могут быть установлены, но не перехвачены,proxy
Результат обработки объекта также будет воздействовать на исходный целевой объект.target
На, как ты это понимаешь? Или возьмите пример в начале, мы переопределяемset
метод, возвращаются все настройки свойств888
, не обладает никакими особыми свойствами (имеется в видуobj
изa
attribute ) для специального перехвата или обработки, затем передатьproxyObj.a = 666
Результат операции также будет воздействовать на исходный целевой объект (obj
объект), поэтомуobj
объектa
Значение также станет888
!
proxyObj.a = 666;
console.log( proxyObj.a); // 888
console.log( obj.a); // 888
API
ES6
серединаProxy
В настоящее время предусмотрено 13 видов прокси-операций, ниже приведены некоторые из наиболее часто используемых.api
Сделайте некоторую индукцию и сортировку, студенты, которые хотят знать другие методы, могут пойти на официальный сайт, чтобы проверить:
--handler.get(target,property,receiver)
Используется для перехвата операции чтения свойства объекта,target
является целевым объектом,property
Приобретенное имя атрибута,receiver
даProxy
или унаследоватьProxy
предмет, как правилоProxy
пример.
let proxy = new Proxy({},{
get : function (target,prop) {
console.log(`get ${prop}`);
return 10;
}
})
console.log(proxy.a) // get a
// 10
Перехватываем чтение пустого объектаget
Операция, при получении своих внутренних свойств выведетget ${prop}
, и возвращает 10 ;
let proxy = new Proxy({},{
get : function (target,prop,receiver) {
return receiver;
}
})
console.log(proxy.a) // Proxy{}
console.log(proxy.a === proxy) //true
вышесказанноеproxy
объектa
свойства сделаныproxy
объект предоставлен, поэтомуreceiver
направлениеproxy
объект, поэтомуproxy.a === proxy
то, что возвращаетсяtrue
.
Следует отметить, что если целевое свойство, к которому осуществляется доступ, недоступно для записи или настройки, возвращаемое значение должно совпадать со значением целевого свойства, то есть оно не может быть изменено, иначе будет выдано исключение~
let obj = {};
Object.defineProperty(obj, "a", {
configurable: false,
enumerable: false,
value: 10,
writable: false
});
let proxy = new Proxy(obj,{
get : function (target,prop) {
return 20;
}
})
console.log(proxy.a) // Uncaught TypeError
вышесказанноеobj
в объектеa
Свойства недоступны для записи или настройки, мы передаемProxy
создалproxy
экземпляр и перехватывает егоget
операция, когда мы выводимproxy.a
будет генерировать исключение, в этот момент, если мы поместимget
Когда возвращаемое значение метода изменяется так, чтобы оно совпадало со значением целевого свойства, то есть 10 ,
Вы можете удалить исключение~
--handler.set(target, property, value, receiver)
Используется для перехвата операции установки значения свойства, параметры находятся вget
По сравнению с методом еще одинvalue
, то есть значение свойства, которое нужно установить~
существуетстрогий режимВниз,set
Метод должен возвращать логическое значение, возвращатьtrue
Это означает, что на этот раз установка свойства прошла успешно.false
и операция установки свойства завершается ошибкой и выдает ошибкуTypeError
.
let proxy = new Proxy({},{
set : function (target,prop,value) {
if( prop === 'count' ){
if( typeof value === 'number'){
console.log('success')
target[prop] = value;
}else{
throw new Error('The variable is not an integer')
}
}
}
})
proxy.count = '10'; // The variable is not an integer
proxy.count = 10; // success
Мы модифицируем вышеset
метод на целевом объектеcount
Назначение атрибутов ограничено, мы требуемcount
Назначение имущества должно бытьnumber
тип данных, если нет, вернуть ошибкуThe variable is not an integer
, мы первыеcount
строка назначения'10'
, выдает исключение, второе присвоение - это число10
, печатает успешно, поэтому мы можем использоватьset
метод для проверки данных!
Точно так же, если целевое свойство недоступно для записи и настройки, его значение не может быть изменено, то есть присвоение является недопустимым, как показано ниже:
let obj = {};
Object.defineProperty(obj, "count", {
configurable: false,
enumerable: false,
value: 10,
writable: false
});
let proxy = new Proxy(obj,{
set : function (target,prop,value) {
target[prop] = 20;
}
})
proxy.count = 20 ;
console.log(proxy.count) // 10
вышесказанноеobj
в объектеcount
свойство, мы устанавливаем его как неизменяемое, и значение по умолчанию, которое мы даем как10
, то даже если он задан как20
, результат не изменился!
--handler.apply(target, thisArg, argumentsList)
Используется для перехвата вызовов функций, есть три параметра, которые являются целевым объектом (функцией)target
, объект контекста при вызовеthisArg
и массив аргументов при вызовеargumentsList
, метод может возвращать любое значение.
target
Должен быть функциональным объектом, иначе выдаетTypeError
;
function sum(a, b) {
return a + b;
}
const handler = {
apply: function(target, thisArg, argumentsList) {
console.log(`Calculate sum: ${argumentsList}`);
return target(argumentsList[0], argumentsList[1]) * 2;
}
};
let proxy = new Proxy(sum, handler);
console.log(sum(1, 2)); // 3
console.log(proxy(1, 2)); // Calculate sum:1,2
// 6
Фактически,apply
также перехватит цельFunction.prototype.apply()
а такжеFunction.prototype.call()
,так же какReflect.apply()
операции следующим образом:
console.log(proxy.call(null, 3, 4)); // Calculate sum:3,4
// 14
console.log(Reflect.apply(proxy, null, [5, 6])); // Calculate sum: 5,6
// 22
--handler.construct(target, argumentsList, newTarget)
construct
для перехватаnew
оператора, чтобы сделатьnew
Оператор генерируетProxy
Применительно к объекту целевой объект, используемый для инициализации прокси, сам должен иметь[[Construct]]
Внутренний метод; он принимает три параметра, целевой объектtarget
, список параметров конструктораargumentsList
и когда объект изначально создается,new
Конструктор действия команды, то есть в следующем примереp
.
let p = new Proxy(function() {}, {
construct: function(target, argumentsList, newTarget) {
console.log(newTarget === p ); // true
console.log('called: ' + argumentsList.join(', ')); // called:1,2
return { value: ( argumentsList[0] + argumentsList[1] )* 10 };
}
});
console.log(new p(1,2).value); // 30
Также метод должен возвращать объект, иначе будет выброшено исключение!
var p = new Proxy(function() {}, {
construct: function(target, argumentsList, newTarget) {
return 2
}
});
console.log(new p(1,2)); // Uncaught TypeError
--handler.has(target,prop)
has
метод можно рассматривать как таргетингin
Хук операции. Когда мы решаем, имеет ли объект определенный атрибут, этот метод вступает в силу. Типичная операцияin
, метод получает два параметра target objecttarget
и свойство для проверкиprop
и возвращаетboolean
стоимость.
let p = new Proxy({}, {
has: function(target, prop) {
if( prop[0] === '_' ) {
console.log('it is a private property')
return false;
}
return true;
}
});
console.log('a' in p); // true
console.log('_a' in p ) // it is a private property
// false
В приведенном выше примере мы используемhas
Метод скрывает подчеркивание свойства_
Частная собственность в начале, так что она будет возвращена при судействеfalse
, чтобы не былоin
оператор найден ~
Следует отметить, что если свойство самого целевого объекта не может быть настроено, свойство не может быть скрыто прокси.Если целевой объект является нерасширяемым объектом, свойство объекта не может быть скрыто прокси, иначе оно будет бросатьTypeError
.
let obj = { a : 1 };
Object.preventExtensions(obj); // 让一个对象变的不可扩展,也就是永远不能再添加新的属性
let p = new Proxy(obj, {
has: function(target, prop) {
return false;
}
});
console.log('a' in p); // TypeError is thrown
привязка данных
Так много было введено выше, и это правильноProxy
Еще одно предварительное понимание, тогда мы можем использоватьProxy
Вручную реализовать двустороннюю привязку предельно простых данных (Object.defineProperty()
Метод реализации может обратиться ко мнеПредыдущая статьяВ конце упоминается)~
В основном это зависит от реализации функции, поэтому я просто махнул макетом~
Структура страницы следующая:
<!--html-->
<div id="app">
<h3 id="paragraph"></h3>
<input type="text" id="input"/>
</div>
В основном зависит от логической части:
//获取段落的节点
const paragraph = document.getElementById('paragraph');
//获取输入框节点
const input = document.getElementById('input');
//需要代理的数据对象
const data = {
text: 'hello world'
}
const handler = {
//监控 data 中的 text 属性变化
set: function (target, prop, value) {
if ( prop === 'text' ) {
//更新值
target[prop] = value;
//更新视图
paragraph.innerHTML = value;
input.value = value;
return true;
} else {
return false;
}
}
}
//添加input监听事件
input.addEventListener('input', function (e) {
myText.text = e.target.value; //更新 myText 的值
}, false)
//构造 proxy 对象
const myText = new Proxy(data,handler);
//初始化值
myText.text = data.text;
выше мы проходимProxy
созданныйmyText
например, путем перехватаmyText
серединаtext
Атрибутыset
метод, чтобы обновить изменения представления и реализовать очень простую двустороннюю привязку данных ~
Суммировать
сказав так много,Proxy
Это, наконец, начинается. Хотя его синтаксис очень прост, на самом деле не так просто воспроизвести его значение, плюс его собственноеProxy
На мой взгляд, его можно использовать для вторичной обработки данных и проверки легальности данных, его даже можно использовать как прокси для функций, а для разработки вас ждут более полезные значения~
Помимо,Vue3.0
Все готово к выпуску, вы не планируете дать ему поучиться?
Ну давай же!