//面向过程
let a=1;
let b=2;
let result = a+b;
//面向对象
class Sum{
add(a,b){
return a+b;
}
}
let sum = new Sum();
sum.add(1,2);
//函数式编程,这里的函数指的是一种映射关系 y=f(x)
function add(a,b){
return a+b;
}
add(1,2);
function add(a,b){
return a+b;
}
//1.函数可以赋值给变量
let add1 = add;
//2.函数可以作为参数
function exec(fn,a,b){
fn(a,b);
}
//3.函数可以作为返回值
function exec(fn){
return function(a,b){
return fn(a,b);
}
}
function init() {
var name = "hello";
function showName() {
debugger
console.log(name);
}
return showName;
}
let showName = init();
showName();
function add(a,b){
return a+b;
}
let c = 1;
let d =2;
function add2(a,b){
d++;//修改了外部变量
return a+b+c;//计算结果依赖外部变量
}
add2();
console.log(d);
cnpm i lodash -S
let _ = require('lodash');
const add = (a, b) => {
console.log('add');
return a + b;
}
const resolver = (...args)=>JSON.stringify(args)
var memoize = function (func,resolver) {
let cache = {};
let memoized = (...args) => {
const key = resolver?resolver(...args):JSON.stringify(args);
if (typeof cache[key] !== 'undefined') {
return cache[key];
} else {
cache[key] = func(...args);
return cache[key];
}
}
memoized.cache = cache;
return memoized;
};
//let memoizedAdd = _.memoize(add,resolver);
let memoizedAdd = memoize(add,resolver);
console.log(memoizedAdd(1,2));
console.log(memoizedAdd(1,2));
console.log(memoizedAdd.cache);
module.exports = memoizedAdd;
cnpm install jest --save-dev
5.test.js
const sum = require('./5.js');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
expect(sum(1, 2)).toBe(3);
});
{
"scripts": {
"test": "jest"
}
}
let _ = require('lodash');
function add(a, b, c) {
return a + b + c;
}
function curry(func) {
let curried = (...args) => {
if(args.length < func.length){
return (...rest)=>curried(...args,...rest);
}
return func(...args);
}
return curried;
}
let curriedAdd = curry(add);
console.log(curriedAdd(1, 2, 3));
console.log(curriedAdd(1)(2, 3));
console.log(curriedAdd(1)(2)(3));
flow
,除了它调用函数的顺序是从右往左的。手工组合
function add1(str) {
return str + 1;
}
function add2(str) {
return str + 2;
}
function add3(str) {
return str + 3;
}
//手工组合
console.log(add3(add2(add1('hello'))));
flow
//let {flow} = require('lodash');
function add1(str) {
return str + 1;
}
function add2(str) {
return str + 2;
}
function add3(str) {
return str + 3;
}
//手工组合
function flow(...fns) {
if (fns.length == 0)
return fns[0];
return fns.reduceRight((a, b) => (...args) => a(b(...args)));
}
let flowed = flow(add3, add2, add1);
console.log(flowed('zhufeng'));
flowRight
let {flowRight} = require('lodash');
function add1(str) {
return str + 1;
}
function add2(str) {
return str + 2;
}
function add3(str) {
return str + 3;
}
function flowRight(...fns) {
if (fns.length == 0)
return fns[0];
return fns.reduce((a, b) => (...args) => a(b(...args)));
}
let flowed = flowRight(add3, add2, add1);
console.log(flowed('zhufeng'));
//带参数的函数组合
let {split,toUpper,join} = require('lodash');
let str = 'click button';//CLICK_BUTTON
let r1 = split(str,' ');
console.log(r1);//[ 'click', 'button' ]
let r2 = toUpper(r1);
console.log(r2);//CLICK,BUTTON
let r3 = split(r2,',');
console.log(r3);//[ 'CLICK', 'BUTTON' ]
let r4 = join(r3,'_');
console.log(r4);//CLICK_BUTTON
数据先放
let {split,toUpper,join,flowRight} = require('lodash');
let str = 'click button';//CLICK_BUTTON
//loadsh数据放前面
const func = flowRight(join('_'),split(','), toUpper, split(' '));
console.log(func(str));
数据后放
let {split,toUpper,join,flowRight} = require('lodash/fp');
let str = 'click button';//CLICK_BUTTON
//fp数据放后
const func = flowRight(join('_'),split(','), toUpper, split(' '));
console.log(func(str));
过程跟踪
let {split,toUpper,join,flowRight} = require('lodash/fp');
let str = 'click button';//CLICK_BUTTON
const logger = (name) => value => {
console.log(name, value);
return value;
}
const func = flowRight(join('_'),logger('afterSplit'),split(','),logger('afterToUpper'), toUpper, split(' '));
console.log(func(str));
Pointfree
const { compose } = require("lodash/fp");
let num = 1;
//Pointed
function calcu(num){
return num+1+2+3;
}
function add1(num){
return num+1
}
function add2(num){
return num+2
}
function add3(num){
return num+3
}
//Pointfree
let fn = compose(add3,add2,add1);
console.log(fn(1));
class Container{
constructor(value){
this.value = value;
}
}
of
方法可称为有指向的容器class PointedContainer{
constructor(value){
this.value = value;
}
static of (value){
return new PointedContainer(value);
}
}
map
方法可称为Functor(函子)of
方法,用来生成实例value
map
方法,接入各种运算函数,从而引发值的变化class Functor{
constructor(value){
this.value = value;
}
static of (value){
return new Functor(value);
}
map(fn){
return new Functor(fn(this.value));
}
}
let result = Functor.of('a')
.map(x=>x+1)
.map(x=>x+2)
.map(x=>x+3);
console.log(result.value);
Maybe
函子可以过滤空值,能过滤空值的函子被称为Maybe函子class Maybe {
constructor(value){
this.value = value;
}
static of (value){
return new Maybe(value);
}
map(fn){
return this.value?new Maybe(fn(this.value)):this;
}
}
Maybe.of(null).map(x=>x.toString())
class Either{
constructor(left, right) {
this.left = left;
this.right = right;
}
static of = function (left, right) {
return new Either(left, right);
};
map(fn) {
return this.right ?
Either.of(this.left, fn(this.right)) :
Either.of(fn(this.left), this.right);
}
get value(){
return this.right||this.left;
}
}
//处理默认值
let user = {gender:null};
let result = Either.of('男',user.gender)
.map(x=>x.toUpperCase())
console.log(result.value);
//处理异常
function parse(str){
try{
return Either.of(null,{data:JSON.parse(str)});
}catch(error){
return Either.of({error:error.message},null);
}
}
console.log(parse("{}").value);
console.log(parse("{x}").value);
class Ap{
constructor(value){
this.value = value;
}
static of (value){
return new Ap(value);
}
map(fn){
return new Ap(fn(this.value));
}
ap(functor) {
return Ap.of(this.value(functor.value));
}
}
const A = Ap.of(x=>x+1);
const B = Ap.of(1)
let result = A.ap(B);
console.log(result);
flatMap
方法,与map
方法作用相同,唯一的区别是如果生成了一个嵌套函子,它会取出后者内部的值,保证返回的永远是一个单层的容器,不会出现嵌套的情况函子嵌套
class Functor {
constructor(value) {
this.value = value;
}
static of(value) {
return new Functor(value);
}
map(fn) {
return new Functor(fn(this.value));
}
}
let result = Functor.of('a')
.map(x=>Functor.of(x+1))
.map(x=>Functor.of(x.value+2))
.map(x=>Functor.of(x.value+3))
console.log(result.value.value);
let r1 = [1,2,3].map(item=>[item+1]);
console.log(r1);//[ [ 1, 1 ], [ 2, 2 ], [ 3, 3 ] ]
console.log(r1[0][0]);
let r2 = [1,2,3].flatMap(item=>[item+1]);
console.log(r2);
console.log(r2[0]);
class Monad {
constructor(value) {
this.value = value;
}
static of(value) {
return new Monad(value);//a
}
map(fn) {
return new Monad(fn(this.value));
}
join() {
return this.value;
}
flatMap(fn){
return this.map(fn).join();
}
}
/* let result = Monad.of('a')
.flatMap(x=>{
let r = Monad.of(x+1);
r.name = 'x1';
return r;
})//new Monad('a1')); 返回的Monad.value=Monad.of(x+1),后面用的是Monad.of(x+1)
console.log(result); */
let result = Monad.of('a')
.flatMap(x=>Monad.of(x+1))
.flatMap(x=>Monad.of(x+2))
.flatMap(x=>Monad.of(x+3))
console.log(result.value);
//flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
let r1 = Array.of(1,2,3).map(x=>x+1);
console.log(r1);
let r2 = Array.of(1,2,3).map(x=>[x+1]);
console.log(r2);
let r3 = Array.of(1,2,3).flatMap(x=>[x+1]);
console.log(r3);
IO Monad
过程调用
const { compose } = require("lodash/fp");
let localStorage = {
getItem(key){
if(key === 'data')
return `{"code":0,"userId":"1"}`;
else if(key === "1"){
return `{"id":1,"name":"zhangsan","age":18}`;
}
}
}
function printUsers() {
const response = localStorage.getItem('data');
const data = JSON.parse(response);
const users = data.userId;
const user = localStorage.getItem(data.userId);
console.log(user);//输出副作用
}
printUsers();
IO函子
const { compose } = require("lodash/fp");
let localStorage = {
getItem(key){
if(key === 'data')
return `{"code":0,"userId":"1"}`;
else if(key === "1"){
return `{"id":1,"name":"zhangsan","age":18}`;
}
}
}
class IO {
constructor(value) {
this.value = value;
}
map(fn) {
return new IO(compose(fn, this.value));
}
join() {
return this.value();
}
start(callback) {
callback(this.value());
}
}
const readByKey = key => new IO(() => localStorage.getItem(key));
const parseJSON = string => JSON.parse(string);
const writeToConsole = console.log;
readByKey('data')
.map(parseJSON)
.start(writeToConsole);
链式调用
const { compose } = require("lodash/fp");
let localStorage = {
getItem(key){
if(key === 'data')
return `{"code":0,"userId":"1"}`;
else if(key === "1"){
return `{"id":1,"name":"zhangsan","age":18}`;
}
}
}
class IO {
constructor(value) {
this.value = value;
}
map(fn) {
return new IO(compose(fn, this.value));
}
flatMap(fn) {
return new IO(compose(x=>x.value(), fn, this.value));
}
start(callback) {
callback(this.value());
}
}
const readByKey = key => new IO(() => localStorage.getItem(key));
const parseJSON = string => JSON.parse(string)
const writeToConsole = console.log;
let ret = readByKey('data')
.map(parseJSON)
.map(item=>item.userId)
.flatMap(readByKey)
.map(parseJSON)
.start(writeToConsole);;
异步执行任务
const Task = execute => ({
execute
});
function get(url) {
return Promise.resolve({ "code": 0, "userId": "1" });
}
const request = url => Task((resolve,reject) => get(url).then(resolve,reject));
request('data')
.execute(user => console.log(user),error => console.error(error));
实现map
const Task = execute => ({
execute,
map: fn => Task(resolve => execute(x => resolve(fn(x))))
});
function get(url) {
return Promise.resolve({ "code": 0, "userId": "1" });
}
const request = url => Task((resolve,reject) => get(url).then(resolve,reject));
request('data')
.map(x => x.userId)
.execute(user => console.log(user),error => console.error(error));
实现 flatMap
const Task = execute => ({
map: fn => Task(resolve => execute(x => resolve(fn(x)))),
flatMap: fn => Task(resolve => execute(x => fn(x).execute(resolve))),
execute
});
function get(url) {
if (url === 'data')
return Promise.resolve({ "code": 0, "userId": "1" });
else if (url === "1") {
return Promise.resolve({ "id": 1, "name": "zhangsan", "age": 18 });
}
}
const request = url => Task(resolve => get(url).then(resolve));
request('data')
.map(x => x.userId)
.flatMap(request)
.map(x => x.name)
.execute(user => console.log(user));
<template>
<div>
<span>count is {{ count }}</span>
<span>plusOne is {{ plusOne }}</span>
<button @click="increment">count++</button>
</div>
</template>
<script>
import { value, computed, watch, onMounted } from 'vue'
export default {
setup() {
// reactive state
const count = value(0)
// computed state
const plusOne = computed(() => count.value + 1)
// method
const increment = () => { count.value++ }
// watch
watch(() => count.value * 2, val => {
console.log(`count * 2 is ${val}`)
})
// lifecycle
onMounted(() => {
console.log(`mounted`)
})
// expose bindings on render context
return {
count,
plusOne,
increment
}
}
}
</script>