현재 카피-온-라이트의 경우 내부 데이터를 수정하지 않았고, 정보를 리턴하고 있기 때문에 읽기에 해당하는 동작을 수행한다.
//before
function remove_item_by_name(cart, name) {
var idx = null;
for (var i = 0; i < cart.length; i++) {
idx = i;
}
if (idx !== null)
cart.splice(idx, 1);
}
// after
function remove_item_by_name(cart, name) {
var new_cart = cart.slice();
var idx = null;
for (var i = 0; i < new_cart.length; i++) {
if (new_cart[i].name === name)
idx = i;
}
if (idx !== null)
new_cart.splice(idx, 1);
return new_cart;
}
카피-온-라이트 모듈을 만들어두면 객체나 배열을 읽거나 쓰기에 편리하다.
//앞에 값 추가 -> .unshift(el)
var array = [1 ,2, 3, 4];
array.unshift(10)
console.log(array) // [ 10, 1, 2, 3, 4 ];
// 앞에 값 삭제 -> .shift()
var array = [1 ,2, 3, 4];
array.shift()
console.log(array) // [ 2, 3, 4 ];
연습문제 solve (p.120)
// before
var mailing_list = [];
function add_connect(email) {
mailing_list.push(email);
}
function submit_form_handler(event) {
var form = event.target;
var email = form.elements['email'].value;
add_connect(email);
}
// after
var mailing_list = [];
function add_connect(mail_list, email) {
const new_mail_list = mail_list.slice();
new_mail_list.push(email);
return new_mail_list;
}
function submit_form_handler(event) {
var form = event.target;
var email = form.elements['email'].value;
mailing_list = add_connect(mailing_list, email);
}
//before
var a = [1, 2, 3, 4]
var b = a.pop();
console.log(b);
console.log(a);
//after
// 1. 읽기 함수와 쓰기 함수로 분리하기
function first_element(array) {
return array[0];
}
function drop_first(array) {
const array_copy = array.slice();
array_copy.shift();
}
// 2. 값 두 개를 리턴하는 함수로 만들기
function shift(array) {
var array_copy = array.slice();
var first = array_copy.shift();
return {
first: first,
array: array_copy
}
}
// push 함수를 카피-온-라이트 버전으로 만들기
function push( array,elem) {
const array_copy = array.slice();
array_copy.push(elem);
return array_copy;
}
// before
// 위 push 함수를 사용해서 리팩토링
function add_contact(mailing_list, email) {
var list_copy = mailing_list.slice();
list_copy.push(email);
return list_copy;
}
// after
function add_contact(mailing_list, email) {
const pushed_mailing_list = push(mailing_list, email);
return pushed_mailing_list;
}
// 배열 항목 설정 함수를 카피-온-라이트 방식으로 제작
function arraySet(array, idx, value) {
const copy_array = array.slice();
copy_array[idx] = value;
return copy_array;
}
변경 가능한 데이터를 읽는 것 ⇒ 액션
변경 불가능한 데이터를 읽는 것 ⇒ 계산
⇒ 데이터 구조를 불변형으로 바꾸면 코드내 계산은 늘어나고 액션을 줄일 수 있다.
액션을 최소화 하기 위해 불변성 있는 데이터만 사용한다면 시간에 따라 변하는 값을 표현하기 힘들다. 그래서 전역변수에 새로운 값을 할당함으로서 시간에 따라 변하는 값을 표현할 수 있다.
불변 구조는 배열을 복사한다. 이는 메모리를 보다 많이 사용하고 느리다고 볼 수 있다. 하지만 언제든 최적화 가능하고, 언어별 가비지 콜랙터의 선응에 따라 더 개선된 속도로 사용할 수 있으며, 그리고 특정 함수형 프로그래밍 언어에서는 이를 빠르게 구현할 수 있는 구현체가 존재한다. 그리고 무엇보다 그렇게 많은 양을, 자주 복사하지 않는다.
// before
function setPrice(item, price){
item.price = price;
}
// after
function setPrice(item, price) {
const item_copy = Object.assign({}, item);
item_copy.price = new_price;
return item_copy;
}
// 객체에 값을 설정하는 함수를 카피-온-라이트로 만들기
function objectSet(object, key, value) {
const object_copy = Object.assign({}, object);
object_copy[key] = value;
return object_copy;
}
// objectSet 함수로 setPrice 고치기
// before
function setPrice(item, new_price) {
const item_copy = Object.assign({}, item);
item_copy.price = new_price;
return item_copy;
}
// after
function setPrice(item, new_price) {
return objectSet(item, 'price', new_price);
}
// 제품 개수 설정하는 함수(setQuantity) 만들기
function setQuantity(item, new_quantity){
objectSet(item, 'quantity', new_quantity);
}
// 객체의 delete연산을 카피-온-라이트로 만들기
function objectDelete(object, key) {
varr object_copy = Object.assign({}, object);
delete object_copy[key];
return object_copy;
}
중첩된 데이터의 경우 최상위 데이터를 복사하고, 쓰기를 하려고 하는 데이터를 한 번 더 복사한 후 덮어 쓰기 함으로서 중첩된 데이터의 읽기와 쓰기가 가능하다.