This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
{
|
||||
const firstName = 'John';
|
||||
|
||||
// if (firstName === John) {
|
||||
// // ReferenceError: John is not defined
|
||||
// console.log(firstName);
|
||||
// }
|
||||
|
||||
// if (firstname === 'John') {
|
||||
// // Uncaught ReferenceError: firstname is not defined
|
||||
// console.log(firstName);
|
||||
// }
|
||||
|
||||
if (firstName === 'John') {
|
||||
console.log(firstName);
|
||||
}
|
||||
|
||||
function greet() {
|
||||
console.log('Hello, ' + fullName); // Cannot find name 'fullName'.
|
||||
console.log(typeof fullName);
|
||||
}
|
||||
|
||||
// greet(); // => ReferenceError: fullName is not defined
|
||||
|
||||
// function greet(fullName) {
|
||||
// console.log(`Hello, ${fullName}`);
|
||||
// }
|
||||
|
||||
greet('John Wick');
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nesting if-statements</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Nesting if-statements</h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
let isSystemUpgrading = false;
|
||||
let isLoggedIn = true;
|
||||
let hasAdminRights = true;
|
||||
|
||||
const items = [
|
||||
{
|
||||
name: 'Item A',
|
||||
cost: 150,
|
||||
},
|
||||
{
|
||||
name: 'Item B',
|
||||
cost: 250,
|
||||
},
|
||||
{
|
||||
name: 'Item C',
|
||||
cost: 350,
|
||||
},
|
||||
];
|
||||
|
||||
function processRequests() {
|
||||
if (!isSystemUpgrading) {
|
||||
if (isLoggedIn) {
|
||||
if (hasAdminRights) {
|
||||
items.forEach((item) => {
|
||||
console.log(`Item Name: ${item.name}`);
|
||||
if (item.cost > 200) {
|
||||
console.log('Item cost is greater than 200.');
|
||||
} else {
|
||||
console.log('Item cost is less than or equal to 200.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('You do not have administrative privileges.');
|
||||
}
|
||||
} else {
|
||||
console.log('You must be logged in to view items.');
|
||||
}
|
||||
} else {
|
||||
console.log('System is currently being upgraded.');
|
||||
}
|
||||
}
|
||||
|
||||
console.time('without inversion');
|
||||
processRequests();
|
||||
console.timeEnd('without inversion');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,68 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nesting if-statements vermeiden über inversion</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Nesting if-statements vermeiden über <strong>inversion</strong></h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const isSystemUpgrading = true;
|
||||
const isLoggedIn = true;
|
||||
const hasAdminRights = true;
|
||||
|
||||
const items = [
|
||||
{
|
||||
name: 'Item A',
|
||||
cost: 150,
|
||||
},
|
||||
{
|
||||
name: 'Item B',
|
||||
cost: 250,
|
||||
},
|
||||
{
|
||||
name: 'Item C',
|
||||
cost: 350,
|
||||
},
|
||||
];
|
||||
|
||||
function processRequests() {
|
||||
if (isSystemUpgrading) {
|
||||
console.log('System is currently being upgraded.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoggedIn) {
|
||||
console.log('You must be logged in to view items.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasAdminRights) {
|
||||
console.log('You do not have administrative privileges.');
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
console.log(`Item Name: ${item.name}`);
|
||||
if (item.cost > 200) {
|
||||
console.log('Item cost is greater than 200.');
|
||||
} else {
|
||||
console.log('Item cost is less than or equal to 200.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.time('inversion');
|
||||
processRequests();
|
||||
console.timeEnd('inversion');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
|
||||
const isSystemUpgrading = false;
|
||||
const isLoggedIn = true;
|
||||
const hasAdminRights = true;
|
||||
|
||||
const items = [
|
||||
{ name: 'Item A', cost: 150 },
|
||||
{ name: 'Item B', cost: 250 },
|
||||
{ name: 'Item C', cost: 350 },
|
||||
];
|
||||
|
||||
function runNested() {
|
||||
let counter = 0;
|
||||
if (!isSystemUpgrading) {
|
||||
if (isLoggedIn) {
|
||||
if (hasAdminRights) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].cost > 200) counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
function runGuard() {
|
||||
let counter = 0;
|
||||
if (isSystemUpgrading) return counter;
|
||||
if (!isLoggedIn) return counter;
|
||||
if (!hasAdminRights) return counter;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].cost > 200) counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
const ITERATIONS = 10_000_000;
|
||||
|
||||
// Warmup
|
||||
for (let i = 0; i < 100_000; i++) {
|
||||
runNested();
|
||||
runGuard();
|
||||
}
|
||||
|
||||
console.time('Verschachtelt');
|
||||
for (let i = 0; i < ITERATIONS; i++) runNested();
|
||||
console.timeEnd('Verschachtelt');
|
||||
|
||||
console.time('Early Returns');
|
||||
for (let i = 0; i < ITERATIONS; i++) runGuard();
|
||||
console.timeEnd('Early Returns');
|
||||
|
||||
// In diesem Test laufen beide Varianten im Chrome V8-Engine praktisch gleich schnell (innerhalb normaler CPU-Schwankungen).
|
||||
|
||||
// Fazit: Verwende Early Returns (Guard Clauses). Sie bieten zwar keinen nennenswerten Performance-Vorsprung gegenüber verschachtelten Abfragen, reduzieren aber die zyklomatische Komplexität und machen den Code deutlich lesbarer.
|
||||
@@ -0,0 +1,38 @@
|
||||
## Kein Performanceunterschied bei Inversion
|
||||
|
||||
### 1. AST-Normalisierung & SSA (Control Flow Graphs)
|
||||
|
||||
V8 (über den Turbofan-Optimierungs-Compiler) führt deinen Code nicht zeilenweise so aus, wie du ihn schreibst:
|
||||
|
||||
* **Control Flow Graph (CFG):** V8 wandelt sowohl verschachtelte Blöcke als auch Early Returns in dieselbe abstrakte Repräsentation um (Static Single Assignment / SSA Form).
|
||||
* **Pfad-Reduktion:** Ein verschachtelter Baum `if (A) { if (B) { if (C) { ... } } }` wird im Zwischencode auf denselben Entscheidungspfad reduziert wie `if (!A) return; if (!B) return; if (!C) return;`.
|
||||
* **Identischer Maschinencode:** Sobald Turbofan den Code optimiert, erzeugen beide Varianten exakt dieselbe Sequenz aus bedingten Sprungbefehlen (`test`, `jnz` / `jz`) auf Assemblerebene.
|
||||
|
||||
---
|
||||
|
||||
### 2. Hardware-Ebene: CPU Branch Prediction
|
||||
|
||||
Unabhängig von der JS-Engine entscheidet die Hardware über die Geschwindigkeit von Verzweigungen:
|
||||
|
||||
* Wenn Bedingungen wie `isLoggedIn` stabil sind (z. B. immer `true`), lernt der **Branch Predictor** der CPU das Muster nach wenigen Durchläufen.
|
||||
* Die CPU führt den Zweig spekulativ ohne Pipeline-Stall aus (Branch Prediction Penalty = 0 Takte).
|
||||
* Ob der nicht genommene Zweig am Ende der Funktion (`nested`) oder direkt hinter dem Check (`early return`) liegt, macht für die Ausführungszeit der CPU keinen Unterschied.
|
||||
|
||||
---
|
||||
|
||||
### 3. Warum misst man im Firefox (SpiderMonkey) manchmal Unterschiede?
|
||||
|
||||
SpiderMonkey (Firefox) und V8 (Chrome) verfolgen unterschiedliche Strategien bei der Bytecode-Erzeugung und den JIT-Stufen:
|
||||
|
||||
| Aspekt | Chrome (V8) | Firefox (SpiderMonkey) |
|
||||
| --- | --- | --- |
|
||||
| **Pipeline** | Ignition (Interpreter) $\rightarrow$ Sparkplug $\rightarrow$ Maglev $\rightarrow$ Turbofan | C++ Interpreter $\rightarrow$ Baseline Interpreter $\rightarrow$ Baseline Compiler $\rightarrow$ WarpMonkey |
|
||||
| **Bytecode-Layout** | V8 optimiert Jump-Targets früh im Bytecode-Generator; Basic Blocks werden linear angeordnet. | SpiderMonkey behält in frühen Phasen oft ein Bytecode-Layout bei, das näher an der Quellcode-Struktur liegt. |
|
||||
| **Bailout / OSR** | Sehr aggressives Inlining und Dead-Code-Elimination im `Maglev`/`Turbofan`-Layer. | `WarpMonkey` nutzt Transpilation über CacheIR; je nach Verschachtelungstiefe können Scope- und Frame-Handling im Baseline-Tier minimal variieren. |
|
||||
|
||||
In **nicht-hochoptimiertem Code** (z. B. Skripte, die nur wenige Male laufen und im Interpreter bzw. Baseline JIT verbleiben):
|
||||
|
||||
* Verursacht tiefe Verschachtelung in manchen Engines zusätzlichen Overhead beim Verwalten von Lexical Environments/Scopes auf dem Stack.
|
||||
* Early Returns erlauben es dem Interpreter, den aktuellen Stack-Frame schneller abzubauen, ohne tiefer liegende Scope-Hierarchien zu durchlaufen.
|
||||
|
||||
Sobald der Code jedoch "heiß" läuft (nach einigen tausend Iterationen), eliminieren sowohl Turbofan als auch WarpMonkey diesen Unterschied vollständig.
|
||||
Binary file not shown.
@@ -0,0 +1,61 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nested if-statements</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Nested if-statements</h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const isSystemUpgrading = false;
|
||||
const isLoggedIn = true;
|
||||
const hasAdminRights = true;
|
||||
|
||||
const items = [
|
||||
{
|
||||
name: 'Item A',
|
||||
cost: 150,
|
||||
},
|
||||
{
|
||||
name: 'Item B',
|
||||
cost: 250,
|
||||
},
|
||||
{
|
||||
name: 'Item C',
|
||||
cost: 350,
|
||||
},
|
||||
];
|
||||
|
||||
function processRequests() {
|
||||
if (isSystemUpgrading) {
|
||||
console.log('System is currently being upgraded.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoggedIn || !hasAdminRights) {
|
||||
console.log('You must be logged in and have administrative privileges to view items.');
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach((item) => {
|
||||
console.log(`Item Name: ${item.name}`);
|
||||
if (item.cost > 200) {
|
||||
console.log('Item cost is greater than 200.');
|
||||
} else {
|
||||
console.log('Item cost is less than or equal to 200.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processRequests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Extraction</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Extraction</h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const isSystemUpgrading = false;
|
||||
const isLoggedIn = true;
|
||||
const hasAdminRights = true;
|
||||
|
||||
const items = [
|
||||
{
|
||||
name: 'Item A',
|
||||
cost: 150,
|
||||
},
|
||||
{
|
||||
name: 'Item B',
|
||||
cost: 250,
|
||||
},
|
||||
{
|
||||
name: 'Item C',
|
||||
cost: 350,
|
||||
},
|
||||
];
|
||||
|
||||
// Extraction
|
||||
function displayItemDetails(item) {
|
||||
console.log(`Item Name: ${item.name}`);
|
||||
if (item.cost > 200) {
|
||||
console.log('Item cost is greater than 200.');
|
||||
} else {
|
||||
console.log('Item cost is less than or equal to 200.');
|
||||
}
|
||||
}
|
||||
|
||||
// auslagerung in utils/helper Ordner möglich
|
||||
function hasAccessRights() {
|
||||
// if (isLoggedIn && hasAdminRights) {
|
||||
// return true
|
||||
// } else {
|
||||
// return false
|
||||
// }
|
||||
|
||||
// return (isLoggedIn && hasAdminRights) ? true : false;
|
||||
|
||||
return isLoggedIn && hasAdminRights;
|
||||
}
|
||||
|
||||
function processRequests() {
|
||||
// Guard (early returns bzw. inversion)
|
||||
if (isSystemUpgrading) {
|
||||
console.log('System is currently being upgraded.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extraction
|
||||
if (!hasAccessRights()) {
|
||||
console.log('You must be logged in and have administrative privileges to view items.');
|
||||
return;
|
||||
}
|
||||
|
||||
items.forEach(displayItemDetails); // Funktionsreferenz
|
||||
}
|
||||
|
||||
processRequests();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,41 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>DRY - Don't Repeat Yourself</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>DRY - Don't Repeat Yourself</h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function calculateRectangles() {
|
||||
// Rectangle 1
|
||||
const length1 = 15;
|
||||
const width1 = 10;
|
||||
const area1 = length1 * width1;
|
||||
console.log('Area of Rectangle 1:', area1);
|
||||
|
||||
// Rectangle 2
|
||||
const length2 = 12;
|
||||
const width2 = 8;
|
||||
const area2 = length2 * width2;
|
||||
console.log('Area of Rectangle 2:', area2);
|
||||
|
||||
// Rectangle 3
|
||||
const length3 = 10;
|
||||
const width3 = 5;
|
||||
const area3 = length3 * width3;
|
||||
console.log('Area of Rectangle 3:', area3);
|
||||
}
|
||||
|
||||
calculateRectangles();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,96 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>DRY - Don't Repeat Yourself - Regel anwenden</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>DRY - Don't Repeat Yourself - Regel anwenden</h1>
|
||||
<div class="output alert alert-secondary my-3"></div>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// IIFE - Immediately invoked function expression. - sorgt für eingeschränkten Gültigkeitsbereich (Schutz) vom Code
|
||||
(() => {
|
||||
// === DOM & VARS =======
|
||||
const DOM = {
|
||||
output: document.querySelector('.output'),
|
||||
};
|
||||
|
||||
const rectangles = [
|
||||
{ length: 15, width: 10 },
|
||||
{ length: 12, width: 8 },
|
||||
{ length: 10, width: 5 },
|
||||
];
|
||||
|
||||
const rectangle = { length: 10, width: 12 };
|
||||
|
||||
// === INIT =============
|
||||
// Newspaper-Metapher Prinzip
|
||||
const init = () => {
|
||||
const areas = calcRectangles(rectangles);
|
||||
|
||||
let html = '';
|
||||
areas.forEach((area, idx) => {
|
||||
html += `Area of Rectange ${idx + 1}: ${area}<br />`;
|
||||
});
|
||||
|
||||
DOM.output.innerHTML = html;
|
||||
};
|
||||
|
||||
// === EVENTHANDLER =====
|
||||
|
||||
// === XHR/FETCH ========
|
||||
|
||||
// === FUNCTIONS ========
|
||||
const calcRectangles = (rects = []) => {
|
||||
rects = Array.isArray(rects) ? rects : [rects];
|
||||
|
||||
const areas = rects.map((rect) => rect.length * rect.width);
|
||||
|
||||
return areas;
|
||||
};
|
||||
|
||||
init();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!--
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>DRY - Don't Repeat Yourself</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DRY - Don't Repeat Yourself</h1>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function calculateRectangles() {
|
||||
const rectangles = [
|
||||
{ length: 15, width: 10 },
|
||||
{ length: 12, width: 8 },
|
||||
{ length: 10, width: 5 },
|
||||
];
|
||||
|
||||
rectangles.forEach((rect, index) => {
|
||||
const area = rect.length * rect.width;
|
||||
console.log(`Area of Rectangle ${index + 1}:`, area);
|
||||
});
|
||||
}
|
||||
|
||||
calculateRectangles();
|
||||
</script>
|
||||
</body>
|
||||
</html> -->
|
||||
@@ -0,0 +1,63 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Syntax Error</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Syntax <code>Error</code></h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
{
|
||||
const age = 25;
|
||||
// console.log('My age is, age); // Uncaught SyntaxError: Invalid or unexpected token
|
||||
console.log('My age is, age');
|
||||
|
||||
// function addNumbers(num1, num2 {
|
||||
// return num1 + num2;
|
||||
// }
|
||||
|
||||
// => SyntaxError: Unexpected token '{'
|
||||
|
||||
// const addNumbers (num1,num2) => {
|
||||
// return num1 + num2;
|
||||
// }
|
||||
// Uncaught SyntaxError: Missing initializer in const declaration
|
||||
|
||||
const addNumbers = (num1, num2) => {
|
||||
return num1 + num2;
|
||||
};
|
||||
|
||||
console.log(1, 2);
|
||||
|
||||
// let person = {
|
||||
// firstName: 'John'
|
||||
// lastName: 'Doe',
|
||||
// }
|
||||
|
||||
// => SyntaxError: Unexpected identifier 'lastName'
|
||||
|
||||
// let person = {
|
||||
// firstName: 'John',
|
||||
// lastName: 'Doe',
|
||||
// };
|
||||
|
||||
// const const = "value"; // => SyntaxError: Unexpected token 'const'
|
||||
// let class = "Math"; // => SyntaxError: Unexpected token 'class'
|
||||
// let for = 'for statement' // => SyntaxError: Unexpected token 'for'
|
||||
// const 🤡 = 'clown' // => SyntaxError: Invalid or unexpected token
|
||||
// const % = 'arithmetic'; // => SyntaxError: Invalid or unexpected token
|
||||
|
||||
// const Math = 'test';
|
||||
// const isNaN = 'is nicht';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Reference Error</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container py-5">
|
||||
<h1>Reference Error</h1>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
{
|
||||
const firstName = 'John';
|
||||
|
||||
// if (firstName === John) {
|
||||
// // ReferenceError: John is not defined
|
||||
// console.log(firstName);
|
||||
// }
|
||||
|
||||
// if (firstname === 'John') {
|
||||
// // Uncaught ReferenceError: firstname is not defined
|
||||
// console.log(firstName);
|
||||
// }
|
||||
|
||||
if (firstName === 'John') {
|
||||
console.log(firstName);
|
||||
}
|
||||
|
||||
function greet() {
|
||||
console.log('Hello, ' + fullName);
|
||||
console.log(typeof fullName);
|
||||
}
|
||||
|
||||
// greet(); // => ReferenceError: fullName is not defined
|
||||
|
||||
// function greet(fullName) {
|
||||
// console.log(`Hello, ${fullName}`);
|
||||
// }
|
||||
|
||||
greet('John Wick');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user