在开发过程中踩了一个坑, 觉得挺有意思, 就顺手编成了一道题
- // Cache 是一个缓存类, 使用时先在 new 方法中注册获取数据的方法, 然后可通过 get 方法获取数据,
- // 并且只有第一次调用 get 会真正调用 new 中注册的方法获取数据, 以后都直接从缓存中返回
- function Cache () {this.store = {}
- }
- Cache.prototype.new = function (name, fn) {
- if (!name || !fn || typeof fn !== 'function') {
- return
- }
- this.store[name] = {name, fn, data: {}}
- }
- Cache.prototype.get = function (name, key) {
- const self = this.store[name]
- key = key || 1
- if (self.data[key]) {
- return Promise.resolve(self.data[key])
- }
- return self.fn(key).then(data => {
- self.data[key] = data
- return data
- })
- }
- Cache.prototype.clear = function (name, key) {
- this.store[name].data[key] = null
- }
- Cache.prototype.clearAll = function (name) {
- this.store[name].data = {}
- }
- // 1. 下面的代码说明 Cache 的实现存在一个 bug, 尝试修复它
- const c = new Cache()
- c.new('foo', function (key) {
- return Promise.resolve([1])
- })
- c.get('foo').then(
- list0 => {
- console.log(list0)
- list0.push(2)
- return c.get('foo')
- }).then(
- list1 => {
- console.log(list1)
- list1.push(3)
- return c.get('foo')
- }).then(
- list2 => {
- console.log(list2)
- })
- // 2. 对以上代码提出一些改进意见
以下是解答:
作为一个缓存类, 每次读取到的数据应该是相同的, 显然这里并不是那么是哪里出了问题? 在 js 中如果返回值不是基础类型 (如 Number,String) 返回的会是一个对象引用, 而这里正是返回了缓存对象的引用, 才导致调用者可以随意更改缓存的内容怎么解决呢? 拷贝后再返回, 切断缓存与返回值间的关联, 而且必须是深拷贝才能彻底切断考虑使用场景是获取后端数据, 这个地方的用 json 序列化实现
get 方法的参数 key 有默认值 1, 这个逻辑并不正确如果 key 为空会导致调用 new 中注册的数据获取方法时错误地传入 key 的默认值 1
- Cache.prototype.get = function (name, key) {
- const self = this.store[name]
- if (self.data[key]) {
- return Promise.resolve(JSON.parse(self.data[key]))
- }
- return self.fn(key).then(data => {
- self.data[key] = JSON.stringify(data)
- return data
- })
- }
我在刚编出这道的时候觉得不过就是一个考察 return 返回引用的题目, 并不多难, 但是在问过几个人以后才发现没那么简单首先需要对使用原型链构造类有基本的了解, 对于那些如果是仅仅只是实现一下业务逻辑, 不做任何抽象和封装的 ctrl+v 工程师而言恐怕确实不需要懂其次是 Promise 和 ES6 语法, 相对来说这些也是比较新的东西
为什么人与人之间差别就那么大呢? 同一个技术点对有的人来说是不必多说的基础, 对于另一些人来说却是天方夜谭
来源: https://juejin.im/post/5aa0037b6fb9a028c42dc260