为何调用decipher后caldata值未变?及JS字节转Uint32方法
问题解答
一、调用decipher后caldata值未变化的原因及解决
原因
JavaScript中原始类型(Number、String等)采用按值传递。你的代码里caldata = new Uint32Array(u32)[0]取的是Uint32Array的第一个元素,属于Number类型(原始值)。调用decipher(caldata, key)时,传递的是这个原始值的副本,函数内部对参数v的操作不会影响外部的caldata。此外,函数中错误地将v当作数组访问v[0],但实际v是Number,v[0]结果为undefined,后续逻辑完全无效。
解决方法
传递引用类型(如数组、TypedArray实例),这类类型传递的是内存地址,函数内部修改会同步影响外部变量。
方案1:用数组包裹caldata
var ROUNDS = 64; var DELTA = 0x9E3779B9; var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]); var u32 = seed.buffer.slice(0); // 用数组包裹原始值,传递引用 var caldata = [new Uint32Array(u32)[0]]; console.log("pre caldata!", caldata[0]); var key = [0x12345678, 0x87654321, 0xAAAAAAAA, 0xBBBBBBBB]; decipher(caldata, key); function decipher(v, k) { var y = v[0]; var sum = (DELTA * ROUNDS) >>> 0; for (let i = 0; i < ROUNDS; i++) { y -= (((y << 4) >>> 0 ^ (y >>> 5)) + y) ^ (sum + k[(sum >>> 11) & 3]); sum = (sum - DELTA) >>> 0; } v[0] = y; } console.log("caldata!", caldata[0]); // 现在值会正常更新 console.log("Seed", seed);
方案2:直接操作Uint32Array实例(更贴合TypedArray场景)
var ROUNDS = 64; var DELTA = 0x9E3779B9; var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]); // 直接创建Uint32Array实例,本身就是引用类型 var caldataArr = new Uint32Array(seed.buffer.slice(0)); console.log("pre caldata!", caldataArr[0]); var key = [0x12345678, 0x87654321, 0xAAAAAAAA, 0xBBBBBBBB]; decipher(caldataArr, key); function decipher(v, k) { var y = v[0]; var sum = (DELTA * ROUNDS) >>> 0; for (let i = 0; i < ROUNDS; i++) { y -= (((y << 4) >>> 0 ^ (y >>> 5)) + y) ^ (sum + k[(sum >>> 11) & 3]); sum = (sum - DELTA) >>> 0; } v[0] = y; } console.log("caldata!", caldataArr[0]); // 值已更新 console.log("Seed", seed);
二、字节数组转换为Uint32类型的实现
转换时需注意字节序(小端/大端),以下两种方式可按需选择:
方式1:直接用TypedArray转换(依赖主机字节序)
如果字节数组的字节序与主机系统一致,可直接用Uint32Array包裹Uint8Array的缓冲区:
var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]); // 转换结果的字节序由主机系统决定 var uint32Val = new Uint32Array(seed.buffer)[0]; console.log(uint32Val.toString(16)); // 小端主机输出f0862415,大端主机输出152486f0
方式2:用DataView指定字节序(精准可控)
若需要明确指定字节序(比如对应C语言的网络字节序——大端),使用DataView可以精准控制:
var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]); var dv = new DataView(seed.buffer); // 第二个参数false表示大端字节序,true表示小端 var uint32BigEndian = dv.getUint32(0, false); console.log(uint32BigEndian.toString(16)); // 固定输出152486f0 var uint32LittleEndian = dv.getUint32(0, true); console.log(uint32LittleEndian.toString(16)); // 固定输出f0862415
内容的提问来源于stack exchange,提问作者JOSEPH129009
相关产品推荐
相关产品推荐

