My Apple Frontend Interview Experience | Frontend Engineer | Hyderabad
Overview
The candidate interviewed for a Frontend Engineer position at Apple in Hyderabad. The process began with a referral and progressed to a single round of online screening. This assessment evaluated the candidate's skills in problem-solving, JavaScript fundamentals, and React expertise. This document details the questions presented and the candidate's approaches to solving them.
Interview Rounds
Round 1: Online Screening (Platform Assessment)
- Role: Frontend Engineer
- Location: Hyderabad (Remote)
- Duration: 60 minutes
- Format: 10 questions (coding and theoretical)
1. Problem Solving: Fetch Keys from Nested Object / Array
The candidate was required to implement a function to extract keys pointing to primitive values from a nested object or array. The expected output was a flattened array of key paths.
Example Inputs/Outputs:
Input:
{ a: { b: {c:1}, d:2 }, e: 3 }
Output:
["a.b.c", "a.d", "e"]
Input:
[1, {a:2, b: [3,4]}, 5]
Output:
["0", "1.a", "1.b.0", "1.b.1", "2"]
Solution:
/**
* Recursively fetches all the paths (keys) to primitive
values from a nested object or array.
*
* @param {Object|Array} input - The input object or array to traverse.
* @returns {Array} - An array of strings,
each representing the path to a primitive value.
*/
function fetchKeys(input) {
const result = [];
/**
* Recursive helper function to traverse the input object/array.
*
* @param {*} value - The current value being traversed.
* @param {string} path - The current path constructed so far.
*/
function traverse(value, path) {
// Check if the current value is a primitive
// (string, number, boolean, null, etc.)
const isPrimitive = (val) =>
val === null || typeof val !== 'object';
// If it's a primitive, add the path to result and stop recursion
if (isPrimitive(value)) {
result.push(path);
return;
}
// If the value is an array, iterate over each element
if (Array.isArray(value)) {
value.forEach((item, index) => {
// Construct the new path with the index
const newPath = path ? `${path}.${index}` : `${index}`;
traverse(item, newPath); // Recursively traverse each item
});
} else {
// If it's an object, iterate over its keys
for (const key in value) {
if (value.hasOwnProperty(key)) {
// Construct the new path with the key
const newPath = path ? `${path}.${key}` : key;
traverse(value[key], newPath); // Recursively traverse the value
}
}
}
}
// Start traversing from the root of the input
traverse(input, '');
// Return the list of all paths to primitive values
return result;
}
2. Problem Solving: Domain Operation Simulator
The task was to write a function to process domain operations (PUT, GET, COUNT) on a given matrix of strings.
Sample Input:
["PUT", "www.apple.com", "10.20.30.40"]
["PUT", "jobs.apple.com", "10.20.30.50"]
["PUT", "sites.google.com", "142.258.145.693"]
["GET", "sample.com"]
["GET", "www.apple.com"]
["COUNT", "apple.com"]
["COUNT", "com"]
Expected Output:
["404", "10.20.30.40", "2", "3"]
Solution:
/**
* Processes a list of operations related to domain-IP mappings.
*
* Supported operations:
* - PUT domain ip → Stores the domain with the associated IP.
* - GET domain → Retrieves the IP for a given domain or
returns "404" if not found.
* - COUNT domain → Counts how many domains exist for the
exact match or subdomain.
*
* @param {Array} operations - An array of operations,
each as [operationType, domain, ip?].
* @returns {Array} - Result of GET and COUNT operations.
*/
function processDomainOperation(operations) {
const map = {}; // Stores domain → IP mappings
const res = []; // Stores the output results for GET and COUNT
for (const [op, domain, ip] of operations) {
if (op === "PUT" && domain && ip) {
// Store or update the IP for the given domain
map[domain] = ip;
} else if (op === "GET" && domain) {
// Retrieve IP if domain exists, else return "404"
res.push(map[domain] || "404");
} else if (op === "COUNT" && domain) {
// Count exact domain and its subdomains
const count = Object.keys(map).filter(d =>
d === domain || d.endsWith("." + domain)
).length;
res.push(count.toString()); // Store count as a string
}
}
return res;
}
3. Promise and setTimeout Output
The candidate had to determine the output of the following code snippet, demonstrating understanding of the event loop, microtasks, and macrotasks:
const p = new Promise((resolve) => {
console.log(1);
setTimeout(() => {
resolve();
});
});
Promise.resolve().then(() => console.log(2));
setTimeout(() => console.log(3));
p.then(() => console.log(4));
setTimeout(() => console.log(5));
4. Shallow Copy with Spread Operator
This question tested the candidate's knowledge of shallow copying and how nested objects are handled when using the spread operator:
let person1 = {
name: "Anil Kumar",
address: {
line1: "Patna",
line2: "Bihar"
}
};
let person2 = { ...person1 };
person1.name = "Ravi Kumar";
person1.address.line1 = "Hyderabad";
console.log(person1);
console.log(person2);
5. Promise Chain with then and finally
The assessment included a complex promise chain to evaluate the candidate's understanding of promise settlement and the behavior of .finally().
6. this Keyword in JavaScript
This question examined the difference in how this behaves in regular functions versus arrow functions:
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius,
};
console.log(shape.diameter());
console.log(shape.perimeter());
7. Scope and const
The candidate was presented with a scoping question involving const inside a block:
function foo() {
const bar = 'bar';
if (true) {
console.log(bar);
const bar = 'bar1';
}
}
8. Reducer Function and Dispatched Actions
The candidate was asked to determine the final state of a reducer after a series of dispatched actions.
Initial State:
const initialState = {
foo: [1],
switch: false
};
Reducer Snippet:
/**
* Reducer to handle 'foo' state operations.
* Supports setting a value and pushing into an array.
*
* @param {Object} state - The current state object.
* @param {Object} action - The action dispatched.
* @returns {Object} - The updated state.
*/
function FooReducer(state = initialState, action) {
switch (action.type) {
case 'SET FOO':
// Set 'foo' to a new value, and 'switch' to true
return Object.assign({}, state, {
foo: action.foo,
switch: true
});
case 'PUSH FOO':
// Append new item to 'foo' array and toggle 'switch'
return Object.assign({}, state, {
foo: [
...state.foo,
action.foo
],
switch: !state.switch
});
default:
// Return current state if action type is unrecognized
return state;
}
}
Dispatched Actions:
dispatch({ type: 'SET_FOO', foo: [1, 2] });
dispatch({ type: 'PUSH_FOO', foo: 3 });
dispatch({ type: 'PUSH_FOO', foo: 6 });
9. Fetching Data in a Functional Component using Hooks
The question involved choosing the correct implementation of data fetching in a functional component using hooks (useEffect).
10. React Context
This question tested the candidate's understanding of React Context API (version 16.3+).
Key Takeaways
The interview process at Apple for a Frontend Engineer position in Hyderabad heavily emphasizes core JavaScript concepts, problem-solving skills, and React fundamentals. The online screening assessment thoroughly tests a candidate's ability to apply these concepts in practical coding scenarios. A strong understanding of the event loop, promise handling, scope, and state management is crucial for success.
Original Source
This experience was originally published on medium. Support the author by visiting the original post.
Read on medium