
Proxy objects in JavaScript. const wrap = obj => { return new Proxy(obj, {   get(target, propKey) {       console.log(`Reading property "${propKey}"`)       return target[propKey]   } }) } const object = { message: 'hello world' } const wrapped = wrap(object) console.log(wrapped.message)  Reading property "message" hello world set handler.Proxy objects allow you to intercept calls to methods that do not exist in proxied objects. When calling the method of a proxied object, the get handler is called, after which a dynamically generated function can be returned. However, this object, if it is not necessary, does not need to be changed.api.getUsers() , can create a GET/users path in the API. This approach can be developed further. For example, a command like api.postItems({ name: 'Item name' }) can invoke POST /items using the first parameter of the method as a request body. const { METHODS } = require('http') const api = new Proxy({}, {   get(target, propKey) {     const method = METHODS.find(method =>       propKey.startsWith(method.toLowerCase()))     if (!method) return     const path =       '/' +       propKey         .substring(method.length)         .replace(/([az])([AZ])/g, '$1/$2')         .replace(/\$/g, '/$/')         .toLowerCase()     return (...args) => {       const finalPath = path.replace(/\$/g, () => args.shift())       const queryOrBody = args.shift() || {}       //    fetch       // return fetch(finalPath, { method, body: queryOrBody })       console.log(method, finalPath, queryOrBody)     }   } } ) // GET / api.get() // GET /users api.getUsers() // GET /users/1234/likes api.getUsers$Likes('1234') // GET /users/1234/likes?page=2 api.getUsers$Likes('1234', { page: 2 }) // POST /items    api.postItems({ name: 'Item name' }) // api.foobar    api.foobar() {} , while all methods are implemented dynamically. Proxy does not need to be used with objects containing the necessary functionality or its parts. The $ icon is used as a wildcard for parameters. arr.findWhereNameEquals('Lily') arr.findWhereSkillsIncludes('javascript') arr.findWhereSkillsIsEmpty() arr.findWhereAgeIsGreaterThan(40)  const camelcase = require('camelcase') const prefix = 'findWhere' const assertions = { Equals: (object, value) => object === value, IsNull: (object, value) => object === null, IsUndefined: (object, value) => object === undefined, IsEmpty: (object, value) => object.length === 0, Includes: (object, value) => object.includes(value), IsLowerThan: (object, value) => object === value, IsGreaterThan: (object, value) => object === value } const assertionNames = Object.keys(assertions) const wrap = arr => { return new Proxy(arr, {   get(target, propKey) {     if (propKey in target) return target[propKey]     const assertionName = assertionNames.find(assertion =>       propKey.endsWith(assertion))     if (propKey.startsWith(prefix)) {       const field = camelcase(         propKey.substring(prefix.length,           propKey.length - assertionName.length)       )       const assertion = assertions[assertionName]       return value => {         return target.find(item => assertion(item[field], value))       }     }   } }) } const arr = wrap([ { name: 'John', age: 23, skills: ['mongodb'] }, { name: 'Lily', age: 21, skills: ['redis'] }, { name: 'Iris', age: 43, skills: ['python', 'javascript'] } ]) console.log(arr.findWhereNameEquals('Lily')) //  Lily console.log(arr.findWhereSkillsIncludes('javascript')) //  Iris  const id = await db.insertUserReturningId(userInfo) //   INSERT INTO user ... RETURNING id 
service object that implements some asynchronous functionality, and the monitor function, which accepts objects, wraps them into proxy objects and organizes monitoring of asynchronous methods of proxied objects. Here is how, at a high level, the work of these mechanisms looks like: const service = { callService() {   return new Promise(resolve =>     setTimeout(resolve, Math.random() * 50 + 50)) } } const monitoredService = monitor(service) monitoredService.callService() //  ,      const logUpdate = require('log-update') const asciichart = require('asciichart') const chalk = require('chalk') const Measured = require('measured') const timer = new Measured.Timer() const history = new Array(120) history.fill(0) const monitor = obj => { return new Proxy(obj, {   get(target, propKey) {     const origMethod = target[propKey]     if (!origMethod) return     return (...args) => {       const stopwatch = timer.start()       const result = origMethod.apply(this, args)       return result.then(out => {         const n = stopwatch.end()         history.shift()         history.push(n)         return out       })     }   } }) } const service = { callService() {   return new Promise(resolve =>     setTimeout(resolve, Math.random() * 50 + 50)) } } const monitoredService = monitor(service) setInterval(() => { monitoredService.callService()   .then(() => {     const fields = ['min', 'max', 'sum', 'variance',       'mean', 'count', 'median']     const histogram = timer.toJSON().histogram     const lines = [       '',       ...fields.map(field =>         chalk.cyan(field) + ': ' +         (histogram[field] || 0).toFixed(2))     ]     logUpdate(asciichart.plot(history, { height: 10 })       + lines.join('\n'))   })   .catch(err => console.error(err)) }, 100) 
Source: https://habr.com/ru/post/347754/
All Articles