lodash源码分析之cloneBuffer
本文为读 lodash 源码的第一百八十二篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
依赖
import root from './root.js'
源码分析
cloneDeep
用来克隆 Buffer
数据类型。
源码如下:
const freeExports = typeof exports === 'object' && exports !== null && !exports.nodeType && exports
const freeModule = freeExports && typeof module === 'object' && module !== null && !module.nodeType && module
const moduleExports = freeModule && freeModule.exports === freeExports
const Buffer = moduleExports ? root.Buffer : undefined, allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined
function cloneBuffer(buffer, isDeep) {
if (isDeep) {
return buffer.slice()
}
const length = buffer.length
const result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length)
buffer.copy(result)
return result
}
cloneBuffer
函数之前的代码主要是做 Node.js
环境检测,并且将 Buffer.allocUnsafe
方法取出。
这部分逻辑跟 isBuffer
方法中的逻辑十分相似,在《lodash源码分析之isBuffer》中已经做过分析,这里不再细说。
深度拷贝
if (isDeep) {
return buffer.slice()
}
如果 isDeep
为 true
,则使用 buffer
实例上的 slice
方法返回一个新的 buffer
。
但是根据文档的描述,这个新的 buffer
其实和原 buffer
指向的是同一块内存,如果原 buffer
有更改,新的 buffer
也会更改,同理,新的 buffer
的更改同样会影响到原 buffer
。
浅拷贝
const length = buffer.length
const result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length)
buffer.copy(result)
return result
现在推荐使用 Buffer.from
、Buffer.alloc
或者 Buffer.allocUnsafe
来开辟一块内存来创建 buffer
,不推荐直接使用 new Buffer(length)
的方式来创建。
lodash
会优先使用 allocUnsafe
来创建,因为这个方法在开辟内存的时候不会做初始化的操作,但是 lodash
在开辟完内存后并没有马上给外界使用这块内存,所以使用这个方法是安全的。因为没有初始化的操作,因此性能会更加高。
如果没有 allocUnsafe
方法,则使用 new buffer.constructor
来开辟一块长度为 length
的内存。这其实相当于 new Buffer(length)
,因为 buffer
实例的构造函数就是 Buffer
,但是使用 new buffer.constructor
会更加安全,因为用户有可能是通过继承 Buffer
类的形式来创建 buffer
的,甚至还有可能将全局的 Buffer
类覆盖了。
例如:
const Buffer = Object
这样全局的 Buffer
类就被改写成 Object
类了。
最后使用 buffer.copy
方法将 buffer
复制到 result
中。
疑惑
为什么 isDeep
的时候使用 slice
让我一直疑惑。
因为根据文档,slice
会:
Returns a new Buffer that references the same memory as the original
也即 slice
所返回的新 Buffer
和原 Buffer
指向的是同一块内存。
在和 TypedArray.slice
的对比中更有如下描述:
While TypedArray#slice() creates a copy of part of the TypedArray, Buffer#slice() creates a view over the existing Buffer without copying.
清楚说明了 slice
是 without copying
的。
照理不能用 slice
来做深度拷贝,总之令人费解。
参考资料
内功修炼之lodash—— clone& cloneDeep(一定有你遗漏的js基础知识)
License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面