Properties, descriptors, prototype chain và class syntax
Property lookup đi qua prototype chain; class là syntax/runtime semantics trên prototype model, không biến JavaScript thành Java.
1. Properties và descriptors
Own property key là String hoặc Symbol. Data descriptor có value/writable; accessor descriptor có get/set; enumerable/configurable quyết định iteration và redefinition. Spread và Object.assign chỉ shallow-copy enumerable own values nhưng có getter/setter invocation semantics khác nhau.
Object.getOwnPropertyDescriptor(obj, "value")
Object.hasOwn(obj, key) // không đi qua prototype
2. Prototype lookup và assignment
Lookup tìm own property rồi đi qua [[Prototype]] chain. Assignment có rules với inherited setter/writable data property; đọc được property không có nghĩa ghi được property. Prototype mutation làm engine optimization khó và input keys đặc biệt có thể gây prototype pollution tại merge/parser boundary.
| Operation | Question cần trả lời |
|---|---|
| Read | Own hay inherited? Getter có side effect không? |
| Write | Setter/inherited writable property hay tạo own property? |
| Enumerate | Enumerable own/inherited và String/Symbol key nào? |
| Merge | Deep hay shallow, key allow-list, prototype pollution guard? |
3. Classes và private state
Methods nằm trên prototype, fields theo instance; static members nằm trên constructor. Private fields dùng branded access và không phải string key có thể enumerate. extends/super có initialization constraints; class method mặc định strict.
- Class syntax không bỏ prototype semantics; method identity thường được share qua prototype.
- Arrow field capture
thistiện cho callback nhưng tạo function mỗi instance. - Composition thường giảm inheritance coupling và dễ test boundary hơn.
4. Immutability và state updates
const chỉ khóa binding, không freeze object. Object.freeze shallow; nested object vẫn mutable nếu không recursively control. Immutable update rõ ownership/state boundary nhưng có allocation cost; Map/Set cần clone hoặc controlled mutation.