var user = { name: ' ', address: { city: '', street: '', house: '' } };
function setName(value, user) { user.name = value; return user; }
function setName(value, user) { return { name: value, address: { city: user.address.city, street: user.address.street, house: user.address.house } }; }
function setName(value, user) { return { name: value, address: user.address }; }
// function get(prop) { return function(item) { return item[prop]; }; } // function setMutable(prop) { return function(value, item) { item[prop] = value; return item; } } // function setImmutable(prop) { return function(value, item) { var props = properties(item), // copy = props.reduce(function(lst, next) { lst[next] = item[next]; return lst; }, {}); copy[prop] = value; // return copy; }; } // obj function properties(obj) { var key, lst = []; for (key in obj) { if (obj.hasOwnProperty(key)) { lst.push(key); } } return lst; }
setName = setMutable('name') // setName = setImmutable('name') // getName = get('name') //
function getUserCity(user) { return user.address.city; } function setUserCity(value, user) { user.address.city = value; return user; }
var getAddress = get('address'), getCity = get('city'), getUserCity = compose(getCity, getAddress), // compose ( ) . .. getUserCity = function(item) { return getCity(getAddress(item)); }, setCity = setMutable('city'), setUserCity = function (value, item) { setCity(value, getAddress(item)) return item; } var newUser = setUserCity(' city', user); getUserCity(newUser) == ' city' // true //PS function compose(func1, func2) { return function() { return func1(func2.apply(null, arguments)); }; }
var getAddress = get('address'), getCity = get('city'), getUserCity = compose(getCity, getAddress), setCity = setImmutable('city'), setUserCity = function (value, item) { setCity(value, getAddress(item)) return item; }; var newUser = setUserCity(' city', user); getUserCity(newUser) == ' city' // true
setUserCity
function. In it, we get a new value for the input for the city value
and the item
user, change the value of the city and ... return the original item
object. But this contradicts the definition of immutable data structures. When changing any part of it, we must create a new object.setUserCity
function turns our immutable object back into a mutable. To verify this, let's execute the following code: var newUser1 = setUserCity('city1', user), newUser2 = setUserCity('city2', user); newUser1 == newUser2 //true
item
, and return the new user var setAddress = setImmutable('address'), setUserCity = function (value, item) { var address = setCity(value, getAddress(item)); return setAddress(address, user); }, newUser1 = setUserCity('city1', user), newUser2 = setUserCity('city2', user); newUser1 == newUser2 //false
var lens = Lens(getter, setter) // .
function Lens(getter, setter) { return { get: getter, set: setter }; }
setUserCity
function. When diving from level A to level B, we need getters and setters A and B. But we just introduced a new abstraction Lens
. Why should not the composition of seters and heteras separately be replaced by the composition of their lenses?compose
lenses, which builds a composition of two lenses: function Lens(getter, setter) { return { compose: function (lens) { return Lens(get2, set2); function get2(item) { return lens.get(getter(item)); } function set2 (value, item) { var innerValue = lens.set(value, getter(item)); return setter(innerValue, item); } }, get: getter, set: setter }; }
var addressLens = Lens(getAddress, setAddress), // cityLens = Lens(getCity, setCity), // addressCityLens = addressLens.compose(cityLens); // addressCityLens.set(' city', user); // city user,
user.address.city
point. Adding a new lens as if plunges us to a lower level.modify
operation: function Lens(getter, setter) { return { modify: function (func, item) { var value = getter(item); return setter(func(value), item); }, compose: function (lens) { return Lens(get2, set2); function get2(item) { return lens.get(getter(item)); } function set2 (value, item) { var innerValue = lens.set(value, getter(item)); return setter(innerValue, item); } }, get: getter, set: setter }; }
function Lens(getter, setter) { // 1 , if (arguments.length == 1) { var property = arguments[0]; getter = get(property); setter = setImmutable(property); } return { modify: function (func, item) { var value = getter(item); return setter(func(value), item); }, compose: function (lens) { return Lens(get2, set2); function get2(item) { return lens.get(getter(item)); } function set2 (value, item) { var innerValue = lens.set(value, getter(item)); return setter(innerValue, item); } }, get: getter, set: setter }; }
Lens('address').compose(Lens('city')).set(' city', user);
lens('address.city').set(' city', user);
user.address.city
. Let's implement the lens
function function lens(cmd) { var lenses = cmd.split('.') .map(pass1(Lens)); return lenses.reduce(function(lst, next) { return lst.compose(next); }); } // , // , function pass1(func) { return function(x) { return func(x); }; }
pass1
function. The fact is that the map
transmits more than 1 parameter to callback, so if we write map(Lense)
, the version of Lense
accepts the heteroter and the seter as input will be used. Therefore, we wrap our pass1
function, which ensures that only the first parameter passed to it enters the Lense
.Source: https://habr.com/ru/post/230649/
All Articles