JavaScript进阶6之函数式编程与ES6ESNext规范

函数式编程

  • 柯里化curry
    • curry
    • compose
      • 示例:
        • 简化版
        • 展开写:
    • debug
      • 示例一:
      • 示例二:
  • 模板字符串
    • css in js方案
  • 箭头函数
    • 问题
  • 生成器 generator
    • 应用场景
  • 反射 Reflect

柯里化curry

compose是curry的应用
在 lodash/fp
underscore
ramba

curry

function curry(fn){
    // 统计传入函数的参数个数
    const len=fn.length
    // 函数命名为的后面重复调用
    return function curried(...args){
        // 当传入的参数个数大于等于函数需要的参数个数的时候,则执行函数
        if(args.length>=len){
            return fn.apply(this,args)
        }else{
            // 否则返回函数并且接收后面传入的参数
            return function(...args2){
                // 执行回调curried函数,将参数合并传入下一次回调中
                return curried.apply(this,args.concat(args2))
            }
        }
    }
}

compose

两个函数组合:

function compose(f,g){
    return function(x){
        return f(g(x))
    }
}

不确定个数函数组合:

// 传入多个函数
function compose(...fns){
    // 当个数
    if(fns.length===0){
        // console.log("-----等于0----");
        // compose不传参数的时候,返回的是一个函数,这个函数传的参数都返回
        return (args)=>args
    }
    if(fns.length===1){
        // console.log("----等于1-----");
        // compose传入一个参数的话,就返回这个函数
        return fns[0]
    }
    // compose传入两个及两个以上函数的时候,使用reduce将作为参数的函数从右往左执行
    return fns.reduce((pre,cur)=>(...args)=>pre(cur(...args)))
}

示例:

简化版
var compose=(f,g)=>(x)=>f(g(x))
const curry=require('lodash').curry

var toUpperCase=curry(function(str){
    return str.toUpperCase()
})

var head=curry(function(x){
    return x[0]
})
var initials=function(name){
    return name.split(' ').map(compose(toUpperCase,head)).join('. ')
}
console.log(initials('hunter stockton thompson'))

在这里插入图片描述

展开写:
function curry(fn){
    // 统计传入函数的参数个数
    const len=fn.length
    // 函数命名为的后面重复调用
    return function curried(...args){
        // 当传入的参数个数大于等于函数需要的参数个数的时候,则执行函数
        if(args.length>=len){
            return fn.apply(this,args)
        }else{
            // 否则返回函数并且接收后面传入的参数
            return function(...args2){
                // 执行回调curried函数,将参数合并传入下一次回调中
                return curried.apply(this,args.concat(args2))
            }
        }
    }
}
// 传入多个函数
function compose(...fns){
    // 当个数
    if(fns.length===0){
        // console.log("-----等于0----");
        // compose不传参数的时候,返回的是一个函数,这个函数传的参数都返回
        return (args)=>args
    }
    if(fns.length===1){
        // console.log("----等于1-----");
        // compose传入一个参数的话,就返回这个函数
        return fns[0]
    }
    // compose传入两个及两个以上函数的时候,使用reduce将作为参数的函数从右往左执行
    return fns.reduce((pre,cur)=>(...args)=>pre(cur(...args)))
}

var head=curry(function(x){
    return x[0]
})
var split=curry(function(rules,str){
    return str.split(rules)
})
var toUpperCase=curry(function(str){
    return str.toUpperCase()
})
var map=curry(function(f,arr){
    return arr.map(f)
})
var join=curry(function(f,arr){
    return arr.join(f)
})
var initials=compose(join('. '),map(compose(toUpperCase,head)),split(' '))


console.log(initials('hunter stockton thompson'))

在这里插入图片描述

debug

示例一:

const curry=require('lodash').curry

var reverse=curry(function(arr){
    return arr.reverse()
})
var map=curry(function(f,arr){
    return arr.map(f)
})
var angry=curry(function(str){
    return str.toUpperCase()+"!"
})

