0
# Object and Array Utilities
1
2
General-purpose utilities for object manipulation, array operations, and data structure handling. These functions provide safe and consistent ways to work with JavaScript objects and arrays.
3
4
## Capabilities
5
6
### Object Manipulation
7
8
Core utilities for working with objects and their properties.
9
10
```typescript { .api }
11
/**
12
* Alias for Object.assign - merge objects
13
* @param target - Target object to merge into
14
* @param sources - Source objects to merge from
15
* @returns Merged target object
16
*/
17
const extend: typeof Object.assign;
18
19
/**
20
* Define a property on an object with specific descriptor options
21
* @param obj - Object to define property on
22
* @param key - Property key (string or symbol)
23
* @param value - Property value
24
* @param writable - Whether property is writable (default: false)
25
*/
26
function def(
27
obj: object,
28
key: string | symbol,
29
value: any,
30
writable?: boolean
31
): void;
32
```
33
34
### Array Operations
35
36
Utilities for safely manipulating arrays.
37
38
```typescript { .api }
39
/**
40
* Remove element from array by value (mutates array)
41
* Uses indexOf to find element, then splices it out
42
* @param arr - Array to remove element from
43
* @param el - Element to remove
44
*/
45
function remove<T>(arr: T[], el: T): void;
46
47
/**
48
* Invoke array of functions with provided arguments
49
* Safely calls each function in the array with the same arguments
50
* @param fns - Array of functions to invoke
51
* @param arg - Arguments to pass to each function
52
*/
53
function invokeArrayFns(fns: Function[], ...arg: any[]): void;
54
```
55
56
### Value Comparison
57
58
Utilities for comparing values and detecting changes.
59
60
```typescript { .api }
61
/**
62
* Compare if value has changed, accounting for NaN equality
63
* Uses Object.is for comparison (handles NaN and -0/+0 correctly)
64
* @param value - New value
65
* @param oldValue - Old value to compare against
66
* @returns True if values are different
67
*/
68
function hasChanged(value: any, oldValue: any): boolean;
69
```
70
71
### Number Conversion Utilities
72
73
Utilities for converting values to numbers with different behaviors.
74
75
```typescript { .api }
76
/**
77
* Loose number conversion - used for .number modifier in v-model
78
* "123-foo" will be parsed to 123, "abc" remains "abc"
79
* @param val - Value to convert
80
* @returns Parsed number or original value if not numeric
81
*/
82
function looseToNumber(val: any): any;
83
84
/**
85
* Strict number conversion for number-like strings only
86
* "123-foo" will be returned as-is, "123" becomes number 123
87
* @param val - Value to convert
88
* @returns Number if val is numeric string, otherwise original value
89
*/
90
function toNumber(val: any): any;
91
```
92
93
### Constants and No-op Functions
94
95
Commonly used constant values and utility functions.
96
97
```typescript { .api }
98
/**
99
* Empty object - frozen in development, regular in production
100
*/
101
const EMPTY_OBJ: { readonly [key: string]: any };
102
103
/**
104
* Empty array - frozen in development, regular in production
105
*/
106
const EMPTY_ARR: readonly never[];
107
108
/**
109
* No-operation function that returns undefined
110
*/
111
const NOOP: () => void;
112
113
/**
114
* Function that always returns false
115
*/
116
const NO: () => false;
117
```
118
119
**Usage Examples:**
120
121
```typescript
122
import {
123
extend, def, remove, invokeArrayFns, hasChanged,
124
EMPTY_OBJ, EMPTY_ARR, NOOP, NO
125
} from "@vue/shared";
126
127
// Object merging with extend
128
const target = { a: 1, b: 2 };
129
const source1 = { b: 3, c: 4 };
130
const source2 = { c: 5, d: 6 };
131
132
const merged = extend(target, source1, source2);
133
console.log(merged); // { a: 1, b: 3, c: 5, d: 6 }
134
console.log(merged === target); // true (mutates target)
135
136
// Property definition
137
const obj = {};
138
def(obj, "hiddenProp", "secret", false); // not writable
139
def(obj, "writableProp", "public", true); // writable
140
141
console.log(obj.hiddenProp); // "secret"
142
console.log(Object.getOwnPropertyDescriptor(obj, "hiddenProp"));
143
// { value: "secret", writable: false, enumerable: false, configurable: true }
144
145
// Array element removal
146
const items = ["a", "b", "c", "b", "d"];
147
remove(items, "b"); // Removes first occurrence
148
console.log(items); // ["a", "c", "b", "d"]
149
150
remove(items, "x"); // No effect if element not found
151
console.log(items); // ["a", "c", "b", "d"]
152
153
// Function array invocation
154
const callbacks = [
155
(msg: string) => console.log(`Callback 1: ${msg}`),
156
(msg: string) => console.log(`Callback 2: ${msg}`),
157
(msg: string) => console.log(`Callback 3: ${msg}`)
158
];
159
160
invokeArrayFns(callbacks, "Hello World");
161
// Logs:
162
// "Callback 1: Hello World"
163
// "Callback 2: Hello World"
164
// "Callback 3: Hello World"
165
166
// Empty callback arrays are handled safely
167
invokeArrayFns([], "message"); // No effect
168
169
// Change detection
170
console.log(hasChanged(1, 1)); // false
171
console.log(hasChanged(1, 2)); // true
172
console.log(hasChanged(NaN, NaN)); // false (Object.is handles NaN correctly)
173
console.log(hasChanged(0, -0)); // true (Object.is distinguishes -0/+0)
174
console.log(hasChanged(null, undefined)); // true
175
176
// Using constants
177
const defaultConfig = extend({}, EMPTY_OBJ, { theme: "dark" });
178
console.log(defaultConfig); // { theme: "dark" }
179
180
const emptyList = EMPTY_ARR.slice(); // Create new array from empty template
181
console.log(emptyList); // []
182
183
// No-op functions
184
const cleanup = NOOP; // Safe default cleanup function
185
const isDisabled = NO; // Function that always returns false
186
187
// Property definition with symbols
188
const secretKey = Symbol("secret");
189
def(obj, secretKey, "hidden value");
190
console.log(obj[secretKey]); // "hidden value"
191
192
// Number conversion utilities
193
console.log(looseToNumber("123")); // 123
194
console.log(looseToNumber("123.45")); // 123.45
195
console.log(looseToNumber("123-foo")); // 123 (parses what it can)
196
console.log(looseToNumber("abc")); // "abc" (returns as-is)
197
198
console.log(toNumber("123")); // 123
199
console.log(toNumber("123.45")); // 123.45
200
console.log(toNumber("123-foo")); // "123-foo" (returns as-is)
201
console.log(toNumber("abc")); // "abc" (returns as-is)
202
```
203
204
### Object Safety Patterns
205
206
```typescript
207
// Safe object merging patterns
208
function mergeConfig(userConfig: any) {
209
// Always start with empty object to avoid mutations
210
return extend({}, defaultConfig, userConfig);
211
}
212
213
// Safe property definition
214
function defineHiddenProperty(obj: object, key: string, value: any) {
215
def(obj, key, value, false); // Non-writable by default
216
}
217
218
// Safe array cleanup
219
function cleanupCallbacks(callbacks: Function[]) {
220
// Remove all callbacks
221
callbacks.splice(0, callbacks.length);
222
}
223
```
224
225
### Performance Characteristics
226
227
- **extend**: Direct alias to `Object.assign` - native performance
228
- **remove**: O(n) operation using `indexOf` + `splice`
229
- **def**: Uses `Object.defineProperty` with optimized defaults
230
- **hasChanged**: Uses `Object.is` which is optimized for equality checking
231
- **invokeArrayFns**: Simple loop, no array methods overhead
232
233
### Development vs Production Behavior
234
235
- **EMPTY_OBJ**: Frozen in development to catch mutations, regular object in production
236
- **EMPTY_ARR**: Frozen in development to catch mutations, regular array in production
237
- This helps catch bugs during development while maintaining performance in production
238
239
### Integration Patterns
240
241
These utilities are used throughout Vue's internals:
242
243
- **Component Props**: `extend` for merging prop defaults
244
- **Event Systems**: `invokeArrayFns` for calling multiple event handlers
245
- **Reactivity**: `hasChanged` for detecting when reactive values change
246
- **Property Definition**: `def` for defining non-enumerable properties on reactive objects