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

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

相关推荐
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
小白学大数据3 小时前
Python爬虫开发中的分析与方案制定
开发语言·c++·爬虫·python
冰芒猓4 小时前
SpringMVC数据校验、数据格式化处理、国际化设置
开发语言·maven
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
杜杜的man4 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang
java小吕布5 小时前
Java中Properties的使用详解
java·开发语言·后端