const compose=function(...fns){
    if(fns.length===0) return (args)=>args
    if(fns.length===1) return fns[0]

    return fns.reduce((pre,cur)=>(...args)=>pre(cur(...args)))
}

// var latin=compose(map,angry,reverse)  //错误执行,angry接收的是一个字符串,
     // 但是reverse执行完后的结果是数组,传给angry会报错,所以应该把angry当做参数传给map用作map的规则才对
var latin=compose(map(angry),reverse)
console.log(latin(['frog','eyes']))

在这里插入图片描述

示例二:

const curry=require('lodash').curry

function compose(...fns){
    if(fns.length===0) return (args)=>args
    if(fns.length===1) return fns[0]
    return fns.reduce((pre,cur)=>(...args)=>pre(cur(...args)))
}

var replace=curry(function(what,replacement,str){
    return str.replace(what,replacement)
})

var split=curry(function(f,str){
    return str.split(f)
})

var toLower=curry(function(x){
    return x.toLowerCase()
})
var join=curry(function(f,arr){
    return arr.join(f)
})
var map=curry(function(f,arr){
    return arr.map(f)
})

// var dasherize=compose(join('-',toLower,split(' '),replace(/\s{2,}/ig, ' ')))  
// 报错,由于toLower接收的是字符串而不是数组,所以应该先用map调用一下他
var dasherize=compose(join('-'),map(toLower),split(' '),replace(/\s{2,}/ig, ' '))

console.log(dasherize('The world is a vampire'));

在这里插入图片描述

模板字符串

css in js方案

题外话:
建议大家往react方向学,react技术点很多,选择很多
比如:
样式体系:

  • less,scss,其实目前看有点过时了

现在主流的样式体系方案:

  1. module css,中规中矩的
  2. css in js,运行时的开销,性能稍差
  3. tailwind css,极致性能

如果要做 SSR 服务端渲染,
一方面,css in js 相对不好处理,但是有对应的方案, 而且比较符合正常开发者定义组件,维护对应的内容
另一方面,官方推荐的是 module css,tailwind css

// 用在 css in js 的方案里

const styled = {
  div: function (strings) {
    const divDom = document.createElement("div");  //nodejs不能执行
    strings.forEach((str) => {
      const s = str.split(";");
      for (const kv of s) {
        const [key, value] = kv.split(":");
        divDom.style[key] = value;    //nodejs不能执行
        console.log("🚀 ~ styled.key:", key, value);
      }
    });

    // return react component    //React中返回
    return divDom;
  },
  h1: function (...args) {
    console.log("🚀 ~ styled.args:", args);
  },
};
const Div = styled.div`
  color: red;
  font-size: 20px;
`;

如果要了解某个代码在编译器中处理完后得到什么内容的话,可以使用babel去看
链接: link
看具体原理,内部具体是怎么做的

在这里插入图片描述

箭头函数

问题

  1. 不能定义构造器,不能new
  2. this指向的是外部的作用域
  3. 没有arguments
  4. this不能绑定(apply,bind,call)
    在这里插入图片描述

生成器 generator

应用场景

大家对于异步的处理是不是都基于 async、await来做的?

// async await的实现,就是借助 promise + generator
const getData = async ()=>{
  const res=Promise.resolve(1)
  return res
}

async function test(){
	await getData()
}

在这里插入图片描述

反射 Reflect

Reflect.set(target, key, value, receiver);
重点看看 receiver,接收者决定this指向

// 用来劫持对象的逻辑

const handler = {
  get(target, key, receiver) {
    console.log("get", key, receiver);
    // 值的获取,是不是就是我们所谓的依赖收集
    // track()
    // return target[key];
    return Reflect.get(target, key);
  },
  set(target, key, value, receiver) {
    console.log("set", value);

    // target[key] = value;
    Reflect.set(target, key, value, receiver);

    // 值的设置就是我们所谓的更新操作
    // trigger()
  },
};

// Vue3.0的响应式原理

const target = {
  a: 1,
  get b() {
    return this.a;
  },
};

