函数式编程
- 柯里化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,其实目前看有点过时了
现在主流的样式体系方案:
- module css,中规中矩的
- css in js,运行时的开销,性能稍差
- 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
看具体原理,内部具体是怎么做的
箭头函数
问题
- 不能定义构造器,不能new
- this指向的是外部的作用域
- 没有arguments
- 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,而不会抛出错误。
这种语法的引入使得代码更加简洁并且更安全,特别是在处理深层嵌套的对象属性时。