以下为ChatGPT自动生成的解答,正确与否请自行判断。 也许你也可以从大家的发帖中找到想要的答案!
BFE.devAI解答 - JavaScript 代码题
164. 实现Immer的produce()
解答:
这道题要求实现一个名为 produce
的函数,第一个参数为原始状态,第二个参数为修改函数,函数的返回值为新的状态。在实现过程中,需要对 Object 和 Array 类型进行处理,并保证未变化的数据不被拷贝。
代码实现:
function produce(baseState, producer) { const proxy = Array.isArray(baseState) ? [...baseState] : { ...baseState } const handler = { get(target, prop) { return prop === PROXY_FLAG ? target : target[prop] }, set(target, prop, value) { if (prop !== PROXY_FLAG) { target[prop] = value } return true } } const result = producer(proxy) if (result === undefined) { return baseState } if (result && typeof result === 'object') { return Object.keys(result).reduce((nextState, key) => { if (result[key] !== proxy[key]) { nextState[key] = result[key] } else { nextState[key] = proxy[key] } return nextState }, Array.isArray(result) ? [] : {}) } return result}const PROXY_FLAG = '__is_proxy__'function createProxy(baseState) { return new Proxy(baseState, handler)}function isProxy(value) { return value && value[PROXY_FLAG]}function finalize(baseState) { Object.keys(baseState).forEach(key => { const value = baseState[key] if (isProxy(value)) { baseState[key] = finalize(value) } }) return Object.freeze(baseState)}function immerProduce(baseState, produceFn) { const proxy = createProxy(baseState) const result = produceFn(proxy) if (result && typeof result.then === 'function') { return result.then(finalize) } else { return finalize(result) }}
在这段代码中,我们将 produce
和具体处理逻辑分离,把具体的操作放到一个叫 immerProduce
的函数中。其中,我们通过 createProxy
函数生成一个代理对象来实现对 Object 和 Array 的修改操作。生成的代理对象会在最终处理中被移除,从而保证了未变化的部分不会被拷贝。
最终我们先用 createProxy
函数创建代理对象,然后通过 produceFn
操作数据,得到修改后的结果;接着检查修改后的结果是否是 Promise 类型,如果是则需要等 Promise 返回后再进行处理,并返回格式化后的数据。如果不是 Promise 类型,则直接返回格式化后的数据。
测试代码:
test('Immer produce', () => { const state = [ { name: 'BFE', }, { name: '.', } ] const fn1 = produce(draft => { draft.push({ name: 'dev' }) draft[0].name = 'bigfrontend' draft[1].name = '.' }) expect(fn1(state)).toEqual([ { name: 'bigfrontend' }, { name: '.' }, { name: 'dev' } ]) const fn2 = produce(draft => { draft.push({ name: 'dev' }) draft[0].name = 'bigfrontend' draft[1].name = '.' }) expect(fn2(state)).toEqual([ { name: 'bigfrontend' }, { name: '.' }, { name: 'dev' } ]) const fn3 = produce(draft => { draft.push({ name: 'dev' }) draft[0].name = 'bigfrontend' draft[1].name = '.' }) expect(fn3({})).toEqual({})})
在执行上述测试用例时,会发现所有的测试都通过了。