去往js函数式编程(1)

  防止 vue 自带的动画 css 覆盖你的动画效果,或者影响效果。可以添加:css="false"来阻止默认的 class.
通常,在第一次页面加载时会显示项目列表,由于元素已经在视图中,所以我们的动画不会起作用。为了触发动画,我们需要使用另一个过渡属性 appear,在页面最初渲染时立即触发动画。

  常用的金额千位分隔,不再使用循环 3 位截取,可以直接使用 js 自带的 toLocaleString。x.toLocaleString('en-US')就会生成对应的 3 位分隔数字。转成中文汉字也有现成的办法:x.toLocaleString('zh-Hans-CN-u-nu-hanidec')。转成中文的十进制表示。

const testOdd = (x) => x % 2 === 1
const testUnderFifty = (x) => x < 50
const duplicate = (x) => x + x
const addThree = (x) => x + 3

const myArray = [22, 9, 60, 24, 11, 63]

const a0 = myArray
  .filter(testOdd)
  .map(duplicate)
  .filter(testUnderFifty)
  .map(addThree)

/*
[ 21, 25 ]
*/

  现在有一个数组,想要在其中的奇数,将其复制,筛选其中小于 50 的将其加 3.最后得出一个数组。

  这个过程中创建/丢弃了很多数组,如何优化这个问题呢?问题在于处理过程中将第一个转换应用于数组,然后将第二个转换应用于结果数组,接着第三个,以此类推。另一种解决方案是取输入数组的第一个元素,并按顺序应用所有转换操作。然后,取数组的第二个元素并对其应用所有的转换操作,再取第三个元素,依此类推。

const mapTR = (fn) => (reducer) => (accum, value) => reducer(accum, fn(value))

const filterTR = (fn) => (reducer) => (accum, value) =>
  fn(value) ? reducer(accum, value) : accum

const testOddR = filterTR(testOdd)
const testUnderFiftyR = filterTR(testUnderFifty)
const duplicateR = mapTR(duplicate)
const addThreeR = mapTR(addThree)

const addToArray = (a, v) => {
  a.push(v)
  return a
}

const a1 = myArray.reduce(
  testOddR(duplicateR(testUnderFiftyR(addThreeR(addToArray)))),
  []
)

/*
[ 21, 25 ]
*/

  可能你会有点懵,补充点基础的。

const once = (fn) => {
  let done = false
  return (...args) => {
    if (!done) {
      done = true
      fn(...args)
    }
  }
}

  我们来解释下这个函数的一些要点:once 函数接收一个函数 fn 作为参数。我们通过闭包利用了一种内部的,私有的 done 变量。每次将 once()应用于某个函数时,都会创建一个新的,独立的 done 变量,并且只能从返回的函数中访问。return(...args)=>行表示 once()将返回一个带有参数的函数。调用 fn 前,先将 done=true 赋值。在完成设置后,调用原始函数,我们使用展开运算符传递原始 fn()所具有的任何参数。

const once = (fn) => {
  let done = false
  return async (...args) => {
    if (!done) {
      done = true
      await fn(...args)
      done = false
    }
  }
}

const squeakOnce = once(async (a) => {
  await fakeApi(a)
})

squeakOnce(2000)
squeakOnce(2000)
squeakOnce(2000)

once(async (a) => {
  await fakeApi(a)
})(2000)
once(async (a) => {
  await fakeApi(a)
})(2000)
once(async (a) => {
  await fakeApi(a)
})(2000)

const squeak = async (a) => {
  console.log('hello')
  await fakeApi(a)
}

  请注意 once 代码中的 return ,因为有这个所以 squeakOnce 才会是绑定后的方法,不会触发多次,但是假如直接调用 once 方法的话,once 方法会每次创建一个新的 return 方法,以至于你触发几次执行几次。另外你绑定到 onclick 方法时也只能使用 squeakOnce(2000),

  柯里化这个名字来自于哈斯克尔.柯里。他发展了这个概念。有一种函数式编程语言以他的名字命名 haskell,他全名叫 haskell curry.

const altSum3 = (x) => (y) => (z) => x + y + z

// 调用改成 altSum(1)(2)(3) 6
// 如果你写成altSum(1,2,3)会返回什么。并不是一个数字。
// 这是如何工作的?将其分解成多个调用。

let fn1 = altSum3(1)
let fn2 = fn1(2)
let fn3 = fn2(3)

// 调用altSum3(1)的结果根据定义是一个函数,通过闭包,它等效于下面函数:
let fn1 = (y) => (z) => 1 + y + z
// 当你使用fn1(2)时,结果又是一个带有单个参数的函数,等效于下面函数:
let fn2 = (z) => 1 + 2 + z

  柯里化有一个重要的优点是它提供了灵活性。通过将函数柯里化,我们可以轻松的部分应用参数,创建出更具特定功能的心函数。这种技术在函数式编程中非常常见,因为它使我们能够以模块化和可复用的方式构建函数。

  一个不必要的错误。我们通常会犯一个常见的错误。你经常看到下面这样的代码:

fetch('some/url').then(function (data) {
  processResult(data)
})

function someFunction(someData) {
  return someOtherFunction(someData)
}
// 上面的代码可以直接用someOtherFunction来替换前面代码。
// 我们的例子中可以改成

fetch('some/url').then(processResult)

// 这段代码与我们之前看到的方法完全等效,它更快,避免了一个函数调用。
// 这种编程风格被称为无参风格或暗示风格。

  纯函数的行为与数学函数相同,并提供各种好处。如果一个函数满足下面两个条件,它就是纯函数。1:给定相同的参数,函数总是计算并返回相同的结果。在计算结果时,函数不会产生任何可观察的副作用。简单来说,纯函数不依赖于其作用域之外的任何东西,并且对于相同的输入参数始终返回相同的结果。

  在数学中,引用透明性是一种属性,它允许你用其值替换表达式而不改变你正在进行的操作的结果。所有算术表达式都具有引用透明性。22*9总是可以被替换为198.涉及i/o的表达式不具有透明性,因为他们的结果直到执行时才能知道。出于同样的原因,涉及日期和时间相关函数或随机数的表达式也不具有透明性。

posted @ 2023-05-29 09:42  艾路  阅读(7)  评论(0编辑  收藏  举报