Frontend Development 19 min read

Understanding Object.keys Order and V8 Property Handling to Fix a wxml2canvas Bug

This article explains why a WeChat mini‑program’s share card lost its QR code due to incorrect assumptions about Object.keys ordering, dives into the ECMAScript specification and V8’s internal property storage, and shows how to modify wxml2canvas to correctly sort elements and avoid the bug.

IT Xianyu
IT Xianyu
IT Xianyu
Understanding Object.keys Order and V8 Property Handling to Fix a wxml2canvas Bug

One day after a release a senior developer reported that the QR code at the bottom of a generated share card was missing, while the same card worked on other devices. The project uses the wxml2canvas library, which is outdated and the root cause of the bug.

The article walks through the debugging process, shows how Object.keys() ordering is defined in the ECMAScript spec, and explains why integer keys are sorted numerically while non‑integer keys keep their creation order.

TL;DR

The bug occurs because wxml2canvas assumes Object.keys() returns keys in creation order, but when keys are positive integers they are sorted ascending, causing the drawing order to be wrong.

How the bug is produced.

How to fix the bug.

What order Object.keys() returns.

How V8 handles object properties.

To reproduce the bug, the library builds a sorted object where each key is a node’s top value. Because integer keys are sorted, the drawing sequence becomes incorrect.

const sorted = {};
sorted[300] = {};
sorted[200] = {};
sorted[100] = {};
console.log(Object.keys(sorted)); // ['100','200','300']

When a floating‑point key is added, the order changes:

const sorted = {};
sorted[300] = {};
sorted[100] = {};
sorted[200] = {};
sorted[50.5] = {};
console.log(Object.keys(sorted)); // ['100','200','300','50.5']

The fix is to force all keys to be floating‑point numbers before sorting:

Object.keys(sorted).sort((a,b)=>a-b).forEach((top, topIndex)=>{
  // do something
});

According to the ECMAScript spec, Object.keys() ultimately uses the internal method [[OwnPropertyKeys]] , which returns keys in three phases: array‑index keys sorted numerically, then string keys in creation order, then Symbol keys in creation order.

Therefore, only valid array indices (positive integers) are sorted; negative numbers and floating‑point numbers are treated as strings and keep their insertion order.

V8 improves property access by separating properties into "elements" (array‑index keys) and "properties" (string keys). Elements are stored in a linear structure called "fast properties". Regular properties are also stored linearly but may be moved to a dictionary ("slow properties") when the object becomes large or undergoes many additions/deletions.

V8 also creates hidden classes to describe an object’s shape; objects with identical shapes share the same hidden class. When properties are added or removed, a new hidden class is generated.

To force V8 to use fast properties, developers can use helper functions such as toFastProperties (shown in the article) or the to-fast-properties npm package.

References:

wxml2canvas repository

ECMAScript spec for OwnPropertyKeys

Fast properties in V8

Various MDN and blog articles cited in the original text.

END – If you enjoyed the article, please share, like, and star the author’s profile for more updates.

debuggingfrontendJavaScriptV8Object.keysproperty orderwxml2canvas
IT Xianyu
Written by

IT Xianyu

We share common IT technologies (Java, Web, SQL, etc.) and practical applications of emerging software development techniques. New articles are posted daily. Follow IT Xianyu to stay ahead in tech. The IT Xianyu series is being regularly updated.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.