compose
函数做为另一个函数的参数时,因为函数式参数,所以先执行作为参数的函数。
函数柯里化
接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数。并且返回接受余下的参数而且返回结果的新函数的技术。
柯里化其实本身是固定一个可以预期的参数,并返回一个特定的函数,处理批特定的需求。这增加了函数的适用性,但同时也降低了函数的适用范围。
Thunk 函数的含义
编译器的“传名调用”实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。
function f(m) {
return m * 2;
}
f(x + 5);
// 等同于
var thunk = function () {
return x + 5;
};
function f(thunk) {
return thunk() * 2;
}
上面代码中,函数 f 的参数x + 5被一个函数替换了。凡是用到原参数的地方,对Thunk函数求值即可。
这就是 Thunk 函数的定义,它是“传名调用”的一种实现策略,用来替换某个表达式。
JavaScript 语言的 Thunk 函数
JavaScript 语言是传值调用,它的 Thunk 函数含义有所不同。在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数。
// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);
// Thunk版本的readFile(单参数版本)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);
var Thunk = function (fileName){
return function (callback){
return fs.readFile(fileName, callback);
};
};
上面代码中,fs 模块的 readFile 方法是一个多参数函数,两个参数分别为文件名和回调函数。经过转换器处理,它变成了一个单参数函数,只接受回调函数作为参数。这个单参数版本,就叫做 Thunk 函数。
任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式。下面是一个简单的 Thunk 函数转换器。
var Thunk = function(fn){
return function (){
var args = Array.prototype.slice.call(arguments);
return function (callback){
args.push(callback);
return fn.apply(this, args);
}
};
};
使用上面的转换器,生成 fs.readFile 的 Thunk 函数。
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);
redux中间件
让我们可以介入数据从 action 到 reducer 之间的传递过程,从而改变数据流,实现如异步、数据过滤、日志上报等功能。
加载中间件有两个核心的方法: createStore 和 applyMiddleware ,接下来我们就从源码剖析,看 redux 中间件的运行原理到底是怎么样的。
import compose from './compose'
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer)
var dispatch = store.dispatch
var chain = []
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
实现applyMiddleware&thunk
export function applyMiddleware(middleWare){
return createStore=>(...args)=>{
// 生成createStore,...agr就是reducer
const store = createStore(...args)
let dispatch = store.dispatch
const midApi = {
getState : store.getState,
dispatch : (...args)=>dispatch(...args)
}
// 把原生的dispatch拿出来,给到middleWare
dispatch = middleWare(midApi)(store.dispatch)
return {
...store,
dispatch
}
}
}
----
const thunk = ({dispatch,getState})=>next=>action=>{
// 如果是函数,执行以下,参数是dispatch和getState
if(typeof action == 'function'){
return action(dispatch,getState)
}
// 默认,什么都没干
return next(action)
}
1、enhancer(createStore)(reducer, preloadedState) 执行的时候,参数 createStore 给了第一层匿名函数,因为我们的目的是要对 createStore 进行修饰。而 reducer, preloadedState 两个参数给了第二层匿名函数。