0

我试图了解这个重新选择库中函数的流程。我目前console.log用来记录输出。尽管如此,还是很难理解流程。让我想想函数式编程是多么复杂!!!

如何使用 ES6 装饰器或代理或任何其他语言功能拦截调用并将函数名称和参数记录到控制台?

function defaultEqualityCheck(a, b) {
  return a === b
}

function areArgumentsShallowlyEqual(equalityCheck, prev, next) {
  if (prev === null || next === null || prev.length !== next.length) {
    return false
  }

  // Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
  const length = prev.length
  for (let i = 0; i < length; i++) {
    if (!equalityCheck(prev[i], next[i])) {
      return false
    }
  }

  return true
}

function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
  
  let lastArgs = null
  let lastResult = null
  
  console.log("Entering defaultMemoize");
  
  console.log("###INPUT### defaultMemoize argument func type: " + typeof func);
  
  // we reference arguments instead of spreading them for performance reasons
  return function () {
    
    if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
      
      // apply arguments instead of spreading for performance.
      lastResult = func.apply(null, arguments)
    }

    lastArgs = arguments
    
    return lastResult
  }
}

function getDependencies(funcs) {
  const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs

  if (!dependencies.every(dep => typeof dep === 'function')) {
    const dependencyTypes = dependencies.map(
      dep => typeof dep
    ).join(', ')
    throw new Error(
      'Selector creators expect all input-selectors to be functions, ' +
      `instead received the following types: [${dependencyTypes}]`
    )
  }

  return dependencies
}

function createSelectorCreator(memoize, ...memoizeOptions) {
  
  console.log("Entering createSelectorCreator");
  
  console.log("#INPUT# argument memoize name: " + memoize.name);

  console.log("#INPUT# argument memoize options: ");
  
  console.log(memoizeOptions);

  return (...funcs) => {
    
    let recomputations = 0
    
    const resultFunc = funcs.pop()
    const dependencies = getDependencies(funcs)

    console.log("##INPUT## argument funcs: ");
    console.log(resultFunc);
    
    const memoizedResultFunc = memoize(
      function () {
        recomputations++
        
        // apply arguments instead of spreading for performance.
        return resultFunc.apply(null, arguments)
      },
      ...memoizeOptions
    )
    
    console.log("memoizedResultFunc: " + typeof memoizedResultFunc);

    // If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
    const selector = defaultMemoize(function () {
      const params = []
      const length = dependencies.length

      if (arguments != null)
      {
        console.log("***INPUT*** arguments: ");
        console.log(arguments);
      }
      
      for (let i = 0; i < length; i++) {
        // apply arguments instead of spreading and mutate a local list of params for performance.
        params.push(dependencies[i].apply(null, arguments))
      }

      // apply arguments instead of spreading for performance.
      return memoizedResultFunc.apply(null, params)
    })

    selector.resultFunc = resultFunc
    selector.recomputations = () => recomputations
    selector.resetRecomputations = () => recomputations = 0
    
    return selector
  }
}

const createSelector = createSelectorCreator(defaultMemoize)

function createStructuredSelector(selectors, selectorCreator = createSelector) {
  if (typeof selectors !== 'object') {
    throw new Error(
      'createStructuredSelector expects first argument to be an object ' +
      `where each property is a selector, instead received a ${typeof selectors}`
    )
  }
  const objectKeys = Object.keys(selectors)
  return selectorCreator(
    objectKeys.map(key => selectors[key]),
    (...values) => {
      return values.reduce((composition, value, index) => {
        composition[objectKeys[index]] = value
        return composition
      }, {})
    }
  )
}

const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent

const subtotalSelector = createSelector(
  shopItemsSelector,
  items => items.reduce((acc, item) => acc + item.value, 0)
)

const taxSelector = createSelector(
  subtotalSelector,
  taxPercentSelector,
  (subtotal, taxPercent) => subtotal * (taxPercent / 100)
)

const totalSelector = createSelector(
  subtotalSelector,
  taxSelector,
  (subtotal, tax) => ({ total: subtotal + tax })
)

let exampleState = {
  shop: {
    taxPercent: 8,
    items: [
      { name: 'apple', value: 1.20 },
      { name: 'orange', value: 0.95 },
    ]
  }
}

console.log(subtotalSelector(exampleState))// 2.15
//console.log(taxSelector(exampleState))// 0.172
//console.log(totalSelector(exampleState))// { total: 2.322 }

4

0 回答 0