A defensive copy protects immutable data when it crosses into code that may mutate it. Deep-copy data before it leaves your safe zone and again when modified data returns. section 7.3 section 7.5
Apply the discipline at both boundaries:
- Copy as data leaves: make a deep copy, then pass the copy to untrusted code. section 7.5
- Copy as data enters: immediately deep-copy received data and use only the copy inside your code. section 7.5
- Use deep copies because nested structures must be duplicated from the top level to the bottom. section 7.13
- Prefer copy-on-write inside the safe zone when you control modifications; reserve defensive copying for exchanges with untrusted code. section 7.8
Protecting a shopping cart
Before calling a mutating promotion routine, create cart_copy = deepCopy(shopping_cart). After the routine returns, assign shopping_cart = deepCopy(cart_copy). A safe wrapper can hide both copies and expose a reliable interface. section 7.4 section 7.6
function add_item_to_cart(name, price) {
var item = make_cart_item(name, price);
shopping_cart = add_item(shopping_cart, item);
var total = calc_total(shopping_cart);
set_cart_total_dom(total);
update_shipping_icons(shopping_cart);
update_tax_dom(total);
shopping_cart =
black_friday_promotion_safe(shopping_cart);
}
function black_friday_promotion_safe(cart) {
var cart_copy = deepCopy(cart);
black_friday_promotion(cart_copy);
return deepCopy(cart_copy);
} #1
Inspect a compact JavaScript wrapper that copies data before calling mutating legacy code and copies the result before returning it. section 7.6
