카메라
TL;박사
렌즈는 직접 조합할 수 있는 접근기다.그것들이 어떻게 일을 하는지, 그리고 어떻게 자신을 만드는지 계속 읽으세요.
Runkit에서 모든 예시와 두 번째 대체 구현을 포함하는 작은 노트북을 만들었습니다.따라서 언제든지 (본문을 읽기 전, 읽기 기간, 읽기 후) 이 문제들을 처리할 수 있다.참조: https://runkit.com/mister-what/lenses
소개
우리 문제의 묘사부터 시작합시다.다음과 같은 데이터 구조를 가지고 있다면, 위치와 직위에 따라 직원을 열거합니다.
const locations = {
berlin: {
employees: {
staff: {
list: [
{
name: "Wiley Moen",
phone: "688-031-5608",
id: "cdfa-f2ae"
},
{
name: "Sydni Keebler",
phone: "129-526-0289",
id: "e0ec-e480"
}
]
},
managers: {
list: [
{
name: "Cecilia Wisoky",
phone: "148-188-6725",
id: "9ebf-5a73"
}
]
},
students: {
list: [
{
name: "Kirsten Denesik",
phone: "938-634-9476",
id: "c816-2234"
}
]
}
}
},
paris: {
employees: {
staff: {
list: [
{
name: "Lucius Herman",
phone: "264-660-0107",
id: "c2fc-55da"
}
]
},
managers: {
list: [
{
name: "Miss Rickie Smith",
phone: "734-742-5829",
id: "2095-69a7"
}
]
}
}
}
};
응용 프로그램의 다른 위치에서 이 구조의 데이터에 접근하면 대량의 중복을 초래하고 데이터 구조가 변경될 때 (어떤 이유로든) 발견하기 어려운 오류를 초래할 수 있다.따라서 우리는 이 문제를 해결하는 또 다른 방법: 렌즈
렌즈
렌즈는 안전하고 변하지 않는 방식으로 데이터에 접근하고 조작하는 데 쓰인다.대상의 접근기 (getter와setter) 도 마찬가지입니다. 이상하지도 않고 특별한 점도 없습니다.렌즈가 정말 강한 이유는 직접 조합할 수 있기 때문이다.그게 무슨 뜻이에요?만약 당신이 생활 속에서 수학 수업을 한 적이 있다면, 함수는 서로 조합할 수 있다는 것을 알고 있다. 즉, 당신이 를 가지고 있다면, 당신은 f와 g의 조합을 로 정의할 수 있다. 을 제외하고는 다른 뜻이 없다.
그러면 우리는 어떻게 Javascript로 합성을 표현합니까?간단히 말하면
function compose(g, f) {
return function(x) {
return g(f(x));
}
}
// or with fat-arrow functions:
const compose = (g, f) => x => g(f(x));
우리는 세 가지 (또는 더 많은 방식) 로 더 높은 구성 순서를 정의할 수 있다.// recursive version
const compose = (...fns) => x =>
fns.length
? compose(...fns.slice(0, -1))(
fns[fns.length - 1](x)
)
: x;
// iterative version
const composeItr = (...fns) => x => {
const functions = Array.from(
fns
).reverse();
/* `reverse` mutates the array,
so we make a shallow copy of the functions array */
let result = x;
for (const f of functions) {
result = f(result);
}
return result;
};
// with Array.prototype.reduce
const composeReduce = (...fns) => x =>
fns.reduceRight(
(result, f) => f(result),
x
);
// use it!
console.log(
compose(
x => `Hello ${x}`,
x => `${x}!`
)("World")
); // -> "Hello World!"
우리는 이제 함수를 어떻게 조합하는지 알게 되었다.조합 함수의 매개 변수와 반환 값이 같은 유형에 속할 때 함수 조합 효과가 가장 좋다는 것을 알 수 있습니다.어떤 위치의 학생들을 위해 그룹의 getter를 정의합시다.
const studentsAtLocation = compose(
(students = {}) => students.list || [],
(employees = {}) => employees.students,
(location = {}) => location.employees
);
const locationWithName = locationName => (
locations = {}
) => locations[locationName];
const getBerlinStudents = compose(
studentsAtLocation,
locationWithName("berlin")
);
const getParisStudents = compose(
studentsAtLocation,
locationWithName("paris")
);
console.log(
getBerlinStudents(locations)
); // [ { name: 'Kirsten Denesik', ... ]
console.log(
getParisStudents(locations)
); // []
만약 네가 아직도 나와 함께 있다면, getter 함수는 상반된 순서로 제공된다는 것을 이미 알아차렸을 것이다.우리는 getter를 매개 변수로 하고 getter의 함수를 되돌려줌으로써 이 문제를 해결할 것입니다.이런 모드 (한 함수를 전달하고 한 함수를 되돌려주는 것) 는 기본적으로 getter/setter 쌍으로 구성할 수 있도록 합니다. 방법은 한 함수를 전달하는 것입니다. 이 함수는 하나의 값을 받아들이고 getter/setter 쌍을 되돌려줍니다.이게 어떤 모습인지 한번 봅시다.const createComposableGetterSetter = (
getter, // (1)
// -- getter(targetData: TargetData): Value
setter // (4)
// -- setter(value: Value, targetData: TargetData) => TargetData
) => toGetterAndSetter => targetData => { // (2)
const getterSetter = toGetterAndSetter(
getter(targetData)
); // (3)
/**
* toGetterAndSetter is called with
* "data" as argument
* and returns a GetterSetter object:
* @typedef {
* {
* get: function(): *,
* set: function(newData: *): GetterSetter
* }
* } GetterSetter
*
*/
return getterSetter.set(
setter(
getterSetter.get(),
targetData
)
); // (5)
};
설령 이것이 "단지"쌍선 함수체일지라도 이곳에서 무슨 일이 일어났는지 이해하는 데 시간이 좀 걸리기 때문에 나는 점차적으로 설명할 것이다.createComposableGetterSetter
한 후에 우리는actutalcomposableGetterSetter
을 얻었다.composableGetterSetter
는 toGetterAndSetter
함수를 얻을 것이다. 이 함수는 일부 데이터를 입력으로 하고 get
및 set
방법으로 대상을 되돌려준다.우리는 함수를 되돌려줍니다. 이 함수는 목표 데이터가 유일한 매개 변수가 되기를 기대합니다.toGetterAndSetter
함수에 전달함으로써 GetterSetter 대상을 구성합니다.set()
방법을 사용합니다. 반환 값은 setter(4), 반환 값은 구조된 GetterSetter 대상의 값(우리 호출getterSetter.get()
으로 간단하게 이 값을 검색합니다)과 targetData(우리 기대setter는 targetData
의 새로운 버전으로 반환되며, 초점 값은 getterSetter.get()
의 반환 값으로 설정됩니다.getterSetter.set(...)
에서 되돌아오는 값(또는 GetterSetter 대상)을 되돌려줍니다.toGetter And Setter 회사
현재 우리는 이미
createComposableGetterSetter
함수를 정의했다.우리는 여전히 toGetterAndSetter
함수를 정의해야 한다. 우리는 그것을 사용하여 목표로부터 데이터를 얻거나 목표에 데이터를 설정할 것이다.먼저 정의해 봅시다toSetAccessors
:const toSetAccessors = data => ({
get: () => data,
set: newData => toSetAccessors(newData)
});
그래서 우리가 목표 대상에 데이터를 설정하고 싶다면 간단한 함수는 우리를 위해 대상을 구성하고 그것을 사용한다.새 데이터로 set
방법을 호출할 때마다 새 데이터를 저장하고 되돌려주는 새로운 실례를 만듭니다.다음은
toGetAccessors
기능입니다.const toGetAccessors = data => ({
get: () => data,
set() {
return this;
}
});
GetAccessor 객체는 데이터만 검색할 수 있어야 합니다.새 데이터를 설정하려고 시도할 때, 그것은 자신의 실례만 되돌려줍니다.이것은 창설 후 변경할 수 없습니다.ComposableGetterSetters 사용(렌즈)
우리는 현재 세 개의 Composablegettersetter (렌즈라고도 함) 를 만들어서 그들이 어떻게 작동하는지, 그리고 그것들을 사용하여 값을 검색하거나 데이터를 변경하는 데 필요한 것이 무엇인지 알 것이다.
렌즈 생성
우리는'파리'부동산을 주목하는 장면,'직원'부동산을 주목하는 장면, 세 번째'학생'부동산을 주목하는 장면을 만들 것이다.
우리는 getter에서 기본값 (이상을 피하기 위해) 을 사용하고 setter에서 대상 확장을 사용하여 불변성을 유지할 것입니다.
const parisLens = createComposableGetterSetter(
obj => (obj || {}).paris,
(value, obj) => ({
...obj,
paris: value
})
);
const employeesLens = createComposableGetterSetter(
obj => (obj || {}).employees,
(value, obj) => ({
...obj,
employees: value
})
);
const studentsLens = createComposableGetterSetter(
obj => (obj || {}).students,
(value, obj) => ({
...obj,
students: value
})
);
우리는 여기에 약간의 중복이 있다는 것을 알아차렸기 때문에 그것을 재구성합시다.const lensProp = propName =>
createComposableGetterSetter(
obj => (obj || {})[propName],
(value, obj) => ({
...obj,
[propName]: value
})
);
// we can now create lenses for props like this:
const parisLens = lensProp("paris");
const employeesLens = lensProp(
"employees"
);
const studentsLens = lensProp(
"students"
);
const listLens = lensProp("list"); // needed to get the list of students
우리는 지금 우리의 렌즈를 합성하고 사용하기 시작할 수 있다.const parisStudentListLens = compose(
parisLens,
employeesLens,
studentsLens,
listLens
);
const parisStudentList = parisStudentListLens(
toGetAccessors
)(locations).get();
console.log(parisStudentList);
// -> undefined, since there is no list of students for paris defined.
const locationsWithStudentListForParis = parisStudentListLens(
_list => toSetAccessors([])
// ignore current list and replace it with an empty array
)(locations).get();
console.log(
locationsWithStudentListForParis
);// -> { ..., paris: { employees:{ ..., students: { list: [] } } } }
이것은 매우 지루할 것이기 때문에, 우리는 몇 가지 도움말 프로그램을 정의할 것이다.const view = (lens, targetData) =>
lens(toGetAccessors)(
targetData
).get();
const over = (
lens,
overFn /* like the `mapf` callback in `Array.prototype.map(mapf)`.
i.e.: You get a value and return a new value. */,
targetData
) =>
lens(data =>
toSetAccessors(overFn(data))
)(targetData).get();
const set = (lens, value, targetData) =>
over(
lens,
() =>
value /* we use `over` with a `overFn` function,
that just returns the value argument */,
targetData
);
우리의 조수를 사용해 보자.// using get, set, over:
const locationsWithStudentListForParis = set(
parisStudentListLens,
[],
locations
);
const locationsWithOneStudentInParis = over(
parisStudentListLens,
(list = []) => [
...list,
{ name: "You", setVia: "Lens" }
],
locations
);
const locationsWithTwoStudentInParis = over(
parisStudentListLens,
(list = []) => [
...list,
{ name: "Me", setVia: "Lens" }
],
locationsWithOneStudentInParis
);
// logging the results:
console.log(
view(parisStudentListLens, locations)
); // -> undefined
console.log(
view(
parisStudentListLens,
locationsWithStudentListForParis
)
); // -> []
console.log(
view(
parisStudentListLens,
locationsWithTwoStudentInParis
)
); // -> [ { name: 'You', setVia: 'Lens' }, { name: 'Me', setVia: 'Lens' } ]
console.log(
view(
parisStudentListLens,
locationsWithOneStudentInParis
)
); // -> [ { name: 'Me', setVia: 'Lens' } ]
console.log(
locationsWithTwoStudentInParis
); // -> ...
이런 방법은 깊이 박힌 불변의 데이터 구조를 구축하는 것을 쉽게 한다.더 간단하게 lensIndex(index: number)
및 lensPath(path: Array<string|number>)
렌즈를 정의하여 보조 대상을 만들 수 있습니다.lensIndex
그리고 그룹 값에 주목합니다.lensPath
렌즈 lensProp
및 lensIndex
를 생성하고 미리 합성하여 깊이 있는 내포된 객체 속성과 패턴 인덱스에 초점을 맞춘 렌즈를 만듭니다.렌즈의 더 많은 응용 분야
렌즈는 화폐, 온도, 단위(공제 단위에서 영국 단위로, 반대로), 사용자의 입력, 해석, 문자열화 JSON 등 여러 가지 값 사이에서 전환하기에 매우 적합하다.
보기를 놓치지 마세요Runkit Notebook.만약 네가 나의 허튼소리를 이해하지 못한다면, 얼마든지 물어봐라!
나는 어떤 질문에도 기꺼이 대답할 것이다.)
Reference
이 문제에 관하여(카메라), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/misterwhat/lenses-the-what-and-how-2g9g텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)