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