// 劫持这个 target 对象的熟悉
const reactiveTarget = new Proxy(target, handler);
console.log("reactiveTarget:", reactiveTarget.a, reactiveTarget.b);

reactiveTarget.a = 10;

console.log("reactiveTarget:", reactiveTarget.a, reactiveTarget.b);

console.log(Reflect.get(target, "a"));
console.log(Reflect.get(target, "b", { b: "null111", a: "null222" }));

在这里插入图片描述
在这里插入图片描述

o?.a是什么意思
在JavaScript中,o?.a是一种新的语法,称为可选链操作符(Optional Chaining Operator)。这个操作符用于在访问对象属性时进行安全的操作,即使对象的某个属性不存在或者为null或undefined,也不会导致运行时错误。
具体来说,o?.a表示如果对象o存在且具有属性a,则返回o.a的值;如果对象o不存在或者属性a不存在,则返回undefined,而不会抛出错误。
这种语法的引入使得代码更加简洁并且更安全,特别是在处理深层嵌套的对象属性时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/532958.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RTSP/Onvif视频安防监控平台EasyNVR调用接口返回匿名用户名和密码的原因排查

视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入,并能对接入的视频流进行处理与多端分发,包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。平台拓展性强、支持二次开发与集成,可应用在景区、校园、水利、社区、工地等场…

怎么快速围绕“人、货、场”做零售数据分析?

做零售数据分析多了,不难发现零售数据分析的关键就是“人、货、场”,那么怎么又快又灵活地分析这三个关键点?不妨参考下奥威BI零售数据分析方案。 奥威BI零售数据分析方案是一套吸取大量项目经验,结合零售企业数据分析共性需求打…

【教学类-50-06】20240410“数一数”4类星号图片制作PDF学具

作品展示: 背景需求: 前文遍历四个文件夹,分别将每个文件夹内的10个图片的左上角加入星号,显示难度系数 【教学类-50-05】20240410“数一数”4类图片添加“难度星号”-CSDN博客文章浏览阅读55次,点赞2次,…

xss跨站脚本攻击笔记

1 XSS跨站脚本攻击 1.1 xss跨站脚本攻击介绍 跨站脚本攻击英文全称为(Cross site Script)缩写为CSS,但是为了和层叠样式表(CascadingStyle Sheet)CSS区分开来,所以在安全领域跨站脚本攻击叫做XSS 1.2 xss跨战脚本攻击分类 第一种类型:反射型XSS 反射…

Prime (2021): 2

前言 这个靶机有亿点难,收获很多。打靶的时候,前面很顺,到创建ssh公钥之后就一点不会了。 1 01 arp扫描,发现有一个130,再查看端口 有22,80,129,445,10123 dirb扫描目录 这…

LinuxAndroid: 旋转编码器input输入事件适配(旋转输入)

rk3588s: 旋转编码器input输入事件适配 基于Android 12 kernel-5.10版本 参考文档: https://blog.csdn.net/szembed/article/details/131551950 Linux 输入设备调试详解(零基础开发)Rotary_Encoder旋转编码器驱动 通用GPIO为例 挂载input输…

废品回收 小程序+APP

用户实名认证、回收员实名认证、后台审核、会员管理、回收员管理、订单管理、提现管理、地图、档案管理。 支持,安卓APP、苹果APP、小程序 流程: 一、用户端下单,地图选择上门位置、填写具体位置、废品名称、预估重量、选择是企业废旧、家…

Netty实现udp服务器

1、TCP与UDP通信协议 网络传输层协议有两种,一种是TCP,另外一种是UDP。 TCP是一种面向连接的协议,提供可靠的数据传输。TCP通过三次握手建立连接,并通过确认和重传机制,保证数据的完整性和可靠性。TCP适用于对数据准…

科技助力输电线安全隐患预警,基于YOLOv5全系列参数【n/s/m/l/x】模型开发构建电力设备场景下输电线安全隐患目标检测预警系统

