Análisis detallado y desarrollo de functores javascript

El análisis detallado y el desarrollo de functores.

Recientemente, estudié en el campo de entrenamiento bien pagado del front-end de la Universidad de Dragou. Aprendí muchos conocimientos que no conocía antes. He experimentado muchos conceptos de programación y métodos de aprendizaje de programación. Gracias al Sr. Cui Cui, la clase y el instructor

El siguiente es un resumen de mi estudio de los functores.

Quiere procesar la cadena, por ejemplo, todos se convierten en caracteres en mayúsculas y devuelven una nueva cadena

 let str = "la gou jiao yu"
 let UpperStr = str.toUpperCase()
 console.log(UpperStr)

Es muy simple. Se puede implementar fácilmente con el método toUpperCase , pero este método es manipular directamente str, para que podamos envolverlo en un contenedor, y operar este contenedor para realizar indirectamente la operación de los datos. Operemos el functor, deje que el funtor opere la cadena en sí, para lograr una manipulación indirecta de la cadena, de modo que podamos centrarnos en el método, independientemente de lo que sea

Entonces este contenedor es en realidad un functor

Functores básicos, que es el contenedor más primitivo

class Container {
    
    
  constructor (value) {
    
    
    this._value = value
  }
  map (fn) {
    
    
    return new Container(fn(this._value))
  }
}
let r = new Container(str).map( x => x.toUpperCase())
console.log(r)

De esta forma, podemos utilizar el functor para introducir la cadena de operación, lo que mejora enormemente la seguridad

A continuación, mejoremos este functor. Es inconveniente hacer algo nuevo cada vez que lo llamamos , así que usemos un método de para optimizar este functor.

Optimización básica del functor

class Container {
    
    
  static of (value) {
    
    
    return new Container(value)
  }
 // 这样一来在函子内部就可以完成 new 的操作 ,不用每一次都new一个新的函子对象出来
  constructor (value) {
    
    
    this._value = value
  }

  map (fn) {
    
    
    return Container.of(fn(this._value))
  }
}
let str = "la gou jiao yu"


let r = Container.of(str).map( x => x.toUpperCase())
console.log(r)

En este proceso, también puede realizar llamadas encadenadas para lograr un procesamiento continuo de cadenas

let r = Container.of(str)
.map( x => x.toUpperCase())
.map(x => x.slice(0,6))
.map(x => x.toLowerCase())
console.log(r)

Pero en muchos casos, la llamada a la función no es fácil, es muy probable que el valor pasado esté vacío

MayBe functors

Entonces tenemos que determinar si el valor pasado está vacío, para que sea posible tener el functor MayBe, lo que significa que este functor está tratando con posibles vacantes

// MayBe 函子
class MayBe {
    
    
  static of (value) {
    
    
    return new MayBe(value)
  }

  constructor (value) {
    
    
    this._value = value
  }

  map (fn) {
    
    
    return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value))
  }

  isNothing () {
    
    
    return this._value === null || this._value === undefined
  }
}

Comenzamos a optimizar en función de un functor y cambiamos el nombre a Maybe, que es el functor Maybe.

let r = MayBe.of(null)
.map( x => x.toUpperCase())
.map(x =>x.slice(0,6))
.map(x => x.toLowerCase())
console.log(r)
// 现在我们的函子拥有了处理空值的能力

Producción:
Inserte la descripción de la imagen aquí

cualquier functor

Pero en el proceso de llamada, queremos saber qué paso de la llamada tiene un problema, por lo que tenemos el functor Either

El significado de o en inglés es cualquiera de los dos, o ... o ..., o ... o ...

Entonces el functor consta de dos partes


class Left {
    
    
  static of (value) {
    
    
    return new Left(value)
  }

  constructor (value) {
    
    
    this._value = value
  }

  map (fn) {
    
    
    return this
  }
}

class Right {
    
    
  static of (value) {
    
    
    return new Right(value)
  }

  constructor (value) {
    
    
    this._value = value
  }

  map (fn) {
    
    
    return Right.of(fn(this._value))
  }
}

Más tarde, para una mejor comprensión, hice que pareciera más un functor

let Either = {
    
    Left ,Right} 
// 我把这两个方法存到了一个Either对象里
function parseJSON (str) {
    
    
  try {
    
    
    return Either.Left.of(JSON.parse(str))
  } catch (e) {
    
    
    return Either.Right.of({
    
     error: e.message })
  }
}
let r = parseJSON('{ "name": "zs" }')
          .map(x => x.name.toUpperCase())
console.log(r)

De esta manera, al llamar a diferentes métodos en el objeto Either, se logra el efecto de left o right

Functores IO

El funtor se ha desarrollado hasta este punto, dado que los datos pueden procesarse, ¿deberían los métodos y funciones poder procesarlos?

Entonces, hay functores de E / S, que se utilizan para manejar indirectamente acciones de función.

// IO 函子
const fp = require('lodash/fp')
// 引入函数式编程的库lodash
class IO {
    
    
  static of (value) {
    
    
    return new IO(function () {
    
    
      return value
    })
  }

