0
# Traversal Context
1
2
When using callback functions with traversal methods (`forEach`, `map`, `reduce`), the `this` context provides extensive information about the current node and methods for modifying the traversal behavior.
3
4
## Context Properties
5
6
The callback's `this` object contains the following properties that describe the current traversal state:
7
8
### Node Information
9
10
```javascript { .api }
11
// Current node being visited
12
this.node // Current node value
13
this.node_ // Original node value (before modifications)
14
15
// Path information
16
this.path // Array of keys from root to current node
17
this.key // Property key of current node in its parent (undefined for root)
18
19
// Hierarchy information
20
this.parent // Parent context object (undefined for root)
21
this.parents // Array of all parent contexts
22
this.keys // Array of enumerable keys of current node (null for non-objects)
23
this.removedKeys // Object tracking keys removed from parent during traversal
24
```
25
26
### State Flags
27
28
```javascript { .api }
29
// Position flags
30
this.isRoot // boolean - Whether current node is the root
31
this.notRoot // boolean - Whether current node is not the root
32
this.isLeaf // boolean - Whether current node has no children
33
this.notLeaf // boolean - Whether current node has children
34
this.level // number - Depth of current node (0 for root)
35
36
// Traversal state
37
this.circular // Parent context if node creates circular reference, null otherwise
38
this.isFirst // boolean - Whether this is first child of parent (set during traversal)
39
this.isLast // boolean - Whether this is last child of parent (set during traversal)
40
```
41
42
## Context Methods
43
44
The context provides methods for modifying nodes and controlling traversal flow:
45
46
### Node Modification
47
48
```javascript { .api }
49
/**
50
* Update the current node value
51
* @param {*} value - New value for the node
52
* @param {boolean} [stopHere=false] - Whether to stop traversing this branch
53
*/
54
this.update(value, stopHere)
55
56
/**
57
* Remove current node (splice from arrays, delete from objects)
58
* @param {boolean} [stopHere=false] - Whether to stop traversing this branch
59
*/
60
this.remove(stopHere)
61
62
/**
63
* Delete current node (uses delete operator even on arrays)
64
* @param {boolean} [stopHere=false] - Whether to stop traversing this branch
65
*/
66
this.delete(stopHere)
67
```
68
69
### Traversal Control
70
71
```javascript { .api }
72
/**
73
* Register function to call before traversing children of current node
74
* @param {Function} fn - Function to call before children
75
*/
76
this.before(fn)
77
78
/**
79
* Register function to call after traversing children of current node
80
* @param {Function} fn - Function to call after children
81
*/
82
this.after(fn)
83
84
/**
85
* Register function to call before each child of current node
86
* @param {Function} fn - Function to call before each child
87
*/
88
this.pre(fn)
89
90
/**
91
* Register function to call after each child of current node
92
* @param {Function} fn - Function to call after each child
93
*/
94
this.post(fn)
95
96
/**
97
* Stop the entire traversal immediately
98
*/
99
this.stop()
100
101
/**
102
* Skip traversing children of the current node
103
*/
104
this.block()
105
```
106
107
## Usage Examples
108
109
### Basic Context Usage
110
111
```javascript
112
const traverse = require('traverse');
113
114
const obj = { a: { b: { c: 1 } }, d: [2, 3] };
115
116
traverse(obj).forEach(function (x) {
117
console.log('Path:', this.path);
118
console.log('Key:', this.key);
119
console.log('Value:', this.node);
120
console.log('Is leaf:', this.isLeaf);
121
console.log('Level:', this.level);
122
console.log('---');
123
});
124
125
// Output shows path and context info for each node:
126
// Path: [] Key: undefined Value: {a: {...}, d: [...]} Is leaf: false Level: 0
127
// Path: ['a'] Key: 'a' Value: {b: {...}} Is leaf: false Level: 1
128
// Path: ['a','b'] Key: 'b' Value: {c: 1} Is leaf: false Level: 2
129
// etc...
130
```
131
132
### Node Modification
133
134
```javascript
135
const traverse = require('traverse');
136
137
// Transform values based on context
138
const obj = {
139
numbers: [1, 2, 3],
140
nested: { value: 4 }
141
};
142
143
traverse(obj).forEach(function (x) {
144
if (typeof x === 'number') {
145
// Double numbers at even levels, triple at odd levels
146
const multiplier = this.level % 2 === 0 ? 2 : 3;
147
this.update(x * multiplier);
148
}
149
});
150
```
151
152
### Conditional Removal
153
154
```javascript
155
const traverse = require('traverse');
156
157
const obj = {
158
items: [1, null, 2, undefined, 3, '', 4],
159
nested: { a: null, b: 5, c: undefined }
160
};
161
162
// Remove falsy values
163
traverse(obj).forEach(function (x) {
164
if (!x && x !== 0 && x !== false) {
165
this.remove();
166
}
167
});
168
```
169
170
### Array vs Object Deletion
171
172
```javascript
173
const traverse = require('traverse');
174
175
const obj = {
176
arr: ['a', 'remove', 'b'],
177
obj: { keep: 1, remove: 2, keep2: 3 }
178
};
179
180
traverse(obj).forEach(function (x) {
181
if (x === 'remove' || x === 2) {
182
if (Array.isArray(this.parent.node)) {
183
this.remove(); // Splice from array
184
} else {
185
this.delete(); // Delete from object
186
}
187
}
188
});
189
```
190
191
### Traversal Control
192
193
```javascript
194
const traverse = require('traverse');
195
196
const obj = {
197
public: { data: 1, more: 2 },
198
private: { secret: 'hidden', confidential: 'data' },
199
normal: 'value'
200
};
201
202
// Skip traversing private sections
203
traverse(obj).forEach(function (x) {
204
if (this.key === 'private') {
205
console.log('Skipping private section');
206
this.block(); // Don't traverse children
207
} else {
208
console.log('Processing:', this.path, this.node);
209
}
210
});
211
```
212
213
### Before/After Hooks
214
215
```javascript
216
const traverse = require('traverse');
217
218
const obj = { a: { b: [1, 2] }, c: 3 };
219
220
traverse(obj).forEach(function (x) {
221
if (typeof x === 'object' && x !== null) {
222
this.before(function (node) {
223
console.log('About to traverse:', this.path);
224
});
225
226
this.after(function (node) {
227
console.log('Finished traversing:', this.path);
228
});
229
}
230
});
231
```
232
233
### Circular Reference Detection
234
235
```javascript
236
const traverse = require('traverse');
237
238
const obj = { name: 'parent' };
239
obj.self = obj; // Create circular reference
240
241
traverse(obj).forEach(function (x) {
242
if (this.circular) {
243
console.log('Found circular reference at path:', this.path);
244
console.log('Points back to path:', this.circular.path);
245
// this.circular is the parent context that creates the cycle
246
}
247
});
248
```
249
250
### Path-Based Operations
251
252
```javascript
253
const traverse = require('traverse');
254
255
const config = {
256
database: { host: 'localhost', port: 5432 },
257
cache: { host: 'redis-server', port: 6379 },
258
api: { version: 'v1', timeout: 5000 }
259
};
260
261
// Update all host values to production hosts
262
traverse(config).forEach(function (x) {
263
if (this.key === 'host' && this.path.length === 2) {
264
const service = this.path[0]; // 'database', 'cache', etc.
265
this.update(`prod-${service}.example.com`);
266
}
267
});
268
```
269
270
## Advanced Context Usage
271
272
### Custom Property Ordering
273
274
```javascript
275
const traverse = require('traverse');
276
277
const obj = { c: 1, a: 2, b: 3 };
278
279
traverse(obj).forEach(function (x) {
280
if (typeof x === 'object' && x !== null) {
281
this.before(function () {
282
// Sort keys alphabetically before traversing
283
if (this.keys) {
284
this.keys.sort();
285
}
286
});
287
}
288
});
289
```
290
291
### Conditional Stopping
292
293
```javascript
294
const traverse = require('traverse');
295
296
let found = false;
297
const obj = {
298
level1: {
299
level2: {
300
target: 'FOUND',
301
other: 'data'
302
}
303
}
304
};
305
306
traverse(obj).forEach(function (x) {
307
if (x === 'FOUND') {
308
console.log('Found target at:', this.path);
309
found = true;
310
this.stop(); // Stop entire traversal
311
}
312
});
313
```