🟨 Java geliştirici için JavaScript

Java dünyasından gelen geliştiricilere yönelik ES6+, modül sistemi, HTTP istemcileri, bundling ve Jest testleri — öğren ve mülakatta net anlat.

🔎 Genel Bakış

  • JS tek iş parçacıklı, event loop ve async odaklıdır (thread yerine Promise / async/await).
  • Tip sistemi dinamiktir; TypeScript geçişi önerilir ama bu sayfa “Java geliştirici için yeter” JS odaklıdır.
  • Modern JS → ESM modülleri, fetch API, bundler ile prod’a uygun paket.

🧠 Dil Temelleri (Java ↔ JS)

Önemli Farklar

  • == vs ===: === (strict) tercih edilir; tür dönüşümü yapmaz.
  • var/let/const: var hoisting + function scope; let/const block scope + TDZ.
  • this: bağlam çağrı şekline göre değişir; arrow function’lar lexical this kullanır.
  • Prototype: Sınıflar syntactic sugar; altında prototip zinciri vardır.
  • Truthy/Falsy: 0,"",null,undefined,NaN,false → falsy; diğerleri truthy.
// === kullan
console.log(0 == false);  // true (kötü)
console.log(0 === false); // false (doğru yaklaşım)

// let/const
let count = 1;
const PI = 3.14; // yeniden atama yok

// Arrow this
const obj = {
  val: 42,
  regular(){ setTimeout(function(){ console.log(this.val); }, 0); }, // undefined
  arrow(){ setTimeout(() => console.log(this.val), 0); } // 42
};
obj.regular(); obj.arrow();

✨ ES6+ Özellikleri

  • Destructuring, spread/rest, template string, default param.
  • Map/Set, class & static, private field #.
  • Optional chaining ?., nullish coalescing ??.
  • Promise, async/await, Promise.all/any/allSettled.
const user = { id: 1, profile: { name: "Ada" } };
const { id, profile: { name } } = user;
const full = { ...user, active: true };   // spread
function sum(...nums){ return nums.reduce((a,b) => a+b, 0); } // rest
const title = `Merhaba ${name}`;