  constructor (fn) {
    
    
    this._value = fn
  }

  map (fn) {
    
    
    return new IO(fp.flowRight(fn, this._value))
      //函数组合
  }
}

// 调用
let r = IO.of(process).map(p => p.execPath)
// console.log(r)
console.log(r._value())

Functores de mónada

Dado que es una llamada de función, hay alguna relación de anidamiento, por ejemplo, el siguiente código, existe el fenómeno de IO (IO (x)), el functor se llama en el functor, que no es conciso

// IO 函子的问题
const fs = require('fs')
const fp = require('lodash/fp')

class IO {
    
    
  static of (value) {
    
    
    return new IO(function () {
    
    
      return value
    })
  }

  constructor (fn) {
    
    
    this._value = fn
  }

  map (fn) {
    
    
    return new IO(fp.flowRight(fn, this._value))
  }
}

let readFile = function (filename) {
    
    
  return new IO(function () {
    
    
    return fs.readFileSync(filename, 'utf-8')
  })
}

let print = function (x) {
    
    
  return new IO(function () {
    
    
    console.log(x)
    return x
  })
}

let cat = fp.flowRight(print, readFile)
// IO(IO(x))
let r = cat('package.json')._value()._value()
console.log(r)

Para solucionar este problema se introdujo el functor Monad, que en inglés significa mónada y también significa entidad indivisible, por lo que se crean los functores Monad para resolver los functores IO anteriores y lograr un aplanamiento.

// IO Monad
const fs = require('fs')
const fp = require('lodash/fp')

class IO {
    
    
  static of (value) {
    
    
    return new IO(function () {
    
    
      return value
    })
  }

  constructor (fn) {
    
    
    this._value = fn
  }

  map (fn) {
    
    
    return new IO(fp.flowRight(fn, this._value))
  }

  join () {
    
    
    return this._value()
  }

  flatMap (fn) {
    
    
    return this.map(fn).join()
  }
}

let readFile = function (filename) {
    
    
  return new IO(function () {
    
    
    return fs.readFileSync(filename, 'utf-8')
  })
}

let print = function (x) {
    
    
  return new IO(function () {
    
    
    console.log(x)
    return x
  })
}

let r = readFile('package.json')
          // .map(x => x.toUpperCase())
          .map(fp.toUpper)
          .flatMap(print)
          .join()

console.log(r)

Después de resolver el problema del aplanamiento, para las funciones, uno de los problemas más importantes es el problema asincrónico, y luego se crea el functor Task para tratar el problema asincrónico.

// Task 处理异步任务
const fs = require('fs')
const {
    
     task } = require('folktale/concurrency/task')
const {
    
     split, find } = require('lodash/fp')

function readFile (filename) {
    
    
  return task(resolver => {
    
    
    fs.readFile(filename, 'utf-8', (err, data) => {
    
    
      if (err) resolver.reject(err)

      resolver.resolve(data)
    })
  })
}

readFile('package.json')
  .map(split('\n'))
  .map(find(x => x.includes('version')))
  .run()
  .listen({
    
    
    onRejected: err => {
    
    
      console.log(err)
    },
    onResolved: value => {
    
    
      console.log(value)
    }
  })

Hasta ahora, se introduce el functor. De hecho, la idea de functor es muy simple, es manipular datos y funciones indirectamente, por lo que se empaquetan en un contenedor, y luego este contenedor es el functor

Para satisfacer las diferentes necesidades, se derivan una variedad de funciones, por lo que a veces el enfoque del aprendizaje de la programación es descubrir qué problemas están en el fondo y cómo resolverlos. De hecho, todas las nuevas tecnologías se optimizan constantemente. Mejorar y resolver algunos problemas subyacentes.

ap(find(x => x.includes('version')))
  .run()
  .listen({
    
    
    onRejected: err => {
    
    
      console.log(err)
    },
    onResolved: value => {
    
    
      console.log(value)
    }
  })

Hasta ahora, se introduce el functor. De hecho, la idea de functor es muy simple, es manipular datos y funciones indirectamente, por lo que se empaquetan en un contenedor, y luego este contenedor es el functor

Para satisfacer las diferentes necesidades, se derivan una variedad de funciones, por lo que a veces el enfoque del aprendizaje de la programación es descubrir qué problemas están en el fondo y cómo resolverlos. De hecho, todas las nuevas tecnologías se optimizan constantemente. Mejorar y resolver algunos problemas subyacentes.

En segundo lugar, también vale la pena aprender la idea de operación indirecta. Este método no invadirá el objeto original y es muy seguro. En el principio del enlace de datos bidireccional de vue, Object.defineProperty se usa para monitorear y operar el objeto, pero después de la introducción del proxy, es muy seguro monitorear el objeto original monitoreando el objeto instanciado por el proxy Es una idea de programación muy importante no manipular directamente los datos originales.

Supongo que te gusta

Origin blog.csdn.net/qq_43377853/article/details/112312377
Recomendado
Clasificación