电力的普及让我们的生活变得更加便利,四通八达的电网连接着生活的方方面面,电力能源主要是依托于庞大复杂的电网电力设备进行传输的,有效地保障电网场景下输电线的安全对于保障我们日常生活所需要的电力有着重要的意义,但是电力设…

Java使用aspose-words实现word文档转pdf

Java使用aspose-words实现word文档转pdf 1.获取转换jar文件并安装到本地maven仓库 aspose-words-15.8.0-jdk16.jar包下载地址:https://zhouquanquan.lanzn.com/b00g257yja 密码:965f 下载aspose-words-15.8.0-jdk16.jar包后,通过maven命令手动安装到本…

HWOD:走方格的方案数

一、自己的解题思路 1、(0,m)和(n,0) (0,m)表示处在棋盘的左边线,此刻能回到原点的路线只有一个,就是一路向上 (n,0)表示处在棋盘的上边线,此刻能回到原点的路线只有一个,就是一路向左 2、(1,1) (1,1)表示只有一个方格&#…

【截至2023年底】语言模型的发展

什么是大语言模型LLM?ChatGPT、LLAMA各自有什么优势? from: https://www.youtube.com/watch?vt6qBKPubEEo github: https://github.com/Mooler0410/LLMsPracticalGuide 来自这篇survey,但据说还在更新,到…

嵌入式ARM版本银河麒麟操作系统V10SP1安装OPenGauss数据库

前言: 官网提供了非常完整的openGauss安装步骤。 https://opengauss.org/zh/download/archive/列举一下个人的使用环境: 麒麟V10 rk3588工控板(ARM) openGauss-3.0.5(极简版)浏览一下官网,可以…

dnspy逆向和de4dot脱壳

拿到一个软件,使用dnspy查看,发现反汇编后关键部分的函数名和代码有很多乱码: 这样的函数非常多,要想进一步调试和逆向,就只能在dnspy中看反汇编代码了,而无法看到c#代码,当时的整个逆向过程只剩…

【Linux的进程篇章 - 进程程序替换】

Linux学习笔记---009 Linux之进程程序替换理解1、进程程序替换1.1、先看代码和现象1.2、替换的原理1.3、回顾fork函数的应用 2、使用所有的替换方法,并且认识函数参数的含义2.1、exec*函数族2.2、exec替换自定义的程序 3、进程的替换的execve系统调用函数 Linux之进…

MAC: 自己制作https的ssl证书(自己签发免费ssl证书)(OPENSSL生成SSL自签证书)

MAC: 自己制作https的ssl证书(自己签发免费ssl证书)(OPENSSL生成SSL自签证书) 前言 现在https大行其道, ssl又是必不可少的环节. 今天就教大家用开源工具openssl自己生成ssl证书的文件和私钥 环境 MAC电脑 openssl工具自行搜索安装 正文 1、终端执行命令 //生成rsa私钥&…

蓝桥杯-单片机基础16——利用定时计数中断进行动态数码管的多窗口显示

综合查阅了网络上目前能找到的所有关于此技能的代码,最终找到了下述方式比较可靠,且可以自定义任意显示的数值。 传统采用延时函数的方式实现动态数码管扫描,在题目变复杂时效果总是会不佳,因此在省赛中有必要尝试采用定时计数器中…

Vue2(十五):replace属性、编程式路由导航、缓存路由组件、路由组件独有钩子、路由守卫、history与hash

一、router-link的replace属性 1、作用:控制路由跳转时操作浏览器历史记录的模式 2、浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push 3、如何开启repla…

数据仓库发展历史与架构演进

从1990年代Bill Inmon提出数据仓库概念后经过四十多的发展,经历了早期的PC时代、互联网时代、移动互联网时代再到当前的云计算时代,但是数据仓库的构建目标基本没有变化,都是为了支持企业或者用户的决策分析,包括运营报表、企业营…

数据结构DAY5--二叉树的概念

树: 概念: 由n个节点组成的有限集,有一个根节点;其他节点只有一个前驱节点,但可以有多个后继节点。(一对多) 叶子节点(终端结点):只有前驱结点没有后继结点 非叶子节点&#xff0…