Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add runnable examples with test harness#628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
itzshikharofficial12 wants to merge1 commit intoleonardomso:master
base:master
Choose a base branch
Loading
fromitzshikharofficial12:add-runnable-examples-and-tests
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletionsREADME.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,6 +24,30 @@

This repository was created with the intention of helping developers master their concepts in JavaScript. It is not a requirement, but a guide for future studies. It is based on an article written by Stephen Curtis and you can read it [here](https://medium.com/@stephenthecurt/33-fundamentals-every-javascript-developer-should-know-13dd720a90d1).

## Examples (runnable)

This repository now includes a small set of concise, runnable examples that illustrate a few of the most important concepts. You can find them in the `examples/` folder. Each file prints a short output that demonstrates the concept.

- `examples/call-stack.js` — simple nested calls to show the call stack order.
- `examples/primitives-vs-references.js` — shows how primitives are copied by value and objects by reference.
- `examples/closures.js` — demonstrates how closures retain lexical scope.
- `examples/map-filter-reduce.js` — quick usage of `map`, `filter` and `reduce`.
- `examples/event-loop.js` — microtask vs macrotask ordering (Promises vs setTimeout).
- `examples/promises-async-await.js` — basic Promise and `async/await` example.
- `examples/this-call-bind.js` — `this` behavior and `call` / `bind` usage.

Try one quickly from the project root:

```
node examples/event-loop.js
```

Or run the default examples script:

```
npm run examples
```

## Community

Feel free to submit a PR by adding a link to your own recaps or reviews. If you want to translate the repo into your native language, please feel free to do so.
Expand Down
25 changes: 25 additions & 0 deletionsexamples/call-stack.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
// Example: Call Stack (LIFO order)
function a() {
console.log('a start');
b();
console.log('a end');
}

function b() {
console.log('b start');
c();
console.log('b end');
}

function c() {
console.log('c');
}

a();

// Expected output:
// a start
// b start
// c
// b end
// a end
15 changes: 15 additions & 0 deletionsexamples/call-stack.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
const { expectOutput } = require('./test-utils');

function testCallStack() {
return expectOutput(() => {
require('./call-stack');
}, [
'a start',
'b start',
'c',
'b end',
'a end'
]);
}

module.exports = testCallStack;
12 changes: 12 additions & 0 deletionsexamples/closures.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
// Example: Closures — a function that remembers its lexical scope
function makeCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}

const counter = makeCounter();
console.log('closure:', counter()); // 1
console.log('closure:', counter()); // 2
12 changes: 12 additions & 0 deletionsexamples/closures.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
const { expectOutput } = require('./test-utils');

function testClosures() {
return expectOutput(() => {
require('./closures');
}, [
'closure: 1',
'closure: 2'
]);
}

module.exports = testClosures;
14 changes: 14 additions & 0 deletionsexamples/event-loop.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
// Example: Event Loop ordering (macrotasks vs microtasks)
console.log('script start');

setTimeout(() => console.log('timeout callback (macrotask)'), 0);

Promise.resolve().then(() => console.log('promise callback (microtask)'));

console.log('script end');

// Expected order:
// script start
// script end
// promise callback (microtask)
// timeout callback (macrotask)
14 changes: 14 additions & 0 deletionsexamples/event-loop.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
const { expectOutputAsync } = require('./test-utils');

function testEventLoop() {
return expectOutputAsync(() => {
require('./event-loop');
}, [
'script start',
'script end',
'promise callback (microtask)',
'timeout callback (macrotask)'
], 100);
}

module.exports = testEventLoop;
10 changes: 10 additions & 0 deletionsexamples/map-filter-reduce.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
// Example: map, filter and reduce
const arr = [1, 2, 3, 4, 5];

const squares = arr.map(n => n * n);
const evens = arr.filter(n => n % 2 === 0);
const sum = arr.reduce((acc, n) => acc + n, 0);

console.log('map -> squares:', squares); // [1,4,9,16,25]
console.log('filter -> evens:', evens); // [2,4]
console.log('reduce -> sum:', sum); // 15
13 changes: 13 additions & 0 deletionsexamples/map-filter-reduce.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
const { expectOutput } = require('./test-utils');

function testMapFilterReduce() {
return expectOutput(() => {
require('./map-filter-reduce');
}, [
'map -> squares: [1,4,9,16,25]',
'filter -> evens: [2,4]',
'reduce -> sum: 15'
]);
}

module.exports = testMapFilterReduce;
12 changes: 12 additions & 0 deletionsexamples/primitives-vs-references.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
// Example: Primitive vs Reference types
// Primitives are copied by value
let a = 1;
let b = a;
b = 2;
console.log('primitives:', { a, b }); // a stays 1, b is 2

// Objects are copied by reference
const obj1 = { x: 1 };
const obj2 = obj1;
obj2.x = 2;
console.log('references:', { obj1, obj2 }); // both reflect the change
12 changes: 12 additions & 0 deletionsexamples/primitives-vs-references.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
const { expectOutput } = require('./test-utils');

function testPrimitivesVsReferences() {
return expectOutput(() => {
require('./primitives-vs-references');
}, [
'primitives: {"a":1,"b":2}',
'references: {"obj1":{"x":2},"obj2":{"x":2}}'
]);
}

