🚀 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.