무음판에서 데이터를 처리하는 라이브러리 및 Stage 2 Record &Tuple
60133 단어 JavaScriptECMAScripttech
JavaScript의 무음 슬라이스, 무음 슬라이스
JavaScript에서 원재료는 이세계적이다. 즉, 변경할 수 없다는 것이다.
다른 한편, 대상은 기본적으로 정음판, 즉 수정할 수 있다는 것이다.
Object.freeze
는 동결할 수 있지만 액세서리 속성이 문제없이 작동하면 [[Prototype]]
의 변경에 영향을 줄 수 있다.동결됐다고 해서 완전히 이구체라고 할 수는 없겠죠.let a = 1;
const obj = Object.freeze({
get a() { return a; },
set a(val) { a = val; },
});
console.log(obj.a); // => 1
++obj.a;
console.log(obj.a); // => 2
const prototype = { a: 1 };
const obj = Object.freeze(Object.create(prototype));
console.log(obj.a); // => 1
++prototype.a;
console.log(obj.a); // => 2
데이터 처리를 위한 라이브러리
Immutable.js
Immutable은 완전히 변하기 쉬운 데이터베이스에 있습니다.있다이것을 사용하면 무의식적인 변경으로 인한 오류를 방지할 수 있다.
import * as Immutable from "immutable";
const map1 = Immutable.Map({ a: 1, b: 2 });
const map2 = map1.set("c", 3);
console.assert( Immutable.is(map1, Immutable.Map({ a: 1, b: 2 })) );
console.assert( Immutable.is(map2, Immutable.Map({ a: 1, b: 2, c: 3 })) );
const list1 = Immutable.List([1, 2]);
const list2 = list1.push(3);
console.assert( Immutable.is(list1, Immutable.List([1, 2])) );
console.assert( Immutable.is(list2, Immutable.List([1, 2, 3])) );
영구 데이터 구조
Immutable.js는 지속적인 데이터 구조의 기술을 사용합니다.영구 데이터 구조는 데이터를 갱신할 때 갱신 전 데이터를 유지하는 데이터 구조를 가리킨다.
매번 데이터를 업데이트할 때마다 내부에서 차이를 얻고 유지하기 때문에 메모리의 사용을 억제할 수 있다.또한 두 개의 이블라토의 데이터를 비교할 때 모든 속성을 비교할 필요가 없을 수도 있다.
Directed Acyclic Graph (React.js Conf 2015 - Immutable Data and React)
다른 한편, 데이터 구조에 현저한 변화가 발생할 때는 적합하지 않다.또 수치 갱신 원가가 일반 대상보다 적지만 얻는 원가가 증가했다.
Immer
한 Immer는 객체에서 새 객체를 쉽게 작성할 수 있는 라이브러리입니다.제공된
produce
는 함수를 사용하여 객체를 만들 때만 원본 객체가 변경되지 않도록 보장합니다.새로 생성된 객체는 동결됩니다.import produce from "immer";
const obj1 = { a: 1, b: 2 };
const obj2 = produce(obj1, (draft) => {
draft.c = 3;
});
console.log(obj1); // => { a: 1, b: 2 }
console.log(obj2); // => { a: 1, b: 2, c: 3 }
console.assert( !Object.isFrozen(obj1) );
console.assert( Object.isFrozen(obj2) );
const arr1 = [1, 2];
const arr2 = produce(arr1, (draft) => {
draft.push(3);
});
console.log(arr1); // => [1. 2]
console.log(arr2); // => [1, 2, 3]
console.assert( !Object.isFrozen(arr1) );
console.assert( Object.isFrozen(arr2) );
Immutable.js와 Immer의 비교
두 개 모두 이블라토가 데이터를 처리하는 프로그램 라이브러리로 유명하지만 특성은 크게 다르다.자세한 내용은 uhyo의 보도를 보십시오.
Stage 2 Record & Tuple
이 제안은 역시 Stage 2입니다.규격이 변경될 가능성이 있다.
새로운 원시 재료로'복합 원시(Commund primitive)'의 데이터형
Record
과 Tuple
을 제시했다.프로그램 라이브러리에 의존하지 않고 이세계의 데이터를 완전히 처리할 수 있다.const record1 = #{ a: 1, b: 2 };
const record2 = #{ ...record1, c: 3 };
console.assert( record1 === #{ a: 1, b: 2 } );
console.assert( record2 === #{ a: 1, b: 2, c: 3 } );
console.log(record1); // => Record { a: 1, b: 2 }
console.log(record2); // => Record { a: 1, b: 2, c: 3 }
const tuple1 = #[1, 2];
const tuple2 = tuple1.pushed(3);
console.assert( tuple1 === #[1, 2] );
console.assert( tuple2 === #[1, 2, 3] );
console.log(tuple1); // => Tuple [1, 2]
console.log(tuple2); // => Tuple [1, 2, 3]
이 제안은 임무블입니다.js와 Immer 두 가지가 가지고 있는 좋은 특징을 동시에 갖추었다.Immutable.js처럼 정음형 데이터를 완전히 구축하고 실제 엔진에 있어 영구 데이터 구조를 사용하면 계산량의 원가를 줄이고 최적화할 여지가 있다[1].또한 Immer처럼 조작이 간단하여 데이터 내용을 표시할 수 있다.
속성 제한
Record
와 Tuple
는 속성으로서 원시값만 유지할 수 있습니다.const record = #{
id: 1234,
symbol: Symbol(),
// Tuple 自体はプリミティブなので保持できる
tags: #["foo", "bar", "baz"],
};
// throws TypeError: cannot use an object as a value in a record
const record = #{
foo: {},
};
및 Record
속성의 키는 문자열뿐입니다.이것은 후술한 수치의 비교에 편리하도록 하기 위해서다.// throws TypeError: Record may only have string as keys
const record = #{
[Symbol()]: "foo",
};
그리고
Tuple
같은 홀은 허용되지 않는다.// SyntaxError: holes are disallowed by syntax
const tuple = #[1, 2, , 4];
어떻게든 상대를 갖고 싶은 경우.
숫자나 문자열 등을 사용하여 객체에 해당하는 테이블을 작성하여
Array
또는 Record
에서 객체 설정을 시뮬레이션할 수 있습니다.특히 어떤 처리 방법을 사용하면 편리해질 수 있다.하지만 이렇게 설치하면 GC에 따라 대상을 열 수 없는 문제가 있습니다.이 문제를 해결하기 위한 제안은 Stage 2 Symbols WeakMap keys입니다.
Tuple
의 키WeakMap
를 사용하면 Symbol
에 대한 인용이 사라지면 대응하는 대상도 CG로 회수할 수 있다.또 사용
Symbol
방법과 달리 대상을 보다 직접적으로 보유WeakMap
하는 방법을 도입하는 방안도 논의되고 있다.등가성
Box
연산자나 ===
를 사용하면 데이터가 같은지 아닌지를 판단할 수 있다.console.assert( #{ a: 1, b: #[1, 2] } === #{ a: 1, b: #[1, 2] } );
Object.is
,0
,-0
의 처리가 논의 중이다.console.assert( #{ a: -0 } === #{ a: +0 } );
console.assert( #[-0] === #[+0] );
console.assert( #{ a: NaN } === #{ a: NaN } );
console.assert( #[NaN] === #[NaN] );
console.assert( !Object.is(#{ a: -0 }, #{ a: +0 }) );
console.assert( !Object.is(#[-0], #[+0]) );
console.assert( Object.is(#{ a: NaN }, #{ a: NaN }) );
console.assert( Object.is(#[NaN], #[NaN]) );
NaN 연산자
typeof
를 연산자로 한 결과 증가typeof
,"record"
.console.log(typeof #{ a: 1 }); // => "record"
console.log(typeof #[1, 2]); // => "tuple"
JSON
일반적인 객체와 마찬가지로
"tuple"
JSON 문자열을 만들 수 있습니다.console.log(JSON.stringify(#{ a: #[1, 2, 3] })); // => '{"a":[1,2,3]}'
는 반대로 JSON 문자열JSON.stringify
이나 Record
를 만들 때Tuple
를 사용한다.console.log(JSON.parseImmutable('{"a":[1,2,3]}')); // => Record { a: Tuple [1, 2, 3] }
심층 구조를 가지고 있을 때의 상량
만약 심층 구조가 있다면, 전자 표로만 묘사하는 것은 매우 어렵다.이 문제를 해결한 사람은 임머입니다.
따라서
const record1 = #{
a: #{
b: #{
foo: 1,
bar: 2,
},
baz: 3,
},
};
const record2 = #{
...record1,
a: #{
...record1.a,
b: #{
...record1.a.b,
bar: 5,
},
},
};
확장JSON.parseImmutable
플랫폼의 제안은 Stage 1 Deep Path Properties in Record Literals입니다.const record1 = #{
a: #{
b: #{
foo: 1,
bar: 2,
},
baz: 3,
},
};
const record2 = #{
...record1,
a.b.bar: 5,
};
Tuple의 특징 방법
Record
는 원형에서 Tuple
와 같은 방법이 있지만 비파괴적이기 때문에 일부Array
와 다르다.Array
Tuple#pushed
의 끝에 원소를 하나 이상 추가하고 새 원소Tuple
를 되돌려줍니다.Tuple
처럼 요소수를 얻을 수 없다.const tuple1 = #[1, 2];
const tuple2 = tuple1.pushed(3, 4);
console.assert( tuple1 === #[1, 2] );
console.assert( tuple2 === #[1, 2, 3, 4] );
Array#push
Tuple#popped
끝에서 원소를 제거한 새 Tuple
를 되돌려줍니다.Tuple
와 같이 제거된 요소를 가져올 수 없습니다.const tuple1 = #[1, 2, 3];
const tuple2 = tuple1.popped();
console.assert( tuple1 === #[1, 2, 3] );
console.assert( tuple2 === #[1, 2] );
Array#pop
Tuple#unshifted
의 시작에 하나 이상의 요소를 추가하고 새 Tuple
를 되돌려줍니다.Tuple
처럼 요소수를 얻을 수 없다.const tuple1 = #[1, 2];
const tuple2 = tuple1.unshifted(3, 4);
console.assert( tuple1 === #[1, 2] );
console.assert( tuple2 === #[3, 4, 1, 2] );
Array#unshift
Tuple#shifted
부터 원소를 제거한 새 Tuple
를 되돌려줍니다.Tuple
와 같이 제거된 요소를 가져올 수 없습니다.const tuple1 = #[1, 2, 3];
const tuple2 = tuple1.shifted();
console.assert( tuple1 === #[1, 2, 3] );
console.assert( tuple2 === #[2, 3] );
Array#shift
지정한 색인 값을 업데이트한 새 값
Tuple#with
을 되돌려줍니다.인덱스에 음수 또는 Tuple
이상의 값을 입력한 경우Tuple#length
.const tuple1 = #[1, 2, 3];
const tuple2 = tuple1.with(1, 5);
console.assert( tuple1 === #[1, 2, 3] );
console.assert( tuple2 === #[1, 5, 3] );
RangeError
지정한 인덱스에서 임의의 원소를 삭제하고 원소를 추가한 새로운 원소
Tuple#spliced
를 되돌려줍니다.Tuple
와 같이 제거된 요소를 가져올 수 없습니다.const tuple1 = #[1, 2, 3, 4];
const tuple2 = tuple1.spliced(1, 2);
const tuple3 = tuple1.spliced(1, 2, 5, 6);
console.assert( tuple1 === #[1, 2, 3, 4] );
console.assert( tuple2 === #[1, 4] );
console.assert( tuple3 === #[1, 5, 6, 4] );
Array#splice
Tuple#sorted
를 정렬하고 새 Tuple
를 되돌려줍니다.매개 변수를 생략하면 Tuple
와 같이 문자열을 통해 비교합니다.const tuple1 = #[10, 20, 1, 2];
const tuple2 = tuple1.sorted();
const tuple3 = tuple1.sorted((a, b) => a - b);
console.assert( tuple1 === #[10, 20, 1, 2] );
console.assert( tuple2 === #[1, 10, 2, 20] );
console.assert( tuple3 === #[1, 2, 10, 20] );
Array
Tuple#reversed
의 원소가 반전된 새로운 원소Tuple
.const tuple1 = #[1, 2, 3];
const tuple2 = tuple1.reversed();
console.assert( tuple1 === #[1, 2, 3] );
console.assert( tuple2 === #[3, 2, 1] );
Tuple과 Arry에 대해서도 비파괴적인 방법이 있어요.
수락
TypedArray
한 방법Tuple
과 Array
에도 비파괴적인 방법을 추가하자는 제안은 Stage 2 Change Aray by Copy입니다.이 제안은 새로 작성된
TypedArray
과Array
로 원래TypedArray
의 영향을 받아야 하는데 그렇지 않다.상세한 상황은 이전에 쓴 보도를 보십시오.매듭을 짓다
이번에는 이블라토 데이터를 처리할 수 있는 새로운 원시재료
@@species
와 Record
를 소개했다.이 제안은 Stage 3 Temporal 과 마찬가지로 문서와 요리책을 제공하는 데 상당히 힘이 있다.
[2]
또 실제 테스트 코드의 플레이 그라운드도 준비했다.
특히 리액트 등에서는 컨디션 관리 편의를 위해 활용이 기대된다.ECMAScript를 추구하는 제안이 즐거우실 텐데 여러분도 괜찮으시면 잘 부탁드립니다.
각주
최적화는 규격에 포함되지 않고 특별한 제한도 없다.엔진을 설치하는 데 있어서 자유롭게 선택할 수 있다.
Temporal의↩︎,설명서(일본어)쿠크 서
Reference
이 문제에 관하여(무음판에서 데이터를 처리하는 라이브러리 및 Stage 2 Record &Tuple), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/petamoriken/articles/f07f48139d9ba1텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)