🚀 Giriş
Modern JavaScript dünyası sürekli gelişiyor. ES6+ ile gelen yenilikler, kodlarımızı daha temiz, daha okunabilir ve daha performanslı hale getiriyor. Bu yazıda, 2024'te bilmeniz gereken en pratik JavaScript ipuçlarını paylaşacağım.
💡 Bu yazıda öğrenecekleriniz:
- Modern array methodları
- Destructuring teknikleri
- Async/await best practices
- Optional chaining kullanımı
- Template literals ipuçları
📊 Modern Array Methods
1. Array.from() ile Çeviriler
// NodeList'i array'e çevir
const divs = Array.from(document.querySelectorAll('div'));
// String'i array'e çevir
const chars = Array.from('Hello'); // ['H', 'e', 'l', 'l', 'o']
// Set'i array'e çevir
const uniqueNumbers = Array.from(new Set([1, 2, 2, 3, 3, 4])); // [1, 2, 3, 4]
// Mapping ile birlikte kullan
const squares = Array.from({length: 5}, (_, i) => i * i); // [0, 1, 4, 9, 16]
2. Array.flatMap() - Map ve Flat Birlikte
const users = [
{name: 'Ahmet', hobbies: ['football', 'reading']},
{name: 'Ayşe', hobbies: ['swimming', 'cooking', 'gaming']},
{name: 'Mehmet', hobbies: ['music']}
];
// Tüm hobileri tek array'de topla
const allHobbies = users.flatMap(user => user.hobbies);
// ['football', 'reading', 'swimming', 'cooking', 'gaming', 'music']
// Aynı işlem map + flat ile (daha uzun)
const allHobbiesOld = users.map(user => user.hobbies).flat();
3. Array.groupBy() - ES2024 Yeniliği
const products = [
{name: 'Laptop', category: 'Electronics', price: 1000},
{name: 'Phone', category: 'Electronics', price: 500},
{name: 'Shirt', category: 'Clothing', price: 30},
{name: 'Jeans', category: 'Clothing', price: 80}
];
// Kategoriye göre grupla
const groupedByCategory = Object.groupBy(products, product => product.category);
/*
{
Electronics: [{name: 'Laptop', ...}, {name: 'Phone', ...}],
Clothing: [{name: 'Shirt', ...}, {name: 'Jeans', ...}]
}
*/
// Fiyata göre grupla
const groupedByPrice = Object.groupBy(products, product =>
product.price > 100 ? 'expensive' : 'affordable'
);
🔧 Destructuring İleri Teknikleri
1. İç İçe Destructuring
const user = {
name: 'Ahmet',
address: {
city: 'Istanbul',
country: 'Turkey',
coordinates: {
lat: 41.0082,
lng: 28.9784
}
},
preferences: {
theme: 'dark',
language: 'tr'
}
};
// İç içe destructuring
const {
name,
address: {
city,
coordinates: { lat, lng }
},
preferences: { theme = 'light' } = {}
} = user;
console.log(name, city, lat, lng, theme); // Ahmet Istanbul 41.0082 28.9784 dark
2. Array Destructuring ile Swap
let a = 1, b = 2;
// Klasik yöntem (geçici değişken)
let temp = a;
a = b;
b = temp;
// Modern yöntem (destructuring)
[a, b] = [b, a];
// Birden fazla değişken swap
let x = 1, y = 2, z = 3;
[x, y, z] = [z, x, y]; // x=3, y=1, z=2
3. Function Parameters Destructuring
// Klasik yöntem
function createUser(name, age, email, city, country) {
// Parametre sırası önemli, karışık
}
// Modern yöntem - destructuring parameters
function createUser({ name, age, email, city = 'Istanbul', country = 'Turkey' }) {
return {
name,
age,
email,
location: `${city}, ${country}`,
createdAt: new Date()
};
}
// Kullanım - sıra önemli değil
const user = createUser({
email: 'ahmet@example.com',
name: 'Ahmet',
age: 25
}); // city ve country default değerleri alır
⚡ Async/Await Best Practices
1. Promise.allSettled() ile Güvenli Paralel İşlemler
const urls = [
'https://api1.example.com/data',
'https://api2.example.com/data',
'https://api3.example.com/data' // Bu başarısız olabilir
];
// Promise.all - bir tanesi fail olursa hepsi fail
try {
const results = await Promise.all(
urls.map(url => fetch(url).then(res => res.json()))
);
} catch (error) {
// Bir API fail olursa buraya düşer
}
// Promise.allSettled - her birinin sonucunu al
const results = await Promise.allSettled(
urls.map(url => fetch(url).then(res => res.json()))
);
// Başarılı olanları filtrele
const successfulResults = results
.filter(result => result.status === 'fulfilled')
.map(result => result.value);
// Başarısız olanları logla
const failedResults = results
.filter(result => result.status === 'rejected')
.map(result => result.reason);
2. Async/Await ile Error Handling
// Helper function - try/catch wrapper
const safeAsync = async (asyncFn) => {
try {
const result = await asyncFn();
return [null, result];
} catch (error) {
return [error, null];
}
};
// Kullanım
const fetchUserData = async (userId) => {
const [error, userData] = await safeAsync(() =>
fetch(`/api/users/${userId}`).then(res => res.json())
);
if (error) {
console.error('User fetch failed:', error);
return null;
}
return userData;
};
// Birden fazla async işlem
const loadUserProfile = async (userId) => {
const [userError, user] = await safeAsync(() => fetchUser(userId));
const [postsError, posts] = await safeAsync(() => fetchUserPosts(userId));
return {
user: userError ? null : user,
posts: postsError ? [] : posts,
errors: {
user: userError,
posts: postsError
}
};
};
3. AbortController ile İptal Edilebilir Requests
class ApiService {
constructor() {
this.controller = null;
}
async fetchData(url, timeout = 5000) {
// Önceki request'i iptal et
if (this.controller) {
this.controller.abort();
}
this.controller = new AbortController();
// Timeout ayarla
const timeoutId = setTimeout(() => {
this.controller.abort();
}, timeout);
try {
const response = await fetch(url, {
signal: this.controller.signal
});
clearTimeout(timeoutId);
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request cancelled or timed out');
}
throw error;
}
}
cancel() {
if (this.controller) {
this.controller.abort();
}
}
}
// Kullanım
const api = new ApiService();
// Request gönder
api.fetchData('/api/data').then(data => console.log(data));
// 2 saniye sonra iptal et
setTimeout(() => api.cancel(), 2000);
🔗 Optional Chaining ve Nullish Coalescing
1. Güvenli Property Access
const user = {
name: 'Ahmet',
address: {
city: 'Istanbul'
// country property yok
}
};
// Klasik yöntem - uzun ve karışık
if (user && user.address && user.address.country) {
console.log(user.address.country);
}
// Modern yöntem - optional chaining
console.log(user.address?.country); // undefined
// Array elements için
const users = [
{ name: 'Ahmet', posts: [{ title: 'Post 1' }] },
{ name: 'Ayşe' } // posts property yok
];
console.log(users[0]?.posts?.[0]?.title); // "Post 1"
console.log(users[1]?.posts?.[0]?.title); // undefined
// Function calls için
const api = {
user: {
getName: () => 'Ahmet'
// getAge function yok
}
};
console.log(api.user?.getName?.()); // "Ahmet"
console.log(api.user?.getAge?.()); // undefined
2. Nullish Coalescing (??) ile Default Values
// Fark: || vs ??
const config = {
theme: '',
count: 0,
enabled: false,
apiUrl: null
};
// || operatörü - falsy değerler için default
console.log(config.theme || 'light'); // 'light' (empty string falsy)
console.log(config.count || 10); // 10 (0 falsy)
console.log(config.enabled || true); // true (false falsy)
// ?? operatörü - sadece null/undefined için default
console.log(config.theme ?? 'light'); // '' (empty string korunur)
console.log(config.count ?? 10); // 0 (0 korunur)
console.log(config.enabled ?? true); // false (false korunur)
console.log(config.apiUrl ?? '/api'); // '/api' (null için default)
// Gerçek kullanım örneği
function createUser(userData) {
return {
name: userData.name ?? 'Anonymous',
age: userData.age ?? 0,
preferences: {
theme: userData.preferences?.theme ?? 'light',
notifications: userData.preferences?.notifications ?? true
}
};
}
📝 Template Literals İleri Kullanım
1. Tagged Template Literals
// HTML template function
function html(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] ? escapeHtml(values[i]) : '';
return result + string + value;
}, '');
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// Kullanım - XSS güvenli HTML
const userName = '';
const userAge = 25;
const userCard = html`
${userName}
Age: ${userAge}
`;
// Çıktı: <script>alert("XSS")</script> şeklinde güvenli
// CSS template function
function css(strings, ...values) {
return strings.reduce((result, string, i) => {
return result + string + (values[i] || '');
}, '');
}
const primaryColor = '#3498db';
const borderRadius = '8px';
const buttonStyles = css`
.button {
background-color: ${primaryColor};
border-radius: ${borderRadius};
border: none;
padding: 10px 20px;
color: white;
cursor: pointer;
}
.button:hover {
background-color: ${primaryColor}dd;
}
`;
2. Multi-line Template Kullanımı
// SQL query builder
function buildQuery({table, select = '*', where = {}, orderBy, limit}) {
const whereClause = Object.entries(where)
.map(([key, value]) => `${key} = '${value}'`)
.join(' AND ');
return `
SELECT ${select}
FROM ${table}
${whereClause ? `WHERE ${whereClause}` : ''}
${orderBy ? `ORDER BY ${orderBy}` : ''}
${limit ? `LIMIT ${limit}` : ''}
`.trim().replace(/\s+/g, ' ');
}
// Kullanım
const query = buildQuery({
table: 'users',
select: 'name, email, age',
where: {
active: true,
role: 'admin'
},
orderBy: 'created_at DESC',
limit: 10
});
// Çıktı: "SELECT name, email, age FROM users WHERE active = 'true' AND role = 'admin' ORDER BY created_at DESC LIMIT 10"
📦 ES Modules Best Practices
1. Dynamic Imports ile Lazy Loading
// utils.js
export const formatDate = (date) => {
return new Intl.DateTimeFormat('tr-TR').format(date);
};
export const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
// main.js - Dynamic import
async function loadUtils() {
const { formatDate, debounce } = await import('./utils.js');
return { formatDate, debounce };
}
// Conditional loading
async function handleUserAction(action) {
if (action === 'export') {
const { exportToExcel } = await import('./excel-utils.js');
exportToExcel(data);
} else if (action === 'chart') {
const { createChart } = await import('./chart-utils.js');
createChart(data);
}
}
// Route-based loading (SPA)
const routes = {
'/dashboard': () => import('./pages/dashboard.js'),
'/profile': () => import('./pages/profile.js'),
'/settings': () => import('./pages/settings.js')
};
async function navigateTo(path) {
const pageModule = await routes[path]();
pageModule.render();
}
2. Module Pattern ile State Management
// store.js - Simple state management
class Store {
constructor(initialState = {}) {
this.state = initialState;
this.listeners = [];
}
getState() {
return { ...this.state };
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.listeners.forEach(listener => listener(this.state));
}
subscribe(listener) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter(l => l !== listener);
};
}
}
// User store
export const userStore = new Store({
user: null,
isLoggedIn: false,
theme: 'light'
});
// Theme store
export const themeStore = new Store({
theme: localStorage.getItem('theme') || 'light',
colors: {
primary: '#3498db',
secondary: '#2ecc71'
}
});
// main.js - Store kullanımı
import { userStore, themeStore } from './store.js';
// State değişikliklerini dinle
const unsubscribeUser = userStore.subscribe((state) => {
console.log('User state changed:', state);
updateUI(state);
});
// State güncelle
userStore.setState({
user: { name: 'Ahmet', email: 'ahmet@example.com' },
isLoggedIn: true
});
// Theme değiştir
themeStore.setState({ theme: 'dark' });
🎯 Sonuç
Modern JavaScript'in sunduğu bu özellikler, kodlarımızı daha temiz, daha okunabilir ve daha performanslı hale getirir. Bu ipuçlarını projelerinizde uygulayarak, 2024'te daha etkili JavaScript geliştiricisi olabilirsiniz.