/** * createStore(reducer,preloadedState预存储状态,enhancer对store性能进行加强) * { * getState,dispatch,subscribe * } */function createStore(reducer, preloadedState, enhancer) { // 9,束缚reducer参数类型 if (typeof reducer !== "function") throw new Error("reducer must be a function"); // 12判断enchancer是否传递,是否是一个函数 if (typeof enhancer !== "undefined") { if (typeof enhancer !== "function") { throw new Error("enhancer must be a function"); } // redux中调用,传入createStore 并返回一个函数,返回reducer, preloadedState return enhancer(createStore)(reducer, preloadedState); } // 1,sotre对象中存储的状态 var currentState = preloadedState; // 6,寄存订阅者函数 var currentListeners = []; // 2,获取状态 function getState() { return currentState; } // 3用于触发action的办法 function dispatch(action) { // 10,判断action是否是一个对象 if (!isPlainObject(action)) throw new Error("action必须是一个对象"); // 11,判断action中的type属性是否存在 if (typeof action.type === "undefined") throw new Error("action对象中必须有type属性"); currentState = reducer(currentState, action); // 依据以后状态和action解决返回新的状态 // 7循环数组调用订阅者 for (let i = 0; i < currentListeners.length; i++) { // 获取订阅者 var listener = currentListeners[i]; // 调用订阅者 listener(); } } // 5,订阅状态 function subscribe(listener) { currentListeners.push(listener); } // 8 返回 return { getState, dispatch, subscribe, };}// 4// store.subscribe(() => {});// 判断参数是否是对象类型// 判断对象的以后原型对象是否和顶层原型对象雷同function isPlainObject(obj) { // 排除根本数据类型和null if (typeof obj !== "object" || obj === null) return false; // 辨别数组和对象 原型对象比照的形式 var proto = obj; // 获取最顶层的原型对象 while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto); } return Object.getPrototypeOf(obj) === proto; // 返回true就是对象}function applyMiddleware(...middlewares) { return function (createStore) { return function (reducer, preloadedState) { // 创立store,拿到store,给中间件传参 var store = createStore(reducer, preloadedState); // 阉割版的 store var middlewareAPI = { getState: store.getState, dispatch: store.dispatch, }; // 调用中间件的第一层函数 传递阉割版的store对象,返回中间件函数内的外面两层函数 var chain = middlewares.map((middleware) => middleware(middlewareAPI)); // 中间件第二层参数传参,第三层就是dispath var dispatch = compose(...chain)(store.dispatch); // 返回一个增强版的store return { ...store, dispatch, }; }; };}function compose() { var funcs = [...arguments]; console.log(funcs); // 因为函数嵌套问题,执行程序尽管是logger再thunk,为了保障程序,要顺叙数组,先执行thunk第二层返回dispath, return function (dispatch) { for (var i = funcs.length - 1; i >= 0; i--) { // 第一轮执行返回值返回是thunk外面的函数,他是logger须要的 dispatch = funcs[i](dispatch); } return dispatch; };}// bindActionCreators函数 将action creator函数转换为可能触发action的函数function bindActionCreators(actionCreators, dispatch) { // 创立一个对象用于返回,返回值是一个对象 // function increment(){ // dispatch({type:'increment'}) // } var boundActionCreators = {}; for (var key in actionCreators) { // IIFE解决key变量不能保留的问题 (function (key) { boundActionCreators[key] = function () { dispatch(actionCreators[key]()); }; })(key); // actionCreators[key]() 拿到increment函数,执行,返回action对象 // dispatch(actionCreators[key]()) dispatch action对象 } return boundActionCreators;}// combineReducers组合小的reducer成为大的reducer,返回一个reducer函数function combineReducers(reducers) { // 查看reducer类型 它必须是函数 var reducerKeys = Object.keys(reducers); for (var i = 0; i < reducerKeys.length; i++) { var key = reducerKeys[i]; if (typeof reducers[key] !== "function") throw new Error("reducer必须是函数"); } // 调用一个一个的小的reducer 将每一个小的reducer中返回的状态存储在一个新的大的对象中 return function (state, action) { var nextState = {}; // 存储最新的状态 // 循环reducer拿到最新的状态 for (var i = 0; i < reducerKeys.length; i++) { var key = reducerKeys[i]; var reducer = reducers[key]; var previousStateForKey = state[key]; nextState[key] = reducer(previousStateForKey, action); } console.log(nextState) return nextState; };}
测试代码
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <button id='increment'>+1</button> <span id='box'>0</span> <button id='decrement'>-1</button> <script src="myRedux.js"></script> <script src="middlewares/logger.js"></script> <script src="middlewares/thunk.js"></script> <script> function enhancer(createStore) { return function (reducer, preloadedState) { var store = createStore(reducer, preloadedState) var dispatch = store.dispatch function _dispatch(action) { if (typeof action === 'function') { return action(dispatch) } dispatch(action) } return { ...store, dispatch: _dispatch } } } function counterReducer(state, action) { switch (action.type) { case 'increment': return state + 1; case 'decrement': return state - 1 default: return state } } var rootReducer = combineReducers({ counter: counterReducer }) // 1创立store // const store = createStore(reducer, 0, enhancer) const store = createStore(rootReducer, { counter: 100 }, applyMiddleware(logger, thunk)) console.log(store) store.subscribe(function () { // 获取最新的状态 console.log(store.getState()) document.getElementById('box').innerHTML = store.getState().counter }) var actions = bindActionCreators({ increment, decrement }, store.dispatch) function increment() { return { type: 'increment' } } function decrement() { return { type: "decrement" } } // 获取加按钮 document.getElementById('increment').onclick = function () { // 触发action // store.dispatch(function (dispatch) { // setTimeout(function () { // dispatch({ // type: 'increment' // }) // }, 1000); // }) // 代码执行程序 logger->thunk->reducer // store.dispatch({ // type: 'increment' // }) actions.increment() } document.getElementById('decrement').onclick = function () { // store.dispatch({ // type: 'decrement' // }) actions.decrement() } </script></body></html>