JS 对象中使用 WebGL2RenderingContext 常量作键为何报错?
版本 1 报错,是因为对象字面量中的普通属性名不能直接使用 WebGL2RenderingContext.BYTE 这样的成员访问表达式。版本 2 使用计算属性名语法 [expression],先求出常量的值,再用这个值创建属性,实现整数到名称的映射。
这个区别由 JavaScript 的对象字面量语法决定,与 WebGL 常量本身无关。
为什么直接写常量表达式会报错?
问题中的失败写法是:
const WebGlDataTypes = {
WebGL2RenderingContext.BYTE: "BYTE"
};
普通属性定义的键可以是标识符形式的名称、字符串字面量或数值字面量,例如:
const example = {
BYTE: "name key",
"another key": "string key",
5120: "numeric key"
};
WebGL2RenderingContext.BYTE 是读取属性值的表达式,不能直接放在普通属性名的位置。解析器读到点号时,无法按属性定义的语法继续解析,于是报出 Unexpected token '.'。
此时错误发生在语法解析阶段,代码还没有执行读取 WebGL 常量的操作。
为什么加上方括号就能工作?
对象字面量中的 [expression]: value 表示计算属性名。JavaScript 会计算方括号内的表达式,将结果转换为属性键,再赋予对应的值。
const WebGlDataTypes = {
[WebGL2RenderingContext.BYTE]: "BYTE"
};
如果该常量可用,且值为 0x1400,键的计算过程如下:
- 读取
WebGL2RenderingContext.BYTE,得到0x1400,也就是十进制的5120。 - 将数值转换为对象属性键字符串
"5120"。 - 创建值为
"BYTE"的属性。
因此,对这项属性来说,下面几种写法的效果相同:
const a = { [WebGL2RenderingContext.BYTE]: "BYTE" };
const b = { 0x1400: "BYTE" };
const c = { "5120": "BYTE" };
读取时,WebGlDataTypes[WebGL2RenderingContext.BYTE] 也会先计算方括号中的表达式,再将数值转换为属性键,因此能找到同一个属性。
完整的修正代码
保留问题中版本 2 的计算属性名即可:
const WebGlDataTypes = {
[WebGL2RenderingContext.BYTE]: "BYTE", // 0x1400
[WebGL2RenderingContext.UNSIGNED_BYTE]: "UNSIGNED_BYTE", // 0x1401
[WebGL2RenderingContext.SHORT]: "SHORT", // 0x1402
[WebGL2RenderingContext.UNSIGNED_SHORT]: "UNSIGNED_SHORT", // 0x1403
[WebGL2RenderingContext.INT]: "INT", // 0x1404
[WebGL2RenderingContext.UNSIGNED_INT]: "UNSIGNED_INT", // 0x1405
[WebGL2RenderingContext.FLOAT]: "FLOAT" // 0x1406
};
console.log(
WebGL2RenderingContext.BYTE.toString(16) +
" = " +
WebGlDataTypes[WebGL2RenderingContext.BYTE]
);
在这些常量可用的环境中,这条日志的消息内容应为:
1400 = BYTE
原问题预期输出中的 glmodel.js:51 等信息是开发者工具显示的源文件位置,并非这段 console.log 拼接出的字符串。具体文件名和行号取决于代码所在位置。
普通对象查找表为什么可以工作?
问题没有给出另一个普通查找表的具体代码。如果它使用数值字面量或普通名称,例如 { 5120: "BYTE" }、{ BYTE: "BYTE" },这些都是合法的属性定义。
普通属性名不会读取同名变量的值:
const key = 5120;
const byName = { key: "BYTE" };
const byValue = { [key]: "BYTE" };
console.log(byName.key); // "BYTE"
console.log(byName[5120]); // undefined
console.log(byValue[5120]); // "BYTE"
{ key: "BYTE" } 创建的是名为 "key" 的属性;{ [key]: "BYTE" } 会读取变量 key,创建名为 "5120" 的属性。
把原来的表达式改成字符串也能消除语法错误,但会改变查找表的含义:
const table = {
"WebGL2RenderingContext.BYTE": "BYTE"
};
这时键是完整的字符串 "WebGL2RenderingContext.BYTE",不能通过数值 5120 查到它。
使用时注意什么?
对象的属性键是字符串或 Symbol。这里的整数会转成字符串,但仍可使用原有的数值查询写法。如果业务要求严格区分数字键和字符串键,可以使用 Map。
计算属性名会在创建对象时立即求值,因此运行环境必须提供 WebGL2RenderingContext 及相应常量。若 API 不可用,需要另行处理环境支持问题;这与版本 1 的语法错误是两个独立问题。
备注:内容仅供参考。
