JSのオブジェクトの分割代入で既定値が割り当てられるのはundefinedの場合のみ
「JSのオブジェクトの分割代入で既定値が割り当てられるのはundefinedの場合のみ」ということは、MDNのAssigning to new variable names and providing default valuesにAssigned a default value in case the unpacked value is undefined.
と書いてあることや、13 ECMAScript Language: Expressionsの13.15.5.3 Runtime Semantics: PropertyDestructuringAssignmentEvaluationに4. If Initializeropt is present and v is undefined, then
とあることから分かる。
ここからNode.jsのfs.readを使ってみていく。
node/lib/fs.js#L605~ に以下のコードがある。
function read(fd, buffer, offsetOrOptions, length, position, callback) { ... } else if (arguments.length === 3) { // This is fs.read(fd, bufferOrParams, callback) if (!isArrayBufferView(buffer)) { // This is fs.read(fd, params, callback) params = buffer; ({ buffer = Buffer.alloc(16384) } = params ?? kEmptyObject); } ... ... ({ offset = 0, length = buffer.byteLength - offset, position = null, } = params ?? kEmptyObject); ... validateBuffer(buffer); ...
例えばfs.read(fd, {offset: 1}, callback)
というように呼び出すと、
params = {offset: 1}
({ buffer = Buffer.alloc(16384) } = {offset: 1}
buffer = Buffer.alloc(16384)
というように処理される。
もしfs.read(fd, {buffer: null}, callback)
というように呼び出すと、
params = {buffer: null}
({ buffer = Buffer.alloc(16384) } = {buffer: null}
buffer = null
というように処理される。
この場合、validateBuffer
が呼びされる前にlength = buffer.byteLength - offset
でbuffer = null
が参照されてしまう。
これを解決したのがこのPR。
github.com
ちなみにdeno_stdは現時点でNodeのv18.8.0との互換を保っているため、以下のように意図的にnullを参照するようにしている。
github.com
// @ts-ignore: Intentionally create TypeError for passing test-fs-read.js#L87 length = opt.buffer.byteLength;