1️⃣ EventEmitter
Задача: реализовать EventEmitter с подпиской, отпиской и вызовом событий.
class EventEmitter {
constructor() {}
subscribe(event, callback) {
this.events[event].push(callback);
}
unsubscribe(event, callback) {
this.events[event] =
this.events[event].filter(cb => cb !== callback);
}
fire(event, payload) {
this.events[event].forEach(callback => callback(payload));
}
}
const eventEmitter = new EventEmitter();
const callback = (payload) =>
console.log(`Callback catch event "test" with payload: ${JSON.stringify(payload)}`);2️⃣ JavaScript Event Loop
Задача: определить порядок вывода в консоль + объяснить Event Loop.
console.log('start');
setTimeout(() => console.log('timeout'), 0);
new Promise((resolve, reject) => {
console.log('promise');
reject();
})
.then(() => console.log('promise'))
.catch(() => console.log('promise1'))
.catch(() => console.log('promise2'))
.then(() => console.log('promise3'))
.then(() => console.log('promise4'));
console.log('final');3️⃣ TypeScript / Runtime
Задача: объяснить поведение instanceof и различия runtime vs compile-time.
interface User {}
class AdminUser implements User {
name: string;
role: string;
constructor(name: string) {
this.name = name;
this.role = "admin";
}
}
function checkGrants(user: User): boolean {
return user instanceof AdminUser;
}
const adminUser2: AdminUser = {
name: "admin",
role: "admin",
};
console.log(checkGrants(new AdminUser("admin"))); // true
console.log(checkGrants(adminUser2)); // false4️⃣ React Refactoring
Задача: провести рефакторинг компонента интернет-магазина.
export default function App() {
const [query, setQuery] = useState("");
const [products, setProducts] = useState([]);
const [filtered, setFiltered] = useState<Product[]>([]);
const [cartCount, setCartCount] = useState(0);
const [cartSum, setSumCount] = useState(0);
const onAdd = useCallback((p: Product) => {
setCartCount(cartCount + 1);
setSumCount(cartSum + p.price);
}, []);
const clear = () => {
setCartCount(0);
setSumCount(0);
};
useEffect(() => {
fetchProducts(query).then((res) => {
setProducts(res.items);
});
}, [query]);
useEffect(() => {
setFiltered(products.filter((p) => p.price >= 0));
}, [products]);
return (
<div>
<div style={{ fontFamily: "sans-serif", maxWidth: 720, margin: "20px auto" }}>
<h2>Shop</h2>
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
<span>Cart: {cartCount}</span>
<span>Sum: ${cartSum}</span>
<div
style={{ backgroundColor: "#808080", padding: "8px" }}
onClick={() => clear()}
>
Clear
</div>
</div>
<div style={{ marginTop: 12, border: "1px solid #eee", borderRadius: 8 }}>
{filtered.map((product) => (
<>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div>
<b>{product.name}</b>
<div style={{ fontSize: 12, opacity: 0.7 }}>
${product.price}
</div>
</div>
<div style={{ display: "flex" }}>
<div
style={{ backgroundColor: "#808080", padding: "8px" }}
onClick={() => onAdd(product)}
>
Add
</div>
</div>
</div>
<hr />
</>
))}
</div>
<h6>Copyrite and footer</h6>
</div>
</div>
);
}