/**
* 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>