JavaScript进阶6之函数式编程与ES6&ESNext规范

函数式编程

柯里化curry

compose是curry的应用

在 lodash/fp

underscore

ramba

curry

javascript 复制代码
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

两个函数组合:

javascript 复制代码
function compose(f,g){
    return function(x){
        return f(g(x))
    }
}

不确定个数函数组合:

javascript 复制代码
// 传入多个函数
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)))
}

示例:

简化版
javascript 复制代码
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'))
展开写:
javascript 复制代码
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

示例一:

javascript 复制代码
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']))

示例二:

javascript 复制代码
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

javascript 复制代码
// 用在 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来做的?

javascript 复制代码
// 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指向

javascript 复制代码
// 用来劫持对象的逻辑

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,而不会抛出错误。

这种语法的引入使得代码更加简洁并且更安全,特别是在处理深层嵌套的对象属性时。

相关推荐
故事不长丨15 小时前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
源心锁15 小时前
👋 手搓 gzip 实现的文件分块压缩上传
前端·javascript
哈库纳玛塔塔15 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
phltxy16 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
Kagol16 小时前
JavaScript 中的 sort 排序问题
前端·javascript
天“码”行空16 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
cos17 小时前
Fork 主题如何更新?基于 Ink 构建主题更新 CLI 工具
前端·javascript·git
odoo中国18 小时前
Odoo 19 模块结构概述
开发语言·python·module·odoo·核心组件·py文件按
代码N年归来仍是新手村成员18 小时前
【Java转Go】即时通信系统代码分析(一)基础Server 构建
java·开发语言·golang
Z1Jxxx19 小时前
01序列01序列
开发语言·c++·算法