class Counter {
  #val = 0;               // private field
  static of(n){ const c = new Counter(); c.#val = n; return c; }
  inc(){ this.#val++; return this.#val; }
}
const c = Counter.of(5).inc();

const city = user.address?.city ?? "Bilinmiyor";

📦 Modüller: ESM vs CJS

TürExportImportNerede
ESMexport/export defaultimport {...} from 'mod'Tarayıcı & Node (modern)
CommonJSmodule.exportsrequire('mod')Node (legacy)
// math.js (ESM)
export function add(a,b){ return a+b; }
export default class Calc { mul(a,b){ return a*b; } }

// app.js
import Calc, { add } from './math.js';
console.log(add(2,3), new Calc().mul(2,3));

// Dinamik import (code-splitting)
if(someCond){ const { heavy } = await import('./heavy.js'); heavy(); }

⚙️ Runtime & Event Loop

  • Tek iş parçacığı; I/O asenkron. Microtask (Promise) → Macrotask (setTimeout).
  • Node’da CommonJS/ESM karma dünyası; "type":"module" ile ESM.
  • CPU-ağır işler için Web Worker / Worker Threads düşün.
console.log("A");
setTimeout(() => console.log("C"), 0);
Promise.resolve().then(() => console.log("B")); // microtask önce
// A, B, C

🌳 DOM & Eventler

  • querySelector, addEventListener, event delegation.
  • Form verisi: FormData, URLSearchParams.
<ul id="list"></ul>
<button id="add">Ekle</button>
const list = document.querySelector("#list");
document.querySelector("#add").addEventListener("click", () => {
  const li = document.createElement("li");
  li.innerText = "Öğe " + (list.children.length+1);
  list.appendChild(li);
});
// Delegation:
list.addEventListener("click", (e) => {
  if(e.target.tagName === "LI"){ e.target.remove(); }
});

🌐 HTTP — fetch & axios

fetch (yerleşik)

async function getUser(id, { signal } = {}) {
  const res = await fetch(`/api/users/${id}`, { signal, headers:{ "Accept":"application/json" }});
  if(!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}
const c = new AbortController();
setTimeout(() => c.abort(), 3000); // timeout
getUser(1, { signal: c.signal }).catch(console.error);

POST / JSON

async function saveUser(u){
  const res = await fetch('/api/users', {
    method:'POST',
    headers:{ 'Content-Type':'application/json' },
    body: JSON.stringify(u)
  });
  if(!res.ok) throw new Error('Save failed');
  return res.json();
}

axios (kolay interceptor & timeout)

import axios from "axios";
const api = axios.create({ baseURL:'/api', timeout: 5000 });
api.interceptors.response.use(
  r => r,
  e => {
    if(e.response?.status === 401){ /* refresh veya login yönlendirme */ }
    return Promise.reject(e);
  }
);
const { data } = await api.get('/users', { params:{ page:1 }});
Pratikler: ETag/If-None-Match ile caching, Retry-After ve exponential backoff, Promise.all() ile paralel istekler.

🚦 Hata Yönetimi

async function request(promise){
  try{
    const res = await promise;
    return [res, null];
  }catch(err){
    return [null, err];
  }
}
// Kullanım
const [user, err] = await request(api.get('/me'));
if(err){ /* toast/log */ }

Global: window.addEventListener('unhandledrejection'), window.onerror ile loglayın.

🧰 Bundling & Build

  • Vite: hızlı dev server + rollup build.
  • Webpack/Rollup/esbuild: tree-shaking, code-splitting, babel.
  • Tarayıcı hedefi için Babel + core-js ile polyfill.
# Vite ile sıfırdan
npm create vite@latest myapp -- --template vanilla
cd myapp
npm i
npm run dev   # HMR
npm run build # dist/

ESM Native: Modern tarayıcılarda bundling’siz de çalışabilirsiniz; ancak üretimde minify/split/cache-busting için bundler önerilir.

📜 package.json & Scriptler

{
  "name": "acme-frontend",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "test": "jest --runInBand",
    "lint": "eslint . --ext .js,.mjs",
    "format": "prettier -w ."
  },
  "dependencies": {
    "axios": "^1.7.0"
  },
  "devDependencies": {
    "vite": "^5.0.0",
    "jest": "^29.7.0",
    "@jest/globals": "^29.7.0",
    "eslint": "^9.0.0",
    "prettier": "^3.2.0"
  }
}

🧹 ESLint & Prettier

// eslint.config.js
export default [
  { files: ["**/*.js"], languageOptions:{ ecmaVersion: "latest", sourceType:"module" },
    rules: { "no-unused-vars":"warn", "eqeqeq":"error", "no-console":"off" } }
];
{
  "printWidth": 100,
  "singleQuote": true,
  "semi": true
}

🧪 Jest Testleri

Saf Fonksiyon Testi

// sum.js
export const sum = (a,b) => a + b;

// sum.test.js
import { describe, it, expect } from "@jest/globals";
import { sum } from "./sum.js";
describe("sum", () => {
  it("toplar", () => { expect(sum(2,3)).toBe(5); });
});

Async & fetch Mock

// user.test.js
import { it, expect, vi, beforeEach } from "@jest/globals";

beforeEach(() => { global.fetch = vi.fn(); });

it("kullanıcıyı getirir", async () => {
  fetch.mockResolvedValueOnce(new Response(JSON.stringify({ id:1, name:"Ada" }), { status:200 }));
  const res = await fetch("/api/users/1");
  const data = await res.json();
  expect(data.name).toBe("Ada");
});

axios Mock

import axios from "axios";
import { it, expect, vi } from "@jest/globals";
vi.mock("axios");

it("axios ile liste çeker", async () => {
  axios.get.mockResolvedValueOnce({ data:[{id:1}] });
  const { data } = await axios.get("/api/list");
  expect(data).toHaveLength(1);
});

JSDOM ile DOM testleri: Jest 29+’da testEnvironment: "jsdom".

🧵 Spring ile Entegrasyon

  • CORS: Spring’te @CrossOrigin veya global CORS konfigürasyonu.
  • Auth: HttpOnly cookie (CSRF korumalı) veya Bearer Token; token’ı localStorage’da saklamayın tercih.
  • Tarih/Zaman: ISO-8601 (UTC) gönderin; OffsetDateTime ile uyumlu.
// Spring JSON uyumlu client
const api = axios.create({ baseURL:"/api", withCredentials:true });
export const getOrders = (page=0) => api.get("/orders", { params:{ page }});

🛡️ Güvenlik Notları

  • XSS: Kullanıcı girdisini DOM’a eklerken sanitize edin (örn. DOMPurify). innerText tercih edin.
  • CSRF: SameSite=strict/lax cookie + CSRF token; withCredentials kullanımında dikkat.
  • Eval yok, 3. parti scriptlere SRI ve CSP.

❓ Mülakat Soruları & Kısa Yanıtlar

1) == ve === farkı?

== tür dönüşümü yapar; === hem tür hem değer eşitliğini ister (tercih edilir).

2) Arrow function’larda this nasıl davranır?

Lexical this; çağırıldığı yere göre değil, tanımlandığı bağlama göre belirlenir.

3) Promise vs async/await?

Aynı modeli ifade eder; async/await daha okunaklıdır, hata yakalama try/catch ile yapılır.

4) ESM ve CJS farkı?

ESM statik import (tree-shaking), CJS dinamik require; tarayıcı/modern Node ESM’i destekler.

5) fetch ile timeout nasıl?

AbortController ile istek iptal edilir; axios’ta timeout ayarı var.

6) Event loop’ta microtask/macrotask?

Promise callbackleri microtask kuyruğunda; setTimeout gibi işler macrotask’tadır.

📝 JS Cheat Sheet

// Diziler
const arr = [1,2,3];
arr.map(x => x*2).filter(x => x>=4);

// Nesneler
const o = { a:1, b:2 };
const { a, ...rest } = o; // {a:1}, rest:{b:2}

// Async
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
await sleep(100);

// Hata
try { await risky(); } catch(e){ console.error(e); }

// Modül
export function fn(){}; export default class C{}
// Import
import C, { fn } from './m.js';