Objects¶
Objects are dynamic collections of key-value pairs. They store structured data and can be created, modified, and accessed at runtime.
Object Creation¶
Object Literal Syntax¶
Example:
Empty Object¶
Keys Must Be Strings¶
// CORRECT: String keys
object = {
"name": "Alice",
"age": 30,
"123": "numeric string key" // numeric-looking keys are quoted too
};
// ERROR: Keys without quotes
// object = {
// name: "Alice", // ERROR
// age: 30 // ERROR
// };
Values Can Be Any Type¶
mixed = {
"string": "text",
"number": 42,
"boolean": true,
"null": null,
"date": $Now(),
"array": [1, 2, 3],
"object": {
"nested": "value"
}
};
Property Access¶
Dot Notation¶
Accessing Nested Properties¶
person = {
"name": "Alice",
"address": {
"street": "123 Main St",
"city": "Springfield",
"zip": "12345"
}
};
city = person.address.city; // "Springfield"
zip = person.address.zip; // "12345"
Accessing Non-Existent Properties¶
Returns null:
object = { "name": "Alice" };
value = object.age; // null (doesn't exist)
nested = object.address.city; // ERROR: Cannot access property of null
Safe access:
Dynamic Property Access¶
Using $GetValue¶
Get property value by name:
object = {
"firstName": "John",
"lastName": "Doe"
};
propertyName = "firstName";
value = $GetValue(object, propertyName); // "John"
Nested Property Access¶
person = {
"name": "Alice",
"contact": {
"email": "alice@example.com"
}
};
// Nested access with dot notation
email = $GetValue(person, "contact.email"); // "alice@example.com"
Using $SetValue¶
Set property value by name:
Creating New Properties Dynamically¶
policy = {};
$SetValue(policy, "number", "POL-001");
$SetValue(policy, "premium", 1200);
$SetValue(policy, "coverage", 250000);
// policy is now:
// {
// "number": "POL-001",
// "premium": 1200,
// "coverage": 250000
// }
Modifying Objects¶
Adding Properties¶
Using .AddProperty()¶
customer = {
"firstName": "John",
"lastName": "Doe"
};
customer = customer.AddProperty("email", "john@example.com");
email = customer.email; // "john@example.com"
Direct Assignment¶
object = {};
object.name = "Alice"; // ERROR: Cannot assign via dot notation
// Use .AddProperty() or $SetValue() instead
Note: EverSharp does not support property assignment via dot notation. Use .AddProperty() or $SetValue().
Updating Properties¶
customer = {
"name": "Alice",
"age": 30
};
// Update using $SetValue
$SetValue(customer, "age", 31);
age = customer.age; // 31
Removing Properties¶
EverSharp does not have a built-in way to remove properties. Workaround:
// Create new object without unwanted property
original = {
"name": "Alice",
"age": 30,
"temp": "remove this"
};
// Manual copy without 'temp'
filtered = {
"name": original.name,
"age": original.age
};
Working with Objects¶
Copying Objects¶
Objects are reference types. Assignment creates a reference, not a copy:
original = {
"name": "Alice",
"age": 30
};
reference = original;
$SetValue(reference, "age", 31);
age1 = original.age; // 31 (modified)
age2 = reference.age; // 31 (same object)
Shallow copy:
function shallowCopy(obj) {
copy = {};
// Manually copy each property
copy = copy.AddProperty("name", obj.name);
copy = copy.AddProperty("age", obj.age);
return copy;
}
Checking for Properties¶
object = {
"name": "Alice",
"age": 30,
"email": null
};
// Check whether a property key exists
hasName = object.HasProperty("name"); // true
hasAge = $HasProperty(object, "age"); // true
hasEmail = object.HasProperty("email"); // true
hasPhone = $HasProperty(object, "phone"); // false
// If you need to know whether the stored value is non-null, check the value explicitly
emailValue = $GetValue(object, "email");
hasNonNullEmail = emailValue != null; // false
Iterating Over Properties¶
EverSharp doesn't have built-in property iteration. Properties must be accessed by known names.
Nested Objects¶
Creating Nested Structures¶
policy = {
"number": "POL-001",
"premium": 1200,
"customer": {
"firstName": "John",
"lastName": "Doe",
"age": 35,
"address": {
"street": "123 Main St",
"city": "Springfield",
"state": "IL",
"zip": "62701"
}
},
"coverage": {
"amount": 250000,
"type": "Term Life",
"years": 20
}
};
Accessing Nested Data¶
customerName = policy.customer.firstName + " " + policy.customer.lastName;
city = policy.customer.address.city;
coverageType = policy.coverage.type;
Safe Nested Access¶
// Unsafe: Will error if intermediate property is null
// city = policy.customer.address.city;
// Safe: Check each level
if (policy != null && policy.customer != null && policy.customer.address != null) {
city = policy.customer.address.city;
}
Modifying Nested Properties¶
policy = {
"number": "POL-001",
"customer": {
"name": "Alice"
}
};
// Update nested property
$SetValue(policy.customer, "age", 30);
age = policy.customer.age; // 30
Objects in Arrays¶
Array of Objects¶
customers = [
{ "name": "Alice", "age": 30 },
{ "name": "Bob", "age": 25 },
{ "name": "Charlie", "age": 35 }
];
// Access by index
firstCustomer = customers[0];
name = firstCustomer.name; // "Alice"
// Or combined
name = customers[0].name; // "Alice"
Filtering Objects¶
customers = [
{ "name": "Alice", "age": 30, "isActive": true },
{ "name": "Bob", "age": 25, "isActive": false },
{ "name": "Charlie", "age": 35, "isActive": true }
];
// Get active customers
active = customers.Filter((c) => c.isActive);
// Get customers over 30
over30 = customers.Filter((c) => c.age > 30);
Mapping Objects¶
// Extract property
names = customers.Map((c) => c.name);
// ["Alice", "Bob", "Charlie"]
// Transform objects
simplified = customers.Map((c) => {
return {
"name": c.name,
"status": c.isActive ? "Active" : "Inactive"
};
});
Sorting Objects¶
// Sort by age
sortedByAge = customers.OrderBy((c) => c.age);
// Sort by name (descending)
sortedByName = customers.OrderByDescending((c) => c.name);
Common Patterns¶
Pattern 1: Object Builder¶
function createCustomer(firstName, lastName, age, email) {
customer = {};
customer = customer.AddProperty("firstName", firstName);
customer = customer.AddProperty("lastName", lastName);
customer = customer.AddProperty("age", age);
customer = customer.AddProperty("email", email);
customer = customer.AddProperty("createdDate", $Today());
customer = customer.AddProperty("isActive", true);
return customer;
}
customer = createCustomer("John", "Doe", 35, "john@example.com");
Pattern 2: Object Validation¶
function validateCustomer(customer) {
errors = [];
if (customer == null) {
errors.Push("Customer is null");
return errors;
}
if (customer.firstName == null || customer.firstName == "") {
errors.Push("First name required");
}
if (customer.age == null || customer.age < 18) {
errors.Push("Must be 18 or older");
}
if (customer.email == null || !customer.email.Contains("@")) {
errors.Push("Valid email required");
}
return errors;
}
Pattern 3: Object Transformation¶
function transformPolicyForExport(policy) {
return {
"policyNumber": policy.number,
"customerName": policy.customer.firstName + " " + policy.customer.lastName,
"monthlyPremium": $Round(policy.premium / 12, 2),
"coverageAmount": "$" + policy.coverage.ToString(),
"status": policy.isActive ? "Active" : "Inactive"
};
}
policies = getPolicies();
exports = policies.Map((p) => transformPolicyForExport(p));
Pattern 4: Merging Objects¶
function merge(obj1, obj2) {
result = {};
// Copy from obj1 (manually, property by property)
result = result.AddProperty("name", obj1.name);
result = result.AddProperty("age", obj1.age);
// Copy from obj2
result = result.AddProperty("email", obj2.email);
result = result.AddProperty("phone", obj2.phone);
return result;
}
// Or use object literal
function merge(obj1, obj2) {
return {
"name": obj1.name,
"age": obj1.age,
"email": obj2.email,
"phone": obj2.phone
};
}
Pattern 5: Default Values¶
function getCustomerEmail(customer) {
if (customer == null) {
return null;
}
email = customer.email;
if (email == null || email == "") {
return "no-email@example.com";
}
return email;
}
// Or using ternary
function getCustomerEmail(customer) {
return customer != null && customer.email != null && customer.email != "" ? customer.email : "no-email@example.com";
}
Pattern 6: Nested Object Creation¶
function createPolicy(number, premium, customerData, coverageData) {
return {
"number": number,
"premium": premium,
"isActive": true,
"createdDate": $Today(),
"customer": {
"firstName": customerData.firstName,
"lastName": customerData.lastName,
"age": customerData.age,
"contact": {
"email": customerData.email,
"phone": customerData.phone
}
},
"coverage": {
"amount": coverageData.amount,
"type": coverageData.type,
"term": coverageData.term
}
};
}
Objects as Function Returns¶
Returning Single Object¶
function createResult(success, message) {
return {
"success": success,
"message": message,
"timestamp": $Now()
};
}
result = createResult(true, "Operation completed");
if (result.success) {
$Log(result.message);
}
Returning Multiple Values¶
function calculatePremium(coverage, age) {
basePremium = coverage * 0.001;
if (age < 25) {
basePremium *= 1.5;
} else if (age > 65) {
basePremium *= 1.25;
}
monthlyPremium = basePremium / 12;
return {
"annual": $Round(basePremium, 2),
"monthly": $Round(monthlyPremium, 2),
"ageCategory": age < 25 ? "young" : (age > 65 ? "senior" : "standard")
};
}
premium = calculatePremium(250000, 30);
annual = premium.annual;
monthly = premium.monthly;
Error Handling Pattern¶
function processPayment(amount) {
if (amount <= 0) {
return {
"success": false,
"error": "Invalid amount",
"errorCode": "INVALID_AMOUNT"
};
}
// Process payment
transactionId = generateTransactionId();
return {
"success": true,
"transactionId": transactionId,
"processedAmount": amount,
"timestamp": $Now()
};
}
result = processPayment(100);
if (result.success) {
$Log("Payment successful: " + result.transactionId);
} else {
$Log("Error: " + result.error);
}
Best Practices¶
1. Use Descriptive Property Names¶
// Less clear
obj = { "p": 1200, "c": 250000 };
// Clear
policy = { "premium": 1200, "coverage": 250000 };
2. Group Related Data¶
// Less organized
customer = {
"name": "John",
"street": "123 Main",
"city": "Springfield",
"email": "john@example.com"
};
// Better organized
customer = {
"name": "John",
"address": {
"street": "123 Main",
"city": "Springfield"
},
"contact": {
"email": "john@example.com"
}
};
3. Check for Null Before Access¶
// Unsafe
city = policy.customer.address.city;
// Safe
if (policy != null && policy.customer != null && policy.customer.address != null) {
city = policy.customer.address.city;
}
4. Use Consistent Structure¶
// Consistent object structure
function createResponse(success, data, error) {
return {
"success": success,
"data": data,
"error": error,
"timestamp": $Now()
};
}
// Always same structure
successResult = createResponse(true, { "id": 123 }, null);
errorResult = createResponse(false, null, "Not found");
5. Validate Object Structure¶
function isValidCustomer(obj) {
if (obj == null) return false;
if (obj.firstName == null) return false;
if (obj.lastName == null) return false;
if (obj.age == null) return false;
return true;
}
if (isValidCustomer(customer)) {
// Safe to use
}
Common Mistakes¶
Mistake 1: Assuming Property Assignment Works¶
object = { "name": "Alice" };
// ERROR: Cannot assign property this way
// object.age = 30;
// CORRECT: Use .AddProperty() or $SetValue()
object = object.AddProperty("age", 30);
// Or
$SetValue(object, "age", 30);
Mistake 2: Not Checking for Null¶
// ERROR: If customer is null, this fails
name = customer.firstName;
// CORRECT
if (customer != null) {
name = customer.firstName;
}
Mistake 3: Using Unquoted Keys¶
// ERROR: Keys must be strings
// object = { name: "Alice" };
// CORRECT
object = { "name": "Alice" };
Mistake 4: Expecting Shallow Copy on Assignment¶
original = { "name": "Alice" };
copy = original; // Reference, not copy!
$SetValue(copy, "name", "Bob");
name = original.name; // "Bob" (same object)
Mistake 5: Accessing Missing Nested Properties¶
customer = { "name": "Alice" };
// ERROR: address is null
// city = customer.address.city;
// CORRECT
if (customer.address != null) {
city = customer.address.city;
}
Advanced Examples¶
Example 1: Complex Data Structure¶
policy = {
"number": "POL-001",
"status": "active",
"dates": {
"issued": $ToDate("2024-01-01"),
"effective": $ToDate("2024-01-15"),
"expires": $ToDate("2025-01-15")
},
"customer": {
"id": "CUST-123",
"personal": {
"firstName": "John",
"lastName": "Doe",
"birthDate": $ToDate("1988-05-15"),
"ssn": "***-**-1234"
},
"contact": {
"email": "john.doe@example.com",
"phone": "(555) 123-4567",
"address": {
"street": "123 Main Street",
"city": "Springfield",
"state": "IL",
"zip": "62701"
}
}
},
"coverage": {
"type": "Term Life",
"amount": 250000,
"term": 20,
"beneficiaries": [{ "name": "Jane Doe", "relationship": "Spouse", "percentage": 100 }]
},
"premium": {
"annual": 1200,
"frequency": "monthly",
"nextDue": $ToDate("2024-02-15")
}
};
Example 2: Data Aggregation¶
function aggregateSales(orders) {
result = {
"totalOrders": orders.Length,
"totalRevenue": 0,
"averageOrderValue": 0,
"largestOrder": 0,
"byCategory": {}
};
// Calculate totals
result.totalRevenue = orders.ReduceToNum((acc, o) => acc + o.total);
result.averageOrderValue = $Round(result.totalRevenue / result.totalOrders, 2);
result.largestOrder = orders.ReduceToNum((acc, o) => (o.total > acc ? o.total : acc));
return result;
}
Example 3: Configuration Object¶
config = {
"pricing": {
"baseRate": 0.001,
"ageFactors": {
"under25": 1.5,
"standard": 1.0,
"over65": 1.25
},
"riskFactors": {
"low": 0.9,
"standard": 1.0,
"high": 1.3
}
},
"limits": {
"minCoverage": 50000,
"maxCoverage": 1000000,
"minAge": 18,
"maxAge": 75
},
"discounts": {
"loyaltyYears": [
{ "years": 5, "discount": 0.05 },
{ "years": 10, "discount": 0.1 },
{ "years": 15, "discount": 0.15 }
]
}
};
function calculatePremium(coverage, age, risk, years) {
baseRate = config.pricing.baseRate;
ageFactor =
age < 25
? config.pricing.ageFactors.under25
: (age > 65
? config.pricing.ageFactors.over65
: config.pricing.ageFactors.standard);
riskFactor = $GetValue(config.pricing.riskFactors, risk);
premium = coverage * baseRate * ageFactor * riskFactor;
return $Round(premium, 2);
}
Next Steps¶
- Learn about arrays: Arrays
- Explore array methods with objects: Native Functions - Arrays
- See practical examples: Object Manipulation
- Understand dynamic access: Native Functions - Utilities