module.exports = testPrimitivesVsReferences;
12 changes: 12 additions & 0 deletionsexamples/promises-async-await.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
// Example: Promises and async/await
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async function run() {
console.log('before await');
await wait(50);
console.log('after await');
}

run();
12 changes: 12 additions & 0 deletionsexamples/promises-async-await.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
const { expectOutputAsync } = require('./test-utils');

function testPromisesAsyncAwait() {
return expectOutputAsync(() => {
require('./promises-async-await');
}, [
'before await',
'after await'
], 100);
}

module.exports = testPromisesAsyncAwait;
31 changes: 31 additions & 0 deletionsexamples/run-tests.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
// Test runner
const { expectOutput } = require('./test-utils');

// Run all example tests
async function runTests() {
const tests = [
require('./call-stack.test.js'),
require('./primitives-vs-references.test.js'),
require('./closures.test.js'),
require('./map-filter-reduce.test.js'),
require('./event-loop.test.js'),
require('./this-call-bind.test.js'),
require('./promises-async-await.test.js'),
];

console.log('\nRunning tests...\n');

let passed = 0;
let failed = 0;

for (const test of tests) {
const result = await test();
if (result) passed++;
else failed++;
}

console.log(`\nResults: ${passed} passed, ${failed} failed\n`);
process.exit(failed > 0 ? 1 : 0);
}

runTests().catch(console.error);
81 changes: 81 additions & 0 deletionsexamples/test-utils.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
// Simple test harness
function expectOutput(fn, expectedLines) {
const originalLog = console.log;
const actualOutput = [];

console.log = (...args) => {
// Handle object stringification consistently
const formatted = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ');
actualOutput.push(formatted);
};

try {
fn();
console.log = originalLog;

const passed = expectedLines.every((expected, i) => {
if (!actualOutput[i]) return false;
// Normalize JSON strings and arrays for comparison
const normalizedExpected = expected.replace(/[\s{}[\]]/g, '');
const normalizedActual = actualOutput[i].replace(/[\s{}[\]]/g, '');
return normalizedActual.includes(normalizedExpected);
});

if (passed) {
console.log('\x1b[32m✓\x1b[0m', fn.name || 'Test passed');
return true;
} else {
console.log('\x1b[31m✗\x1b[0m', fn.name || 'Test failed');
console.log('Expected:', expectedLines);
console.log('Got:', actualOutput);
return false;
}
} catch (err) {
console.log = originalLog;
console.error('\x1b[31m✗\x1b[0m Test error:', err);
return false;
}
}

// For async tests
function expectOutputAsync(fn, expectedLines, timeout = 1000) {
return new Promise((resolve) => {
const originalLog = console.log;
const actualOutput = [];

console.log = (...args) => {
const formatted = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
).join(' ');
actualOutput.push(formatted);
};

fn();

// Wait for all async operations to complete
setTimeout(() => {
console.log = originalLog;

const passed = expectedLines.every((expected, i) => {
if (!actualOutput[i]) return false;
const normalizedExpected = expected.replace(/[\s{}[\]]/g, '');
const normalizedActual = actualOutput[i].replace(/[\s{}[\]]/g, '');
return normalizedActual.includes(normalizedExpected);
});

if (passed) {
console.log('\x1b[32m✓\x1b[0m', fn.name || 'Test passed');
resolve(true);
} else {
console.log('\x1b[31m✗\x1b[0m', fn.name || 'Test failed');
console.log('Expected:', expectedLines);
console.log('Got:', actualOutput);
resolve(false);
}
}, timeout);
});
}

module.exports = { expectOutput, expectOutputAsync };
13 changes: 13 additions & 0 deletionsexamples/this-call-bind.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
// Example: this, call, apply and bind
const person = {
name: 'Alice',
greet() {
return `Hello ${this.name}`;
}
};

const greet = person.greet;
console.log('direct method:', person.greet()); // Hello Alice
console.log('extracted function (this lost):', greet()); // undefined or global
console.log('call ->', greet.call({ name: 'Bob' })); // Hello Bob
console.log('bind ->', greet.bind({ name: 'Carol' })()); // Hello Carol
14 changes: 14 additions & 0 deletionsexamples/this-call-bind.test.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
const { expectOutput } = require('./test-utils');

function testThisCallBind() {
return expectOutput(() => {
require('./this-call-bind');
}, [
'direct method: Hello Alice',
'extracted function (this lost): Hello undefined',
'call -> Hello Bob',
'bind -> Hello Carol'
]);
}

module.exports = testThisCallBind;
4 changes: 4 additions & 0 deletionsindex.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,3 +5,7 @@

Any kind of contribution is welcome. Feel free to contribute.
*/

// NOTE: For short runnable examples that illustrate many of the concepts listed
// in this repo, check the `examples/` folder. Each example is a small Node script
// you can run with `node examples/<name>.js` or `npm run examples` (default).
13 changes: 13 additions & 0 deletionspackage-lock.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

3 changes: 2 additions & 1 deletionpackage.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,8 @@
},
"homepage": "https://github.com/leonardomso/33#readme",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"examples": "node examples/event-loop.js"
},
"repository": {
"type": "git",
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp