我是靠谱客的博主 感性奇迹,最近开发中收集的这篇文章主要介绍函数式编程与 JS 异步编程、手写 Promise> IO函子问题学习笔记函数式编程与面向对象编程的区别:什么是一等公民:就是可以作为变量,作为返回值,作为传入的参数的东西。函数就是一等公民高阶函数:闭包:纯函数的概念:什么是硬编码,为什么要尽量避免硬编码通过柯里化解决硬编码问题:函数组合:将多个函数组合形成新的函数 洋葱圈函数式编程不能提高程序性能,因为函数式编程存在大量闭包,闭包导致占用内存,还会影响性能。副作用会导致函数不纯,副作用无法避免。函子:回调函数:什么是回调地狱问题: 回调函数层,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

学习笔记

函数式编程与面向对象编程的区别:

  • 函数式编程将事物与事物之间的逻辑关系抽象成函数映射关系。
  • 函数可以独立存在,可以作为参数,作为返回值,作为变量。通过函数式编程避免了this的复杂作用域问题。
  • 而面向对象编程是将万物抽象为对象,事物之间的联系和属性都成为对象的属性值,所以逻辑关系需要依托对象的关系来访问或者实现。

什么是一等公民:就是可以作为变量,作为返回值,作为传入的参数的东西。函数就是一等公民

高阶函数:

高阶函数即:函数作为参数传入,函数作为返回值

闭包:

  • 闭包就是,在函数内部,返回了一个函数,同时这个函数引用了外部函数的变量。
  • 在与外部函数同作用域内访问这个函数,可以访问到里面的内部函数和这个函数的变量。
  • 一旦访问,由于内部函数对外部变量进行了引用,导致外部函数执行完被销毁后,外部函数的变量不会被立即销毁,而是被缓存起来。

纯函数的概念:

  • 相同的输入永远有相同的输出。lodash是一个js库,有许多纯函数。
    纯函数可缓存,【可缓存有什么好处呢,在什么场景下需要呢–可缓存的话,相同的输入浏览器不会重复执行,会直接查找缓存输出结果。这样可以提高性能】即变量无状态。
  • splice属于不纯的函数,不是因为它会改变原始数组,而是因为传入相同的参数无法得到相同的输出结果。谨记纯函数的概念-----相同的输入有相同的输出。
  • 纯函数可测试。因为相同的输入永远有相同的输出【对于测试的知识还不了解?】
  • 可以并行处理:纯函数是一个封闭空间,因为它的执行结果只依赖于参数的不同。所以纯函数不需要访问共享的内存数据,所以在多线程并行环境下可以任意运行纯函数都不会产生影响
  • 纯函数的副作用:如果函数依赖于外部的状态就无法保证相同的输入具有相同的输出。就会带来副作用。带来什么副作用—导致不纯,不纯就会存在一些问题呗,比如不缓存,比如并行时产生影响,比如不好测试,扩展性和可复用性降低。带来安全隐患和不确定性等。
let min = 18;
function checkage(min,age) {
//这个函数的输出结果依赖于min的值。min暴露在全局作用域,存在更改的风险,所以无法保证相同的输入具有相同的输出。
return age >= min;
}

什么是硬编码,为什么要尽量避免硬编码

function checkage(age) {
let min = 18;//在这里给了min一个固定值,这就是硬编码,硬编码限制了代码的灵活性
return age >= 18;
}

通过柯里化解决硬编码问题:

  • 什么是柯里化—当一个函数有多个参数时,先传递一部分参数调用【这部分参数将作为一个固定不变的量】,然后返回一个新的函数来接收剩余的参数,新函数返回结果。

  • 个人感觉有些类似于闭包。闭包的作用主要是对外部变量的引用和缓存。柯里化主要是解决硬编码问题,解决纯函数不纯的问题

  • 柯里化概念的代码理解:

function kelihua = fixparam => (otherparam => otherparam + fixparam + '')
function kelihua(fixparam) {
return function(otherparam) {
return otherparam + fixparam + ''
}
}
  • 柯里化总结:
    给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数
    柯里化会对函数参数进行缓存[因为闭包]
    柯里化可以让函数变得更灵活[因为传入的函数可以开发者自定义]
    柯里化可以将多元函数最终转换成一元函数.

  • 柯里化demo:

  • 判断字符串中是否包含空白字符/数字:


[String.match(正则表达式)
匹配一个正则表达式,返回符合要求的字符]
const _ = require('lodash')//引入lodash的curry方法[柯里方法,支持传入一个或者多个参数,返回
等待接收剩余参数的函数]
function mymatch(str,reg) {
return str.match(reg)
}
const match = _.curry(mymatch);//给mymatch函数进行柯里化
const havaSpace = match(/s+/g);
const haveNumber = match(/d+/g);
console.log(haveSpace('haha haha'));//[' ']
console.log(haveSpace('hahahaha'));//null
console.log(haveNumber('123haha'));//['123']
console.log(haveNumber('hhh'));//null
  • 判断数组中的元素是否有包含空白字符/数字:

const _ = require('lodash')
const filter = _.curry((array,func) => {
array.filter(func)
})
const filterspace = filter(haveSpace);
const filternumber = filter(haveNumber);
filterspace(['hello world','aaa']);//['hello world']
filternumber(['aaa','sfv','sw22']);//['sw22']
  • 柯里化原理的模拟实现:
    • [柯里化:接收一个函数func作为参数,返回一个新函数newfunc.根据传入的参数的个数是否是接收的函数的参数func的个数,来判断直接返回func还是返回等待接收剩余参数的newfunc]
    • function curry(func) {//这个函数实现的难点:关于args/arguments/…展开符 不太了解????
       let paramlength = 0;
      return function aa(...args) {//闭包,会缓存参数
      paramlength = args.length;//实参的数量
      if(paramlength < func.length) {//func.length表示传入的函数实际需要的参数数量
      
      let param = args.concat(Array.from(arguments));
      return aa(...param);//...表示将数组展开成一个个的元素
      
      }
      else {
      return func(...args);//将所有参数展开为数组作为参数
      }
      }
      
    
    

函数组合:将多个函数组合形成新的函数 洋葱圈

  • compose(fn1,fn2) lodash中的组合函数:flow() flowRight()都可以组合不止两个/多个函数
  • 了解reduce():
    将函数作为参数传入,遍历执行数组中每个元素并将函数的回调再次传入函数 最终得到结果 一般用来求和或者求积
    arr.reduce( (pre,cur,index) => pre+cur,0);//0作为回调的初始值传入 pre表示上一次回调返回的值,初始为0,cur表示当前被处理的元素。 index参数不是必需的
  • 关于compose组合函数的理解:❓
function compose(...args) {
return function(value) {
return args.reverse().reduce(function(data,fn) {
return fn(data)
},value)
}
}
const compose = (...args) => vlaue => args.reverse().reduce( (data,fn) => fn(data) , value)

函数式编程不能提高程序性能,因为函数式编程存在大量闭包,闭包导致占用内存,还会影响性能。

函数式编程中的函数指的是数学中的函数,不是程序中的函数或方法

副作用会导致函数不纯,副作用无法避免。

但是纯函数是没有副作用的,相同的输入具有相同的输出,满足这两个条件的函数才是纯函数。

函子:

  • 什么是函子?作用是什么?使用场景经常有哪些?发散知识关联知识有哪些?
  • 函子是包含值和值的变形关系的容器。通过函子可以用来控制副作用。函子始终不会把值对外公布
  • 函子是一个对象,可以理解为开发者可以传入需要处理的值以及需要处理的操作给函子,函子会在内部存储值并处理数据。返回一个新的函子对象。
    hanzi(data)
    .map(fn1)
    .map(fn2)//返回的是一个函子对象,每个函子都有map方法
class Hanzi() {
static of(val) {
retun new Hanzi(val)
}
constructor(val) {
this._val = val;
}
map(fn) {
return new Hanzi(fn(this._val))
}
}
  • IO函子,处理不纯的函数。将异步操作存储起来
  • 除了lodash库,还有folktale库
  • task函子:类似promise,处理异步任务
  • pointed函子:实现了of静态方法的函子
    of是为了避免使用new来创建对象
  • Monad函子

回调函数:

  • 由调用者定义,交给执行者去执行的函数,称为回调函数。由调用者告诉执行者异步任务结束后应该做什么。
  • 比如ajax请求,请求接口后,不知道何时能响应请求,所以就将请求成功和请求失败时应该执行的函数先定义好,当请求完成时队列会自动去执行。
  • demo:

function foo(callback) {
setTimeout( () => {
callback();//callback就是一个回调函数。
},1000)
}
foo( () => {
<!-- foo中作为参数传入的这个函数就是一个回调函数。用来取代callback() -->
})
  • 回调函数是 JavaScript 中异步模式的根基,
  • JavaScript 是单线程模式执行的机制,正常情况下执行同步机制,但是同步机制会存在队列阻塞等问题。所以需要异步模式。
  • 单线程机制如何实现异步呢,就用到了回调函数。当存在异步操作时,对异步操作结束后应该执行什么内容调用者是知道的,只是调用者并不知道异步操作何时会结束。
  • 所以回调就是—调用者将异步结束后该做什么任务先定义成函数交给队列,队列会清楚异步操作何时结束,异步结束后会自动去执行相应的结果处理函数【即回调】
  • JavaScript 的异步操作常见的有计时器,事件绑定,ajax请求
  • 回调函数,事件监听,[发布/订阅?],Promise 对象都可以实现 JavaScript 异步编程。

什么是回调地狱问题: 回调函数层层嵌套

webpack-dev-server使用 ?

async await

async是Generator的语法糖

Promise:用来解决回调地狱问题。Promise实际上就是一个对象。

用来告知外界异步任务结束时是成功还是失败。成功或者失败时都会执行相对应的任务。

  • Promise对象的then方法会返回一个全新的Promise对象。
  • 后面的then方法就是在为上一个then返回的Promise注册回调
  • Promise链接调用中,上一个then方法中回调函数的返回值会作为后一个then方法回调的参数
  • Promise链式调用:最大程度的避免嵌套–回调地狱问题,提供更加扁平的用户编程体验
  • 当Promise失败或者主动抛出异常时都会执行catch,失败时回调。
  • Promise静态方法:?
  • Promise.all()。Promise并行执行[比如同步执行多个请求]:将多个路径整合成数组,一并去请求,只有当所有请求成功时才会执行成功时回调,只要其中一个请求不成功,就会执行失败时回调。等待所有任务结束
  • Promise.race():将多个promise对象组合成一个全新的promise对象,只会等待第一个结束的任务。可以用来进行请求超时控制。
  • Promise执行时序/宏任务 VS 微任务
    回调队列当中的任务称之为宏任务,宏任务执行过程中如果临时增加了额外需求,在宏任务执行完成后,会立即执行,而不用进入队列中重新排队,这就是微任务[提交程序整体的响应能力]。而Promise的回调是作为微任务去执行。而setTimeout是以宏任务的形式进入到队列。所以即使延迟实际是0ms,也需要等待执行。
  • .then( ) 里面的实参应该是函数. 如果不是函数, 就无视它
    Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log) console.log作为函数,接收一个形参即1 结果输出1
  • Promise有三个状态:Pending/Fulfilled/Rejected。一旦状态确定,就不可更改
  • resolve参数的作用是将promise状态更改为成功
  • promise在任务队列中属于微任务
  • promise中不管有没有异步函数,执行机制都是异步的

new 做了哪些操作?


1、创建一个空对象
2、将构造函数的prototype属性赋值给新对象的__proto__属性
3、将构造函数的this(执行上下文)指向新对象
4、执行构造函数的代码
5、将新对象返回

最后

以上就是感性奇迹为你收集整理的函数式编程与 JS 异步编程、手写 Promise> IO函子问题学习笔记函数式编程与面向对象编程的区别:什么是一等公民:就是可以作为变量,作为返回值,作为传入的参数的东西。函数就是一等公民高阶函数:闭包:纯函数的概念:什么是硬编码,为什么要尽量避免硬编码通过柯里化解决硬编码问题:函数组合:将多个函数组合形成新的函数 洋葱圈函数式编程不能提高程序性能,因为函数式编程存在大量闭包,闭包导致占用内存,还会影响性能。副作用会导致函数不纯,副作用无法避免。函子:回调函数:什么是回调地狱问题: 回调函数层的全部内容,希望文章能够帮你解决函数式编程与 JS 异步编程、手写 Promise> IO函子问题学习笔记函数式编程与面向对象编程的区别:什么是一等公民:就是可以作为变量,作为返回值,作为传入的参数的东西。函数就是一等公民高阶函数:闭包:纯函数的概念:什么是硬编码,为什么要尽量避免硬编码通过柯里化解决硬编码问题:函数组合:将多个函数组合形成新的函数 洋葱圈函数式编程不能提高程序性能,因为函数式编程存在大量闭包,闭包导致占用内存,还会影响性能。副作用会导致函数不纯,副作用无法避免。函子:回调函数:什么是回调地狱问题: 回调函数层所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(72)

评论列表共有 0 条评论

立即
投稿
返回
顶部