+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples_book/.gitignore b/examples_book/.gitignore
new file mode 100644
index 0000000..e71f774
--- /dev/null
+++ b/examples_book/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+test_js/
+*.html
+*.json
+deploy*
+*.bat
+mybooks/
\ No newline at end of file
diff --git a/examples_book/Appendix_B/README.md b/examples_book/Appendix_B/README.md
new file mode 100644
index 0000000..f17914a
--- /dev/null
+++ b/examples_book/Appendix_B/README.md
@@ -0,0 +1,7 @@
+# ภาคผนวก ข
+
+* [ไฟล์ hello.js](hello.js)
+* [ไฟล์ server.mjs](server.mjs)
+* [ไฟล์ ajax.mjs](ajax.mjs)
+
+
diff --git a/examples_book/Appendix_B/ajax.mjs b/examples_book/Appendix_B/ajax.mjs
new file mode 100644
index 0000000..106770b
--- /dev/null
+++ b/examples_book/Appendix_B/ajax.mjs
@@ -0,0 +1,22 @@
+import * as http from "http";
+import * as fs from "fs";
+import * as url from "url";
+/* ถ้านำเข้ามอดูลตามมาตรฐาน CommonJS ก็ให้ใช้ require()
+var http = require("http"),
+ fs = require("fs"),
+ url = require("url"); */
+http.createServer( function(request, response) {
+ var parser = url.parse(request.url,true);
+ var path = parser.pathname;
+ var query = parser.query;
+ if( path=="/message" ) {
+ var echo = `{"echo" : "${query.msg}"}`;
+ //response.writeHead(200, {"Content-Type": "text/plain"});
+ response.writeHead(200, {
+ "Content-Type": "text/html",
+ "Access-Control-Allow-Origin" : "*"});
+ response.end(echo);
+ console.log(echo);
+ }
+}).listen(8001,"127.0.0.1");
+console.log("Server running at http://127.0.0.1:8001/");
\ No newline at end of file
diff --git a/examples_book/Appendix_B/hello.js b/examples_book/Appendix_B/hello.js
new file mode 100644
index 0000000..2f56984
--- /dev/null
+++ b/examples_book/Appendix_B/hello.js
@@ -0,0 +1,2 @@
+let msg = "Hello, world!"; // เป็นการประกาศตัวแปรแบบ let ซึ่งเป็นไวยากรณ์ของ ES6
+console.log(msg);
\ No newline at end of file
diff --git a/examples_book/Appendix_B/server.mjs b/examples_book/Appendix_B/server.mjs
new file mode 100644
index 0000000..6850331
--- /dev/null
+++ b/examples_book/Appendix_B/server.mjs
@@ -0,0 +1,9 @@
+import * as http from "http";
+// ถ้านำเข้ามอดูลตามมาตรฐาน CommonJS ก็ให้ใช้ require()
+// var http = require("http");
+http.createServer(function (req, res) {
+ res.writeHead(200, {"Content-Type": "text/html"});
+ res.write("
Hello, world!
");
+ res.end();
+}).listen(8001, "127.0.0.1");
+console.log("Server running at http://127.0.0.1:8001/");
diff --git a/examples_book/Appendix_G.md b/examples_book/Appendix_G.md
new file mode 100644
index 0000000..6950e56
--- /dev/null
+++ b/examples_book/Appendix_G.md
@@ -0,0 +1,444 @@
+# ภาคผนวก ง Well-Known symbols
+
+```js
+console.log(typeof Symbol.asyncIterator); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.hasInstance); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.isConcatSpreadable); // symbol –-ส่วนข้อมูลเป็นบูลีน
+console.log(typeof Symbol.iterator); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.match); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.matchAll); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.replace); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.search); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.split); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.species); // symbol --ส่วนข้อมูลเป็นคอนสตรัคเตอร์
+console.log(typeof Symbol.toPrimitive); // symbol --ส่วนข้อมูลเป็นฟังก์ชัน หรือเมธอด
+console.log(typeof Symbol.toStringTag); // symbol --ส่วนข้อมูลเป็นสตริง
+console.log(typeof Symbol.unscopables); // symbol --ส่วนข้อมูลเป็นอ็อบเจ็กต์
+```
+
+## การใช้งาน Symbol.hasInstance
+
+```js
+function MyConstructor() { }
+class MyClass { }
+let obj1 = new MyConstructor();
+let obj2 = new MyClass();
+console.log(obj1 instanceof MyConstructor); // true
+console.log(obj2 instanceof MyClass); // true
+
+console.log(MyConstructor[Symbol.hasInstance](obj1)); // true
+// จะเหมือนเขียน console.log(obj1 instanceof MyConstructor); // true
+console.log(MyClass[Symbol.hasInstance](obj2)); // true
+// จะเหมือนเขียน console.log(obj2 instanceof MyClass); // true
+```
+
+```js
+class PositiveNumber {
+ constructor(value) {
+ this.value = value;
+ }
+}
+Object.defineProperty( PositiveNumber, Symbol.hasInstance, {
+ // ดัดแปลงพฤติกรรมของพร็อพเพอร์ตี้ Symbol.hasInstance อันเดิม ด้วยการประกาศเมธอดอันใหม่
+ value: function(objNumber) {
+ // พารามิเตอร์ objNumber รับค่าอากิวเมนต์เป็นอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
+ if(objNumber.value > 0) {
+ return true; // ถ้าค่าในอ็อบเจ็กต์มากกว่า 0
+ } else {
+ return false; // ถ้าค่าในอ็อบเจ็กต์น้อยกว่าหรือเท่ากับ 0
+ }
+ } // สิ้นสุดประกาศฟังก์ชัน
+}); // สิ้นสุด Object.defineProperty
+let positive = new PositiveNumber(10);
+let negative = new PositiveNumber(-10);
+console.log(positive instanceof PositiveNumber); // true
+console.log(negative instanceof PositiveNumber); // false
+```
+
+## การใช้งาน Symbol.isConcatSpreadable
+
+```js
+let a1 = [1, 2, 3];
+let a2 = [4, 5, 6];
+let a3 = a1.concat(a2);
+console.log(a3); // [ 1, 2, 3, 4, 5, 6 ]
+console.log(a1[Symbol.isConcatSpreadable]); // undefined
+console.log(a2[Symbol.isConcatSpreadable]); // undefined
+console.log(a3[Symbol.isConcatSpreadable]); // undefined
+```
+
+หมายเหตุ ตัวอย่างต่อไปนี้ อย่าลืมก็อปปี้ a1 กับ a2 ของตัวอย่างอย่างก่อนหน้านี้มาใช้งานด้วย
+
+```js
+a1[Symbol.isConcatSpreadable] = true;
+a2[Symbol.isConcatSpreadable] = true;
+let a3 = a1.concat(a2);
+console.log(a3); // [ 1, 2, 3, 4, 5, 6 ]
+```
+
+```js
+a1[Symbol.isConcatSpreadable] = false;
+a2[Symbol.isConcatSpreadable] = false;
+let a3 = a1.concat(a2);
+console.log(a3); // [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
+```
+
+```js
+a1[Symbol.isConcatSpreadable] = true;
+a2[Symbol.isConcatSpreadable] = false;
+let a3 = a1.concat(a2);
+console.log(a3); // [ 1, 2, 3, [ 4, 5, 6 ] ]
+```
+
+```js
+a1[Symbol.isConcatSpreadable] = false;
+a2[Symbol.isConcatSpreadable] = true;
+let a3 = a1.concat(a2);
+console.log(a3); // [ [ 1, 2, 3 ], 4, 5, 6 ]
+```
+
+```js
+let likedArray = {
+ 0: "a",
+ 1: "b",
+ length: 2,
+ [Symbol.isConcatSpreadable]: true
+};
+let arr = [ "A", "B" ].concat(likedArray);
+console.log(arr); // [ 'A', 'B', 'a', 'b' ]
+```
+
+## การใช้งาน Symbol.match, Symbol.matchAll, Symbol.replace, Symbol.search, Symbol.split
+
+```js
+console.log(typeof RegExp.prototype[Symbol.match]); // "function"
+console.log(typeof RegExp.prototype[Symbol.matchAll]); // "function"
+console.log(typeof RegExp.prototype[Symbol.replace]); // "function"
+console.log(typeof RegExp.prototype[Symbol.search]); // "function"
+console.log(typeof RegExp.prototype[Symbol.split]); // "function"
+```
+
+```js
+let regexObj = {
+ [Symbol.match](value) {
+ return value.match(/Hello/); // จับคู่คำว่า "Hello"
+ },
+ [Symbol.replace](value, replacement) {
+ return value.replace(/!/, replacement); // แทนที่คำว่า "!" ด้วย replacement
+ },
+ [Symbol.search](value) {
+ return value.search(/World/); // ค้นหาคำว่า "World"
+ },
+ [Symbol.split](value) {
+ return value.split(/\s/); // ใช้ช่องว่างเป็นตัวแบ่ง
+ }
+}
+let str = "Hello World !";
+// เรียกเมธอด [Symbol.match]
+console.log(str.match(regexObj)); // [ 'Hello', index: 0, input: 'Hello World !', groups: undefined ]
+// เรียกเมธอด [Symbol.replace]
+console.log(str.replace(regexObj, "?")); // "Hello World ?"
+// เรียกเมธอด [Symbol.search]
+console.log(str.search(regexObj)); // 6
+// เรียกเมธอด [Symbol.split]
+console.log(str.split(regexObj)); // [ 'Hello', 'World', '!' ]
+```
+
+```js
+let regexObj = {
+ [Symbol.matchAll](value) {
+ return value.matchAll(/o/g); // จับคู่ตัวอักษร "o"
+ }
+}
+let str = "Hello World !";
+result = str.matchAll(regexObj)
+for (const m of result) {
+ console.log(m);
+}
+// แสดงผลลัพธ์
+// [ 'o', index: 4, input: 'Hello World !', groups: undefined ]
+// [ 'o', index: 7, input: 'Hello World !', groups: undefined ]
+```
+
+## การใช้งาน Symbol.species
+
+```js
+class MyArray extends Array {
+}
+let array = new MyArray(1, 2, 3, 4);
+let newarray = array.filter((item) => item > 2);
+console.log(newarray); // [ 3, 4 ]
+console.log(array instanceof MyArray); // true
+console.log(newarray instanceof Array); // true
+console.log(newarray instanceof MyArray); // true
+```
+
+```js
+class MyArray extends Array {
+ static get [Symbol.species]() {
+ return Array;
+ }
+}
+let array = new MyArray(1, 2, 3, 4);
+let newarray = array.filter((item) => item > 2);
+console.log(newarray); // [ 3, 4 ]
+console.log(array instanceof MyArray); // true
+console.log(newarray instanceof Array); // true
+console.log(newarray instanceof MyArray); // false
+```
+
+```js
+class MyArray extends Array {
+ static get [Symbol.species]() {
+ return this;
+ }
+}
+let array = new MyArray(1, 2, 3, 4);
+let newarray = array.filter((item) => item > 2);
+console.log(newarray); // [ 3, 4 ]
+console.log(array instanceof MyArray); // true
+console.log(newarray instanceof Array); // true
+console.log(newarray instanceof MyArray); // true
+```
+
+```js
+class MyClass {
+ static get [Symbol.species]() {
+ console.log("Symbol.species is called");
+ return this;
+ }
+ constructor(value) {
+ this.value = value;
+ }
+ create() {
+ return new this.constructor[Symbol.species](this.value);
+ // เสมือนเขียน return new MyClass(this.value);
+ }
+}
+let obj = new MyClass();
+obj.create(); // "Symbol.species is called"
+```
+
+หมายเหตุ ตัวอย่างต่อไปนี้ อย่าลืมก็อปปี้ MyClass จากตัวอย่างก่อนหน้ามาใช้ด้วย
+
+```js
+class MyClass2 extends MyClass {
+}
+let obj = new MyClass2();
+let obj2 = obj.create(); // "Symbol.species is called"
+console.log(obj2 instanceof MyClass); // true
+console.log(obj2 instanceof MyClass2); // true
+```
+
+```js
+class MyClass2 extends MyClass {
+ static get [Symbol.species]() {
+ console.log("Symbol.species is overrided");
+ return MyClass;
+ }
+}
+let obj = new MyClass2();
+let obj2 = obj.create(); // "Symbol.species is overrided"
+console.log(obj2 instanceof MyClass); // true
+console.log(obj2 instanceof MyClass2); // false
+```
+
+## การใช้งาน Symbol.toPrimitive
+
+```js
+let a = {};
+console.log("It is " + a) // "It is [object Object]"
+```
+
+```js
+let two = new Number(2); // ประกาศอ็อบเจ็กต์ Number
+console.log(two.toString()); // "2"
+console.log(two.valueOf()); // 2
+// เบื้องหลังจะเรียกใช้ two.valueOf() ให้กลายเป็น 2 ก่อน แล้วถึงคูณด้วย 5 จึงกลายเป็น 2 * 5
+console.log(two * 5); // 10
+```
+
+```js
+let obj = {};
+console.log(obj.toString() ); // "[object Object]"
+console.log(obj.valueOf()); // {}
+// เบื้องหลังจะเรียกใช้ obj.toString()
+console.log(String(obj)); // "[object Object]"
+```
+
+```js
+let date = new Date("12-30-2023");
+console.log(date.toString()); // "Sat Dec 30 2023 00:00:00 GMT+0700 (Indochina Time)"
+console.log(date.valueOf()); // 1703869200000
+// เบื้องหลังจะเรียกใช้ date.toString()
+console.log(new Date(date)); // "Sat Dec 30 2023 00:00:00 GMT+0700 (Indochina Time)"
+```
+
+```js
+class ThaiCurrency {
+ constructor(amount) {
+ this.amount = amount;
+ }
+}
+let obj = new ThaiCurrency();
+console.log(obj[Symbol.toPrimitive]); // undefined
+```
+
+```js
+class ThaiCurrency {
+ constructor(amount){
+ this.amount = amount;
+ }
+ [Symbol.toPrimitive](hint) {
+ switch (hint) {
+ case "number":
+ return this.amount;
+ case "string":
+ return this.amount + " Baht";
+ case "default":
+ return this.amount + " THB";
+ } // สิ้นสุด switch
+ } // สิ้นสุดประกาศเมธอด
+} // สิ้นสุดประกาศคลาส
+let money = new ThaiCurrency (100);
+console.log(money / 2); // 50 -- case "number":
+console.log(String(money)); // "100 Baht" -- case "string"
+console.log("Price " + money); // "Price 100 THB" -- case "default"
+console.log(money == "100 THB"); // true -- case "default"
+```
+
+```js
+function ThaiCurrency(amount) {
+ this.amount = amount;
+}
+ThaiCurrency.prototype[Symbol.toPrimitive] = function(hint) {
+ switch (hint) {
+ case "number":
+ return this.amount;
+ case "string":
+ return this.amount + " Baht";
+ case "default":
+ return this.amount + " THB";
+ } // สิ้นสุด switch
+}; // สิ้นสุดประกาศเมธอด
+let money = new ThaiCurrency (100);
+console.log(money / 2); // 50 -- case "number":
+console.log(String(money)); // "100 Baht" -- case "string"
+console.log("Price " + money); // "Price 100 THB" -- case "default"
+console.log(money == "100 THB"); // true -- case "default"
+```
+
+## การใช้งาน Symbol.toStringTag
+
+```js
+obj = { }
+obj[Symbol.toStringTag] = "My Object";
+console.log(obj.toString()); // "[object My Object]"
+console.log(Object.prototype.toString.call(obj)); // "[object My Object]"
+```
+
+```js
+class MyClass { }
+let obj = new MyClass();
+console.log(obj[Symbol.toStringTag]); // undefined
+console.log(obj.toString()); // "[object Object]"
+```
+
+```js
+class MyClass {
+ constructor() {
+ this[Symbol.toStringTag] = "MyClass";
+ }
+}
+let obj = new MyClass();
+console.log(obj[Symbol.toStringTag]); // "MyClass"
+console.log(obj.toString()); // "[object MyClass]"
+// toString() เบื้องหลังจะเก็บไว้ที่ MyClass.Prototype.toString()
+// ซึ่งสืบทอดมาจาก Object.prototype.toString()
+console.log(obj.toString === MyClass.prototype.toString); // true
+console.log(obj.toString === Object.prototype.toString); // true
+// กำหนดให้ this ชี้ไปยัง obj
+console.log(Object.prototype.toString.call(obj)); // "[object MyClass]"
+```
+
+```js
+class MyClass {
+ constructor() {
+ this[Symbol.toStringTag] = "MyClass";
+ }
+ toString() { // โอเวอร์ไลด์เมธอด Object.prototype.toString
+ return "This is MyClass"; // ไม่ได้แสดงข้อความ "[object MyClass]"
+ }
+}
+let obj = new MyClass();
+console.log(obj.toString()); // "This is MyClass"
+console.log(Object.prototype.toString.call(obj)); // "[object MyClass]"
+```
+
+```js
+function MyConstructor() { }
+MyConstructor.prototype[Symbol.toStringTag] = "My Object";
+let obj = new MyConstructor();
+console.log(obj.toString()); // "[object My Object]"
+console.log(Object.prototype.toString.call(obj)); // "[object My Object]"
+```
+
+```js
+Array.prototype[Symbol.toStringTag] = "My Array";
+let myarray = [1, 2, 3];
+console.log(Object.prototype.toString.call(myarray)); // "[object My Array]"
+// ต่อไปจะทำการเรียก toString() ของอาร์เรย์
+console.log(myarray.toString()) // "1,2,3"
+console.log(Array.prototype.toString.call(myarray)) // "1,2,3"
+```
+
+## การใช้งาน Symbol.unscopables
+
+```js
+Array.prototype[Symbol.unscopables] = Object.assign(Object.create(null), { // โดยดีฟอลต์
+ copyWithin: true,
+ entries: true,
+ fill: true,
+ find: true,
+ findIndex: true,
+ keys: true,
+ values: true
+});
+```
+
+```js
+let array = [4, 3, 2, 1];
+console.log(array); // [ 4, 3, 2, 1 ]
+with(array) {
+ sort(); // เรียงลำดับอาร์เรย์ใหม่จากน้อยไปหามาก
+ console.log(typeof copyWithin); // "undefined"
+}
+console.log(array); // [ 1, 2, 3, 4 ]
+```
+
+```js
+let obj = {
+ foo: "foo value",
+ bar: "bar value"
+}
+with(obj) {
+ console.log(foo); // "foo value"
+ console.log(bar); // "bar value"
+}
+```
+
+```js
+let obj = {
+ foo: "foo value",
+ bar: "bar value"
+}
+obj[Symbol.unscopables] = Object.assign(Object.create(null), {
+ foo: true // ห้ามใช้ foo ในบล็อกของประโยคคำสั่ง with
+});
+with(obj) {
+ console.log(typeof foo); // "undefined"
+ console.log(bar); // "bar value"
+}
+```
+
+
diff --git a/examples_book/Chapter02.md b/examples_book/Chapter02.md
new file mode 100644
index 0000000..ba6f4da
--- /dev/null
+++ b/examples_book/Chapter02.md
@@ -0,0 +1,281 @@
+# โค้ดบทที่ 2 รันจาวาสคริปต์อย่างง่าย
+
+## จาวาสคริปต์บนเว็บเบราเซอร์
+
+### วิธีแทรกจาวาสคริปต์ลงในไฟล์ HTML
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### ตัวอย่างการวางจาวาสคริต์ใน <body> ...</body>
+
+```html
+
+
+
+
+
+
Hello, world!
+
+
+```
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+### ตัวอย่างการวางจาวาสคริต์ใน <head> ...</head>
+
+```html
+
+
+
+
+
+
+
+
Hello, World!
+
+
+```
+
+หมายเหตุ ตัวอย่างนี้จะเกิด error (ต้องดูที่หน้าคอนโซล)
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### ตัวอย่างการใช้งาน ES6 ในฝั่งเว็บเบราเซอร์
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+### แยกไฟล์จาวาสคริปต์ ออกจาก HTML
+
+
+* [ไฟล์ myScript_1.js](Chapter03/myScript_1.js)
+
+* [ไฟล์ myScript_2.js](Chapter03/myScript_2.js)
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+## จาวาสคริปต์ ES บนเว็บเบราเซอร์รุ่นเก่า
+
+### ตัวอย่างการใช้งาน Traceur
+
+```tab.html
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### ตัวอย่างการใช้งาน Babel
+
+```tab.html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## จาวาสคริปต์นอกเว็บเบราเซอร์ด้วย Node.js
+
+### รันจาวาสคริปต์นอกเว็บเบราเซอร์ จากไฟล์นามสกุล .js ตามลำพัง
+
+```js
+class Chat {
+ constructor(message) {
+ this.message = message;
+ }
+ say() {
+ console.log(this.message);
+ }
+};
+let chat = new Chat("Hello, world!");
+chat.say();
+```
+
+### ตัวอย่างการรันจาวาสคริปต์ให้กลายเป็นเซิร์ฟเวอร์
+
+```js
+var http = require('http');
+http.createServer(function (request, response) {
+ response.writeHead(200, {'Content-Type': 'text/plain'});
+ response.end("Hello, world!");
+}).listen(8001, '127.0.0.1');
+console.log('Server running at http://127.0.0.1:8001/');
+```
+
+## จาวาสคริปต์นอกเว็บเบราเซอร์ด้วย Deno
+
+```js
+import { serve } from "https://deno.land/std@0.97.0/http/server.ts";
+const s = serve({ port: 8000 });
+console.log("http://localhost:8000/");
+for await (const req of s) {
+ req.respond({ body: "Hello, world!" });
+}
+```
+
+## เครื่องมือในการดีบั๊ก
+
+```html
+
+
+
+
+
+
+
+
+
+```
diff --git a/examples_book/Chapter03.md b/examples_book/Chapter03.md
new file mode 100644
index 0000000..d9d1c60
--- /dev/null
+++ b/examples_book/Chapter03.md
@@ -0,0 +1,1129 @@
+# โค้ดบทที่ 3 ทบทวนมาตรฐานเก่า
+
+## คอมเมนต์
+```js
+var x = 10; //This is an example.
+```
+
+```js
+/* This is an example
+ECMAScript 6 is very easy*/
+var x = 10;
+```
+
+## console.log()
+```html
+
+
+
+
+
Hello, world!
+
+
+
+```
+
+```js
+console.log("Hello world", 122, 333.333); // "Hello world 122 333.333"
+```
+
+### debugger
+```js
+console.log("line 1"); // "line 1"
+debugger; // บรรทัดนี้เป็นตำแหน่งของ breakpoint เพื่อหยุดการทำงานของโปรแกรมชั่วขณะ ตอนดีบั๊กโปรแกรม
+console.log("line 2"); // "line 2"
+```
+
+## การใช้เซมิโคลอน (;)
+```js
+console.log("Hello world");
+```
+
+```js
+console
+.log
+(
+"Hello world"
+);
+```
+
+```js
+;
+;
+;
+```
+
+```js
+;;;;;
+```
+
+```js
+console.log("Hello world")
+console
+.log
+(
+"Hello world"
+)
+```
+
+```js
+var a = 1
+var b = 5
+var c = a + b
+(a * b)
+```
+
+```js
+var a = 1;
+var b = 5;
+var c = a + b(a * b);
+```
+
+```js
+var a = 1 + 2
+-3 + 10
+console.log(a) // 10
+```
+
+```js
+var a = 1 + 2 -3 + 10;
+console.log(a); // 10
+```
+
+```js
+function todo() {
+ return {
+ "foo" : 1
+ };
+}
+```
+
+```js
+function todo() {
+ return
+ {
+ "foo" : 1
+ };
+}
+```
+
+## เส้นทางการทำงานโปรแกรม
+
+```js
+console.log(1);
+console.log(2);
+console.log(3);
+console.log(4);
+```
+
+```js
+console.log(1); console.log(2); console.log(3); console.log(4);
+```
+
+```js
+console.log(1) console.log(2) console.log(3) console.log(4)
+```
+
+## การตั้งชื่อ
+```js
+var _ = 100; // ตั้งชื่อแบบนี้ได้
+var $ = 100; // ตั้งชื่อแบบนี้ได้
+var _a =100; // ตั้งชื่อแบบนี้ได้
+var $a =100; // ตั้งชื่อแบบนี้ได้
+var Abc = 100; // ตั้งชื่อแบบนี้ได้
+var abc = 100; // ตั้งชื่อแบบนี้ได้ แต่ทว่าตัวแปร Abc กับ abc จะถือว่าคนละชื่อกัน
+var a0123 = 100; // ตั้งชื่อแบบนี้ได้
+var 9b = 100; // ทำไม่ได้ มันจะเกิด SyntaxError เพราะมีเลข 9 นำหน้าชื่อตัวแปร
+var สวัสดีครับ = 100; // ตั้งชื่อภาษาไทยแบบนี้ได้ แต่ส่วนใหญ่นิยมตั้งชื่อเป็นภาษาอังกฤษ)
+```
+
+## คำสงวน
+
+```js
+var let = -1; // ทำไม่ได้ มันจะเกิด SyntaxError เพราะ let เป็นคำสงวน
+var this= -10; // ทำไม่ได้ มันจะเกิด SyntaxError เพราะ this เป็นคำสงวน
+```
+
+```js
+var Date = 100;
+console.log(Date); // แสดงผลลัพธ์ 100
+```
+
+```js
+var Date = 100;
+console.log(Date); // แสดงผลลัพธ์ 100
+var d = new Date();
+console.log(d);
+```
+
+## การประกาศตัวแปร
+```js
+var x = 100;
+```
+
+```js
+var x = 1, y = 2, z = 3; // ประกาศตัวแปร x, y และ z ให้อยู่ในบรรทัดเดียวกัน
+```
+
+```js
+var x = 1;
+var y = 2;
+var z = 3;
+```
+
+```js
+var x= 1, y = x;
+/* จะเสมือนเขียนซอร์สโค้ดแบบนี้
+var x = 1;
+var y = x;
+*/
+```
+
+```js
+var x;
+console.log(x); // undefined
+```
+
+* หมายเหตุ แสดงผลลัพธ์เหมือนรันใน Node.js
+```js
+var undefined = 55555;
+console.log(undefined); // บนเว็บบราวเซอร์จะแสดงเป็น undefined แต่บน Node.js จะแสดงเป็น 55555
+var x;
+console.log(x); // undefined
+```
+
+### การประกาศตัวแปรโดยไม่มี var
+```js
+x = 1;
+```
+
+* หมายเหตุ ควรรันคำส่ง delete x; ก่อน เพื่อลบตัวแปร x = 1; ที่รันก่อนหน้านี้
+```js
+console.log(x); // ReferenceError
+```
+
+```js
+var x; // ประกาศตัวแปร แต่ยังไมีการกำหนดค่าให้ x จึงมีค่าเป็น undefined
+console.log(x); // undefined
+```
+
+
+## ไดนามิกไทป์
+```js
+var foo = 42; // เริ่มต้นตัวแปร foo จะมีชนิดข้อมูลเป็นตัวเลข
+foo = "bar"; // ภายหลัง foo เปลี่ยนมาเก็บข้อมูลเป็นสตริง
+foo = true; // ภายหลัง foo เปลี่ยนมาเก็บข้อมูลเป็นบูลีน
+```
+
+## ข้อมูล
+
+### null กับ undefined
+
+```js
+console.log(null === undefined) // false
+console.log(null == undefined) // true
+console.log(typeof null) // "object"
+console.log(typeof undefined) // "undefined"
+```
+
+### ตัวเลข
+```js
+console.log(100, 0, -0, -300, 3.14, -78.222); // 100 0 -0 -300 3.14 -78.222
+```
+
+```js
+console.log(200e5); // 200 x 105 = 20000000
+console.log(2E-5); // 2 x 10-5 = 0.00002
+```
+
+```js
+console.log(Math.sqrt(-1)); // NaN (ไม่สามารถถอดรากที่สองของ -1)
+console.log(0/0); // NaN ( 0 หาร 0 ไม่มีนิยาม)
+console.log(parseInt("Hi")); // NaN (ไม่สามารถแปลง "Hi" เป็นตัวเลขได้)
+```
+
+```js
+console.log(Infinity * Infinity); // Infinity
+console.log(Infinity / Infinity); // NaN
+console.log(-344 * Infinity); // -Infinity
+console.log(3 / Infinity); // 0
+```
+
+```js
+console.log(Number.MAX_VALUE); // 1.7976931348623157e+308 โดยประมาณ
+console.log(Number.MAX_VALUE + 100); // 1.7976931348623157e+308 โดยประมาณ (บรรทัด 2)
+console.log(Number.MAX_VALUE * 10); // Infinity (บรรทัด 3)
+console.log(Number.MAX_VALUE * -10); // -Infinity (บรรทัด 4)
+```
+
+```js
+console.log(Number.MIN_VALUE); // 5e-324 (เป็นค่าโดยประมาณ)
+```
+
+### สตริง
+```js
+"Learning JavaScript"
+'Learning JavaScript'
+```
+
+```js
+// ใช้ \" อยู่ภายในสตริง ส่วนเครื่องหมาย ' สามารถเขียนอยู่ในสตริงได้เลย
+console.log("...\"Learning\" 'JavaScript'..."); // ..."Learning" 'JavaScript'...
+// ใช้ \' อยู่ภายในสตริง ส่วนเครื่องหมาย " สามารถเขียนอยู่ในสตริงได้เลย
+console.log('..."Learning" \'JavaScript\'...'); // ..."Learning" 'JavaScript'...
+```
+
+```js
+var str= "line1\
+line2\
+line3";
+console.log(str); // line1line2line3
+```
+
+```js
+console.log("1234567890".length); // 10
+```
+
+### บูลีน
+
+```js
+var TRUE_value = true;
+var FALSE_value = false
+console.log(TRUE_value); // true
+console.log(FALSE_value); // false
+```
+
+```js
+-5;
+-10.71;
+"Learning JavaScript";
+true;
+var a = -5;
+var b = -10.71;
+var c = "Learning JavaScript";
+var d = true;
+```
+
+## โอเปอเรเตอร์
+
+### โอเปอเรเตอร์ทางคณิตศาสตร์
+```js
+console.log(true + 0); // ได้ผลลัพธ์เป็น 1 เพราะ true จะถือว่ามีค่าเป็น 1
+console.log(false + false); // ได้ผลลัพธ์เป็น 0 เพราะ false จะถือว่ามีค่าเป็น 0
+console.log(100 - true); // 99
+console.log(true * 30); // 30
+console.log(true / 2); // 0.5
+console.log(true % 10); // 1
+console.log(+true); // 1
+console.log(-false); // -0
+var a = false, b=true;
+console.log(++a); // 1
+console.log(--b); // 0
+```
+
+```js
+console.log(NaN + 30); // NaN
+console.log(NaN - 30); // NaN
+console.log(NaN * 30); // NaN
+console.log(NaN / 30); // NaN
+console.log(NaN % 30); // NaN
+console.log(+NaN); // NaN
+console.log(-NaN); // NaN
+var x = NaN;
+console.log(++x); // NaN
+console.log(--x); // NaN
+```
+
+```js
+console.log(Infinity * 0); // NaN
+console.log(Infinity * 1); // Infinity
+console.log(Infinity * Infinity); // Infinity
+console.log(Infinity * -Infinity); // -Infinity
+console.log(Infinity / 0); // Infinity
+```
+
+* การใช้งานโอเปอเรเตอร์ยกกำลัง (Exponentiation Operator)
+
+```js
+var ans = 10 ** 2; // นำเลข 10 มายกกำลัง 2 ( 102 )
+console.log(ans); // 100
+// เสมือนใช้เมธอด Math.pow() ดังนี้
+console.log(ans === Math.pow(10, 2)); // true
+```
+
+* ลำดับของโอเปอเรเตอร์ **
+
+```js
+var ans = 3 * 10 ** 2;
+console.log(ans); // 300
+```
+
+```js
+var ans = 3 * (10 ** 2);
+console.log(ans); // 300
+```
+* ข้อเข้มงวดของโอเปอเรเตอร์ **
+
+```js
+var ans1 = -10 ** 2; // syntax error
+var ans2 = +10 ** 2; // syntax error
+```
+
+```js
+ans1 = -(10 ** 2); // -100
+ans1 = (-10) ** 2; // 100
+ans2 = +(10 ** 2); // 100
+ans2 = (+10) ** 2; // 100
+```
+
+```js
+var value1 = 9, value2 = 10;
+// ใช้งานโอเปอเรเตอร์ ++ แบบ prefix
+// ค่าของ value1 ถูกบวกด้วยหนึ่ง ก่อนที่จะยกกำลัง 2
+console.log(++value1 ** 2); // 100
+console.log(value1); // 10
+// ใช้งานโอเปอเรเตอร์ ++ แบบ postfix
+// หลังจากยกกำลัง 2 ไปแล้ว ค่าของ value2 จึงถูกบวกด้วยหนึ่งทีหลัง
+console.log(value2++ ** 2); // 100
+console.log(value2); // 11
+```
+
+```js
+var value1 = 11, value2 = 10;
+// ใช้งานโอเปอเรเตอร์ -- แบบ prefix
+// ค่า value1 ถูกลบด้วยหนึ่ง ก่อนที่จะยกกำลัง 2
+console.log(--value1 ** 2); // 100
+console.log(value1); // 10
+// ใช้งานโอเปอเรเตอร์ -- แบบ postfix
+// หลังจากยกกำลัง 2 ไปแล้ว ค่าของ value2 จึงถูกลบด้วยหนึ่งทีหลัง
+console.log(value2-- ** 2); // 100
+console.log(value2); // 9
+```
+
+### โอเปอเรเตอร์ที่ใช้กำหนดค่าให้กับตัวแปร
+
+```js
+var a = 20;
+a +=true; // true มีค่าเป็น 1
+console.log(a); // 21
+a *=NaN;
+console.log(a); // NaN
+```
+
+### โอเปอเรเตอร์ที่ใช้กับสตริง
+
+```js
+100 + true + "50"; // "10150"
+// เสมือนเขียน (100 + true) + "50"
+```
+
+```js
+20 / "10" + "76"; // 276
+// เสมือนเขียน ( 20 / "10") + "76"
+```
+
+### โอเปเรอเตอร์แบบตรรกะ
+```js
+console.log(true || true); // true (เงื่อนไข short circuit)
+console.log(true || false); // true (เงื่อนไข short circuit)
+console.log(false || true); // true
+console.log(false || false); // false
+console.log(true && true); // true
+console.log(true && false); // false
+console.log(false && true); // false (เงื่อนไข short circuit)
+console.log(false && false); // false (เงื่อนไข short circuit)
+console.log(!true); // false
+console.log(!false); // true
+```
+
+### โอเปอเรเตอร์ระหว่างบิต
+
+* ตัวอย่าง Bitwise AND
+```js
+var a = 12; // 1100 (เลขฐานสอง)
+var b = 5; // 0101 (เลขฐานสอง)
+var c = a & b; // 0100 (เลขฐานสอง)
+console.log(c.toString(2)); // 100 (เลขฐานสอง)
+console.log(c); // 4
+console.log(12 & 5); // 4
+```
+
+* ตัวอย่าง Bitwise OR
+
+```js
+var a = 12; // 1100
+var b = 5; // 0101
+var c = a | b; // 1101
+console.log(c.toString(2)); // 1101
+console.log(c); // 13
+console.log(12 | 5); // 13
+```
+
+* ตัวอย่าง Bitwise XOR
+
+```js
+var a =12; // 1100
+var b= 5; // 0101
+var c = a ^ b; // 1001
+console.log(c.toString(2)); // 1001
+console.log(c); // 9
+console.log(12 ^ 5); // 9
+```
+
+* ตัวอย่าง Bitwise NOT
+
+```js
+var a= 9; // 00000000000000000000000000001001
+var b = ~a; // 11111111111111111111111111110110 (1's Complement)
+console.log(b); // -10
+console.log(~9); // -10
+```
+
+* ตัวอย่าง การเลื่อนบิตไปทางซ้ายมือ
+
+```js
+var a = 9; // 00000000000000000000000000001001
+var c = a << 2; // เลื่อนบิตจากขวามือไปทางซ้ายมือ 2 ตำแหน่ง
+ // 00000000000000000000000000100100
+console.log(c); // 36
+console.log(9 << 2); // 36
+```
+
+* ตัวอย่าง การเลื่อนบิตไปทางขวามือ
+
+```js
+var a = 9; // 00000000000000000000000000001001
+var c = a >> 2; // เลื่อนบิตจากซ้ายมือไปทางขวามือ 2 ตำแหน่ง
+ // 00000000000000000000000000000010
+console.log(c); // 2
+console.log(9 >> 2); // 2
+```
+
+```js
+-9; // 11111111111111111111111111110111 (เลขฐานสอง)
+-9 >> 2; // 11111111111111111111111111111101 (เลขฐานสอง) = -3 (เลขฐานสิบ)
+```
+
+```js
+var a = 9; // 00000000000000000000000000001001
+var c = a >>> 2; // เลื่อนบิตจากซ้ายมือไปทางขวามือ 2 ตำแหน่ง พร้อมเติมเลข 0 ที่บิตด้านหน้าสุด
+ // 00000000000000000000000000000010
+console.log(c); // 2
+console.log(9 >>> 2); // 2
+```
+
+### โอเปอเรเตอร์ typeof
+
+```js
+console.log(typeof true); // "boolean"
+console.log(typeof false); // "boolean"
+console.log(typeof -0.13); // "number"
+console.log(typeof NaN); // "number"
+console.log(typeof Infinity); // "number"
+console.log(typeof undefined); // "undefined"
+console.log(typeof ''); // "string"
+console.log(typeof "Hi"); // "string"
+console.log(typeof (typeof 100) ); // "string"
+console.log(typeof null); // "object"
+console.log(typeof {x: 1, y: 2}); // "object"
+console.log(typeof [1, 2]); // "object"
+console.log(typeof function(){ }); // "function"
+console.log(typeof Math.sqrt); // "function"
+console.log(typeof class C { }); // "function"
+console.log(typeof Symbol()); // "symbol"
+```
+
+### โอเปอเรเตอร์วงเล็บ
+
+```js
+var a = 1 + 2 * 3 + 5;
+// จะเสมือนเขียนเป็น var a = 1 + (2 * 3) + 5;
+console.log(a); // 12
+```
+
+```js
+var a = (1 + 2) * (3 + 5);
+console.log(a); // 24
+```
+
+### โอเปอเรเตอร์คอมม่า
+
+```js
+var a = 1, b = 2;
+var x = (1+34, a+=2, b*=10, b+1);
+console.log(x); // 21
+```
+
+### โอเปอเรเตอร์ void
+
+```js
+var a = void 12;
+console.log(a); // undefined
+console.log(Math.ceil(4.4)); // 5
+console.log(void Math.ceil(4.4)); // undefined
+var b = 1;
+console.log(void (++b)); // undefined
+console.log(b); // แสดงค่าออกมาเป็น 2 เพราะตัวแปร b ถูกบวกเพิ่มไป 1 ค่า
+```
+
+## อาร์เรย์
+```js
+[1, 1, 1, true, "Array"]; // อาร์เรย์
+```
+
+```js
+var a = ["a", "b", "c", "d", "e"];
+console.log(typeof a); // "object"
+console.log(a[0], a[1], a[2], a[3], a [4]); // "a b c d e"
+```
+
+```js
+var array = [ ]; // ประกาศเป็นอาร์เรย์ว่าง
+array[0] = 1;
+array[1] = 2;
+```
+
+```js
+var array = [1, 2, 3, 4, 5];
+console.log(array.length); // 5
+```
+
+```js
+var array = [1, 2, 3, 4, 5];
+console.log(array.length); // 5
+array.length = 7; // เพิ่มขนาดอาร์เรย์จาก 5 เป็น 7
+console.log(array); // [ 1, 2, 3, 4, 5, <2 empty slots> ]
+console.log(array.length); // 7
+array[9] = 100;
+console.log(array); // [ 1, 2, 3, 4, 5, <4 empty slots>, 100 ]
+console.log(array.length); // 10
+```
+
+## การประกาศฟังก์ชัน
+
+```js
+function calculate(param1, param2) {
+ return param1 * param2;
+}
+
+var result = calculate(10, 2);
+console.log(result); // 20
+```
+
+```js
+function calculate() {
+ return 20;
+}
+var result = calculate();
+console.log(result); // 20
+
+calculate(); // คืนค่า 20
+calculate(); // คืนค่า 20
+calculate(); // คืนค่า 20
+```
+## ประโยค return
+
+```js
+function myFunction() {
+ return 1;
+ console.log("myFunction"); // บรรทัดนี้เส้นทางการทำงานของโปรแกรมจะมาไม่ถึง
+}
+var result = myFunction();
+console.log(result); // 1
+```
+
+```js
+function myFunction() {
+ return;
+}
+var result = myFunction();
+console.log(result); // undefined
+```
+
+```js
+function myFunction() {
+ console.log("myFunction");
+ // จะเสมือนมีประโยค return undefined; วางไว้ตำแหน่งสุดท้าย ก่อนฟังก์ชันจบการทำงาน
+}
+var result = myFunction(); // "myFunction"
+console.log(result); // undefined
+```
+
+```js
+var result = calculate();
+console.log(result); // 20
+function calculate() {
+ return 20;
+}
+```
+
+### ฟังก์ชันไร้ชื่อ
+
+```js
+function (param1, param2) { // ถ้ารันจะเกิด error
+ return param1 * param2;
+}
+```
+
+### นิพจน์ฟังก์ชัน
+
+```js
+var calculate = function (param1, param2) {
+ return param1 * param2;
+}
+console.log(calculate(10, 2)); // 20
+calculate = 100; // ตัวแปร calculation สามารถแก้ไขให้เป็นค่าอื่นได้
+console.log(calculate); // 100
+```
+
+```js
+var calculate = function calc2(param1, param2) {
+ return param1 * param2;
+}
+console.log(calculate(10, 2)); // 20
+```
+
+```js
+function cal(a, b) {
+ console.log(a * b);
+}
+```
+
+```js
+cal = function(a, b) {
+ console.log(a*b);
+}
+
+var myFunction = cal;
+
+myFunction(5,4); // 20
+cal(5,4); // 20
+```
+
+### ฟังก์ชันคอลแบ็ค
+
+```js
+function sayHi() {
+ console.log("Hi");
+}
+function sayBye() {
+ console.log("Bye");
+}
+function say(func) {
+ func(); // เรียกฟังก์ชันให้ทำงาน
+}
+say(sayHi); // "Hi"
+say(sayBye); // "Bye"
+```
+
+### รีเทิร์นออกมาเป็นฟังก์ชัน
+
+```js
+function say(func) {
+ console.log("Say...");
+ function sayHi() {
+ console.log("Hi");
+ }
+ return sayHi; // รีเทิร์นฟังก์ชัน
+} // สิ้นสุดการประกาศฟังก์ชัน
+var hi = say(); // "Say..."
+hi(); // "Hi"
+```
+
+```js
+function say(func) {
+ console.log("Say...");
+ return function() { // รีเทิร์นฟังก์ชันไร้ชื่อ
+ console.log("Hi");
+ }
+} // สิ้นสุดการประกาศฟังก์ชัน
+var hi = say(); // "Say..."
+hi(); // "Hi"
+```
+
+### อ็อบเจ็กต์ arguments
+
+```js
+function myFunction(param1, param2) {
+ console.log(param1, param2);
+}
+myFunction(); // undefined undefined
+myFunction(100); // 100 undefined
+myFunction(100,200); // 100 200
+myFunction(100,200,300,400); // 100 200
+```
+
+```js
+function myFunction (param1, param2) {
+ console.log(arguments);
+}
+myFunction(100,200,300,400); // [Arguments] { '0': 100, '1': 200, '2': 300, '3': 400 }
+```
+
+### ข้อควรระวังในการประกาศฟังก์ชัน
+
+* 1)
+```js
+function myFunction(param1, param2) { // ฟังก์ชันนี้ไม่เคยถูกเรียกใช้งาน
+ console.log("function1 value:", param1, param2);
+}
+myFunction(100, 200); // เรียกใช้ฟังก์ชันที่ประกาศอยู่ด้านล่าง
+function myFunction(param) { // จะโอเวอร์ไรด์ทับฟังก์ชันที่ประกาศไว้ก่อนหน้านี้
+ console.log("function2 value:", param);
+}
+myFunction(100);
+myFunction(100, 200);
+/* แสดงผลลัพธ์เป็น
+"function2 value: 100"
+"function2 value: 100"
+"function2 value: 100" */
+```
+
+* 2)
+```js
+alert = function(data) { // alert ถูกกำหนดให้เป็นฟังก์ชันตัวใหม่
+ console.log(data); // แสดงข้อความออกทางหน้าคอนโซล
+}
+alert("Hello, World"); // แสดงข้อความ "Hello, World" ออกทางหน้าคอนโซล
+```
+
+* 3)
+```js
+function todo(a, a, a) { // ประกาศพารามิเตอร์ชื่อ a ซ้ำกัน
+ console.log(a);
+}
+todo(1, 5, 10); // 10
+```
+
+### ขอบเขตการมองเห็นของตัวแปร
+
+```js
+if(true) {
+ var a = 1; // a มีขอบเขตการมองเห็นแบบโกลบอล
+}
+{
+ var b = 2; // b มีขอบเขตการมองเห็นแบบโกลบอล
+}
+console.log(a, b); // 1 2
+```
+
+```html
+
+
+
+
+
+
+
+```
+
+```js
+console.log(NaN, undefined, Infinity); // NaN undefined Infinity
+console.log(window.NaN, window.undefined, window.Infinity); // NaN undefined Infinity
+// ถ้ารันอยู่ใน Node.js
+// console.log(global.NaN, global.undefined, global.Infinity);
+// NaN undefined Infinity
+```
+
+### ฟังก์ชันซ้อนฟังก์ชัน
+
+```js
+function outerFunc() {
+ var value = 0;
+ function innerFunc() {
+ console.log(++value);
+ }
+ return innerFunc;
+}
+var func1 = outerFunc(); // บรรทัด a
+func1(); // 1
+func1(); // 2
+var func2 = outerFunc(); // บรรทัด b
+func2(); // 1
+func2(); // 2
+```
+
+```js
+function cumulative(num) {
+ n = num
+ return function(a) {
+ n += a
+ console.log("answer = ", n)
+ }
+}
+cumA= cumulative(100)
+cumA(1) // "answer = 101"
+cumA(1) // "answer = 102"
+cumA(1) // "answer = 103"
+cumB = cumulative(20)
+cumB(-1) // "answer = 19"
+cumB(-1); // "answer = 18"
+cumB(-1); // "answer = 17"
+```
+
+```js
+function part_cal(x) {
+ return function(y) {
+ return function(z) {
+ console.log(x+y+z); // บรรทัด a
+ }
+ }
+}
+part_cal(10)(20)(30) // 60
+```
+
+```js
+function cal(x, y, z) {
+ console.log(x + y + z)
+}
+cal(10, 20 , 30) // 60
+```
+
+
+## Hoist
+```js
+var value = 100;
+```
+
+```js
+console.log(x) // เกิด error
+x = 1
+/* แบบนี้ไม่เกิด error
+ x = 1
+ console.log(x) */
+```
+
+```js
+console.log(x) // undefined
+var x = 1
+```
+
+```js
+x = undefined // เสมือนลอยขึ้นไปข้างบน
+console.log(x) // undefined
+x = 1
+```
+
+```js
+function myFunction(num) {
+ // สามารถมองเห็นตัวแปร value
+ console.log(value); // undefined
+ if(num > 10) {
+ var value = num*10; // ประกาศตัวแปร value ที่ตรงนี้ แต่มองเห็นได้ทั่วฟังก์ชัน
+ /* ซอร์สโค้ด */
+ } else {
+ // ถ้าเงื่อนไขประโยค if เป็นเท็จ ก็จะเข้ามาทำงานที่ else
+ // ซึ่งจะเห็นตัวแปร value มีค่าเป็น undefined
+ console.log(value); // undefined
+ }
+ // สามารถมองเห็นตัวแปร value ได้ หลังจากประโยค if …else ทำงานเสร็จสิ้น
+ console.log(value);
+}
+```
+
+```js
+function myFunction(num) {
+ var value; // ประกาศตัวแปร value โดยไม่มีค่าเริ่มต้น จึงทำให้มีค่าเป็น undefined
+ console.log(value); // undefined
+ if(num > 10) {
+ value = num*10; // บรรทัดนี้เป็นเพียงการกำหนดค่าให้กับตัวแปร value
+ /* ซอร์สโค้ด */
+ } else {
+ console.log(value); // undefined
+ }
+ console.log(value);
+}
+```
+
+```js
+// สามารถมองเห็นตัวแปร value
+console.log(value); // undefined
+if(true) {
+ var value = 100; // ประกาศตัวแปรแบบ var
+}
+console.log(value); // 100
+```
+
+```js
+var value; // ประกาศตัวแปร value โดยไม่มีค่าเริ่มต้น จึงทำให้มีค่าเป็น undefined
+console.log(value); // undefined
+if(true) {
+ value = 100; // บรรทัดนี้เป็นเพียงการกำหนดค่าให้กับตัวแปร value
+}
+console.log(value); // 100
+```
+
+```js
+// มองเห็นฟังก์ชันก่อนการประกาศใช้งาน
+myFunction(); // "Hoisted"
+function myFunction() {
+ console.log("Hoisted");
+}
+myFunction(); // "Hoisted"
+```
+
+```js
+function outerFunc() {
+ innerFunc(); // มองเห็นฟังก์ชันก่อนการประกาศใช้งาน
+ function innerFunc() {
+ console.log("inner function");
+ }
+}
+outerFunc(); // "inner function"
+console.log(typeof innerFunc); // undefined
+```
+
+## สตริคท์โหมด
+
+```js
+"use strict"; // ประกาศโหมดสตริคท์ ด้วยการเขียนไว้ที่ตอนต้นของไฟล์
+var x = 1;
+```
+
+```js
+function myFunction() {
+ "use strict"; // เฉพาะฟังก์ชันนี้จะอยู่ในโหมดสตริคท์
+ var x = 1;
+}
+```
+
+* 1)
+
+* หมายเหตุ ถ้าไม่เกิด error ให้รันคำส่ง delete x; ก่อน เพื่อลบตัวแปร var x = 1; ที่รันก่อนหน้านี้ จะได้เกิด error ตามตัวอย่าง
+```js
+"use strict";
+x = 1; // เกิด error เพราะไม่ได้ประกาศตัวแปรแบบ var ถ้าอยู่ดี ๆ จะมากำหนดค่าให้ทันทีแบบนี้จะทำไม่ได้
+```
+
+* 2)
+
+```js
+"use strict";
+function x(a, a) { }; // เกิด error เพราะประกาศพารามิเตอร์ ที่มีชื่อ a ซ้ำกัน
+```
+
+* 3)
+
+```js
+"use strict";
+var x = 1;
+delete x; // เกิด error ไม่สามารถลบตัวแปรได้
+```
+
+* 4)
+
+```js
+"use strict";
+delete Object.prototype; //เกิด error เพราะพร็อพเพอร์ตี้ตัวนี้ห้ามลบ
+```
+
+* 5)
+
+```js
+"use strict";
+var x = 010; // เกิด error ไม่สามารถประกาศแบบนี้ได้
+var y = \010; // เกิด error ไม่สามารถประกาศแบบนี้ได้
+```
+
+* 6)
+
+```js
+"use strict";
+var obj = { };
+Object.defineProperty(obj, "x", {value:0, writable:false});
+obj.x = 1; // เกิด error เนื่องจากมันเป็นพร็อพเพอร์ตี้ที่อ่านค่าได้อย่างเดียว
+```
+
+* 7)
+
+```js
+"use strict";
+var obj = {get x() {return 0} };
+obj.x = 1; // เกิด error ไม่สามารถกำหนดค่าให้กับ x ได้
+```
+
+* 8)
+
+```js
+"use strict";
+var obj = { };
+Object.preventExtensions(obj);
+obj.a= 1; // เกิด error ไม่สามารถเพิ่มพร็อพเพอร์ตี้เข้าไปในอ็อบเจ็กต์ได้
+```
+
+* 9)
+
+```js
+"use strict";
+function f() { return this; }
+console.log(f()); // undefined
+```
+
+* 10)
+
+```js
+"use strict";
+var eval = 1; // เกิด error ไม่สามารถใช้ชื่อ eval เป็นตัวแปร
+```
+
+* 11)
+
+```js
+"use strict";
+var arguments = 1; // เกิด error ไม่สามา รถใช้ชื่อ arguments เป็นตัวแปร
+```
+
+* 12)
+
+```js
+"use strict";
+with (Math) { a = cos(1) }; // เกิด error ไม่สามารถใช้ประโยคคำสั่ง with ได้
+```
+
+* 13)
+
+```js
+"use strict";
+eval("var x = 1;"); // ประกาศตัวแปร x ด้วย eval()
+x = 2; // เกิด error
+// แบบนี้จะไม่เกิด error
+// eval("var x = 1; x = 2;"); // ไม่เกิด error
+```
+
+* 14)
+
+```js
+"use strict";
+var implements =1; // เกิด error เพราะ implements คือคำสงวนในโหมดสตริคท์
+```
+
+* 15)
+
+```js
+"use strict";
+if(true) {
+ function myFunction1(){ } // ขอบเขตแบบโลคอล
+}
+{
+ function myFunction2(){ } // ขอบเขตแบบโลคอล
+}
+console.log(typeof myFunction1); // undefined (ถ้าไม่ใช่โหมดสตริคท์จะแสดงค่าเป็น "function")
+console.log(typeof myFunction2); // undefined (ถ้าไม่ใช่โหมดสตริคท์จะแสดงค่าเป็น "function")
+```
+
+```js
+"use strict";
+var isStrict = (function() { return !this; })( );
+console.log(isStrict); // true
+```
diff --git a/examples_book/Chapter03/js/myScript_1.js b/examples_book/Chapter03/js/myScript_1.js
new file mode 100644
index 0000000..ade84ee
--- /dev/null
+++ b/examples_book/Chapter03/js/myScript_1.js
@@ -0,0 +1 @@
+alert("Hello");
\ No newline at end of file
diff --git a/examples_book/Chapter03/js/myScript_2.js b/examples_book/Chapter03/js/myScript_2.js
new file mode 100644
index 0000000..e3c1dc9
--- /dev/null
+++ b/examples_book/Chapter03/js/myScript_2.js
@@ -0,0 +1 @@
+alert("Good Bye");
diff --git a/examples_book/Chapter04.md b/examples_book/Chapter04.md
new file mode 100644
index 0000000..53e89c7
--- /dev/null
+++ b/examples_book/Chapter04.md
@@ -0,0 +1,491 @@
+# โค้ดบทที่ 4 ทบทวนประโยคคำสั่งเบื้องต้น
+
+## บล็อก
+
+บล็อก (Block) ในจาวาสคริปต์ คือการใช้เครื่องหมายปีกกาเปิดและปิด ({ …} ) เพื่อรวมกลุ่มประโยคคำสั่งต่าง ๆ โดยมันจะมีโครงสร้างดังต่อไปนี้
+
+
+```notrun
+{
+ ประโยคคำสั่ง_1;
+ ประโยคคำสั่ง_2;
+ ...
+ ประโยคคำสั่ง_n;
+}
+```
+
+```js
+{
+ var a = 2; // ประโยคคำสั่ง 1
+ a++; // ประโยคคำสั่ง 2
+ console.log(a); // ประโยคคำสั่ง 3
+}
+```
+
+```js
+if (true) {
+ var a = 2; // ประโยคคำสั่ง 1
+ a++; // ประโยคคำสั่ง 2
+ console.log(a); // ประโยคคำสั่ง 3
+}
+```
+## ประโยควนลูป
+
+### ประโยคคำสั่ง while
+
+```notrun
+while(condition) {
+ statement
+}
+// ถ้ามีประโยคคำสั่งในบอดี้เพียงตัวเดียว ก็สามารถเขียนสั้นๆ โดยไม่ต้องมีเครื่องหมาย {} ครอบ
+while(condition) statement;
+```
+
+```js
+var i = 0;
+while (i < 3) {
+ console.log(i);
+ i++;
+}
+/* แสดงผลลัพธ์
+0
+1
+2 */
+```
+
+### ประโยคคำสั่ง do …while
+```notrun
+do {
+ statement
+} while(condition);
+// ถ้ามีประโยคคำสั่งในบอดี้เพียงตัวเดียว ก็สามารถเขียนสั้นๆ โดยไม่ต้องมีเครื่องหมาย {} ครอบ
+do
+ statement
+while(condition);
+```
+
+```js
+var i = 0;
+do {
+ console.log(i);
+ i++;
+} while (i < 3);
+/* แสดงผลลัพธ์
+0
+1
+2 */
+```
+
+### ประโยคคำสั่ง for
+```notrun
+for ([expr1]; [expr2]; [expr3]) {
+ statement
+}
+// ถ้ามีประโยคคำสั่งในบอดี้เพียงตัวเดียว ก็สามารถเขียนสั้นๆ โดยไม่ต้องมีเครื่องหมาย {} ครอบ
+for ([expr1]; [expr2]; [expr3]) statement;
+```
+
+```js
+for(var i=0; i<3; i++) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+0
+1
+2 */
+```
+
+### ประโยคคำสั่ง continue
+```js
+for(var i=0; i<3; i++) {
+ if(i<=1) {
+ continue; // ข้ามประโยคคำสั่งที่เหลือ ไปทำงานรอบถัดไปแทน
+ }
+ console.log(i);
+}
+// แสดงผลลัพธ์
+// 2
+```
+
+### ประโยคคำสั่ง break
+
+```js
+for(var i=0; i<3; i++) {
+ if(i==2) {
+ break; // ยุติการทำงานของ for
+ }
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+0
+1 */
+```
+
+### ประโยคคำสั่ง label
+
+```js
+outer: for(var i=0; i < 2; i++) { // บรรทัด a
+ console.log("i: ", i);
+ for (var j=i; j < 2; j++ ) {
+ if ( j == 1) {
+ continue outer; // บรรทัด b
+ }
+ console.log("j: ", j);
+ } // สิ้นสุดประโยคคำสั่ง for
+} // สิ้นสุดประโยคคำสตั่ง for ที่ได้ติดฉลาก outer:
+/* แสดงผลลัพธ์
+"i: 0"
+"j: 0"
+"i: 1" */
+```
+
+```js
+outer: while(true) { // บรรทัด a
+ for (var i=0; i < 3; i++ ) {
+ if ( i == 1) {
+ break outer; // บรรทัด b
+ }
+ console.log("i: ", i);
+ } // สิ้นสุดประโยคคำสั่ง for
+} // สิ้นสุดประโยคคำสั่ง while
+// แสดงผลลัพธ์
+// "i: 0"
+```
+
+## ประโยคเลือกเส้นทางการทำงาน
+
+### ประโยคคำสั่ง if
+```notrun
+if (condition) {
+ statement
+}
+```
+
+```notrun
+if (condition) {
+ ประโยคคำสั่ง_1
+} else {
+ ประโยคคำสั่ง_2
+}
+```
+
+```notrun
+if (เงื่อนไข_1) {
+ ประโยคคำสั่ง_1
+} else if (เงื่อนไข_2) {
+ ประโยคคำสั่ง_2
+} else if (เงื่อนไข_3) {
+ ประโยคคำสั่ง_3
+}
+...
+else { // มีหรือไม่มีก็ได้
+ ประโยคคำสั่ง_N // เข้ามาทำงานก็ต่อเมื่อไม่ตรงกับเงื่อนไขใดๆ ใน if ก่อนหน้านี้เลย
+}
+```
+
+```notrun
+if (เงื่อนไข_1)
+ ประโยคคำสั่ง_1
+else if (เงื่อนไข_2)
+ ประโยคคำสั่ง_2
+...
+else if (เงื่อนไข_N)
+ ประโยคคำสั่ง_N
+else
+ ประโยคคำสั่ง_Z
+```
+
+```js
+// var i = 1;
+// var i = 2;
+// var i = 3;
+if(i == 1)
+ console.log("if statement");
+else if(i == 2)
+ console.log("else if statement");
+else
+ console.log("else statement");
+```
+
+### ประโยคคำสั่ง switch
+```notrun
+switch (นิพจน์_switch) {
+ case value1:
+ // เมื่อนิพจน์_switch มีค่าตรงกับ value1 เส้นทางการทำงานก็จะเริ่มจากจุดนี้เป็นต้นไป
+ [ประโยคคำสั่ง]
+ [break;]
+ case value2:
+ // เมื่อนิพจน์_switch มีค่าตรงกับ value2 เส้นทางการทำงานก็จะเริ่มจากจุดนี้เป็นต้นไป
+ [ประโยคคำสั่ง]
+ [break;]
+...
+ case valueN:
+ // เมื่อนิพจน์_switch มีค่าตรงกับ valueN เส้นทางการทำงานก็จะเริ่มจากจุดนี้เป็นต้นไป
+ [ประโยคคำสั่ง]
+ [break;]
+ default:
+ // เมื่อนิพจน์_switch ไม่ตรงกับค่าที่อยู่ด้านหลัง case ตัวใดเลย
+ // เส้นทางการทำงานก็จะเริ่มจากจุดนี้เป็นต้นไป
+ [ประโยคคำสั่ง]
+ [break;]
+}
+```
+
+```js
+// var i = 1;
+// var i = 2;
+// var i = 3;
+switch (i) {
+ case 1:
+ console.log("case1"); // ถ้า i มีค่าเป็น 1 ก็จะมาทำประโยคนี้
+ break; // ออกจากประโยค switch
+ case 2:
+ console.log("case2"); // ถ้า i มีค่าเป็น 2 ก็จะมาทำประโยคนี้
+ break; // ออกจากประโยค switch
+ default:
+ console.log("case_default"); // ถ้า i ไม่ใช่ 1 กับ 2 ก็จะมาทำประโยคนี้
+}
+```
+
+```js
+switch (1) {
+ case 1:
+ console.log("case1");
+ case 2:
+ console.log("case2");
+ default:
+ console.log("case_default");
+}
+/* แสดงผลลัพธ์เป็น
+"case1"
+"case2"
+"case_default" */
+```
+
+```js
+switch (1) {
+ case 1:
+ case 2:
+ default:
+ console.log("case_default");
+}
+// แสดงผลลัพธ์เป็น
+// "case_default"
+```
+
+### โอเปอเรเตอร์แบบเงื่อนไข
+```notrun
+เงื่อนไข ? นิพจน์_1 : นิพจน์_2
+```
+
+```js
+// var condition = true;
+// var condition = false;
+var value = condition ? "foo" : "bar";
+console.log(value); // "foo" หรือ "bar"
+```
+
+```js
+// var condition = true;
+// var condition = false;
+var value;
+if(condition) {
+ value = "foo";
+} else {
+ value = "bar";
+}
+console.log(value); // "foo" หรือ "bar"
+```
+
+## ประโยคคำสั่งว่าง
+```js
+;
+```
+
+```js
+while(true); // วนลูปไม่รู้จบ
+// หรือจะใช้ในประโยค for
+for(;;); // วนลูปไม่รู้จบ
+```
+
+## การจัดการความผิดพลาด
+
+```js
+throw "Error"; // โยน exception เป็นชนิดข้อมูลสตริง
+throw 100; // โยน exception เป็นชนิดข้อมูลตัวเลข
+throw true; // โยน exception เป็นชนิดข้อมูลบูลีน
+throw new Object(); // โยน exception เป็นชนิดข้อมูลอ็อบเจ็กต์
+throw new Error("Error") // โยน exception เป็นชนิดข้อมูลอ็อบเจ็กต์
+```
+
+```js
+console.log(x); // ReferenceError
+```
+
+```js
+new Error(["ข้อความ error"])
+```
+
+```js
+throw new SyntaxError ("Syntax error");
+```
+
+### ประโยคคำสั่งจัดการความผิดพลาด
+```js
+try {
+ console.log(x); // บรรทัด a เกิด error
+ x++; // บรรทัด b
+} catch (e) {
+ console.log(typeof e); // "object"
+ console.log(e.message); // "x is not defined"
+ console.log(e.name); // "ReferenceError"
+}
+console.log("Last statement"); // บรรทัด c
+/* แสดงผลลัพธ์เป็น
+"object"
+"x is not defined"
+"ReferenceError"
+"Last statement" */
+```
+
+```js
+try {
+ throw 42; // โยน exception ออกมาเอง
+ console.log(42); // เส้นทางการทำงานของโปรแกรมจะมาไม่ถึง
+} catch (e) {
+ console.log(e); // 42
+}
+console.log("Last statment");
+/* แสดงผลลัพธ์
+42
+"Last statment" */
+```
+
+```js
+try {
+ console.log(x); // บรรทัด a เกิด error
+} catch (e) {
+ console.log(e.message); // "x is not defined"
+} finally {
+ console.log("finally");
+}
+console.log("Last statement");
+/* แสดงผลลัพธ์
+"x is not defined"
+"finally";
+"Last statement" */
+```
+
+```js
+try {
+ console.log("no error"); // บรรทัด a ทำงานปกติ
+} catch (e) {
+ console.error(e.message);
+} finally {
+ console.log("finally");
+}
+console.log("Last statement ");
+/* แสดงผลลัพธ์
+"no error"
+"finally";
+"Last statement" */
+```
+
+```js
+function foo() {
+ try {
+ return "foo";
+ } finally {
+ console.log("finally");
+ }
+}
+console.log(foo());
+/* แสดงผลลัพธ์
+"finally";
+"foo"; */
+```
+
+```js
+function foo() {
+ try {
+ console.log(x); // บรรทัด a เกิด error
+ return "foo";
+ } finally{
+ console.log("finally"); // บรรทัด b ทำงาน
+ }
+}
+console.log(foo()); // บรรทัด c ไม่เข้ามาทำงาน
+/* แสดงผลลัพธ์
+"finally"
+จากนั้นจะจบการทำงานพร้อมแจ้ง error ว่า
+"Uncaught ReferenceError: x is not defined"
+*/
+```
+
+### Optional Catch Binding
+
+```js
+try {
+ console.log(x); // บรรทัด a เกิด error
+} catch { // มาตรฐานใหม่ ด้านหลัง catch ไม่จำเป็นต้องมีวงเล็บ ไม่ต้องระบุชื่อตัวแปร
+ console.log("Error");
+}
+/* แสดงผลลัพธ์
+"Error" */
+```
+
+```js
+try {
+ console.log(x); // บรรทัด a เกิด error
+} catch(e) { // มาตรฐานเก่า ด้านหลัง catch ต้องมีวงเล็บแล้วให้ระบุชื่อตัวแปร
+ console.log("Error");
+}
+/* แสดงผลลัพธ์
+"Error" */
+```
+
+### cause ใน error
+
+```js
+new Error(
+ "My error", // ค่าอากิวเมนต์ตัวแรก
+ {cause: "otherError"} // ค่าอากิวเมนต์ตัวที่สอง
+ );
+```
+
+```js
+try {
+ console.log(x); // บรรทัด a
+ } catch (error) {
+ throw new Error(
+ "My Error",
+ {cause: error}
+ );
+}
+/* โปรแกรมจะตาย และแจ้ง error ออกมา */
+```
+
+### ทิ้งท้าย
+```js
+try {
+ va a=1 // บรรทัด a เกิด SyntaxError
+} catch {
+ console.log("Error");
+} finally {
+ console.log("finally");
+}
+/* โปรแกรมจะตาย และแจ้งว่าเกิด SyntaxError ออกมา */
+```
+
+```js
+try {
+ throw new SyntaxError() // บรรทัด a เกิด SyntaxError
+} catch {
+ console.log("Error");
+} finally {
+ console.log("finally");
+}
+/* แสดงผลลัพธ์
+"Error"
+"finally" */
+```
diff --git a/examples_book/Chapter05.md b/examples_book/Chapter05.md
new file mode 100644
index 0000000..b32fbc7
--- /dev/null
+++ b/examples_book/Chapter05.md
@@ -0,0 +1,987 @@
+# โค้ดบทที่ 5 ทบทวนอ็อบเจ็กต์
+
+## วิธีสร้างอ็อบเจ็กต์อย่างง่าย
+
+```js
+var font = { };
+```
+
+```js
+var font = {
+ color: "red", // คีย์ชื่อ color : ข้อมูลเป็นสตริง "red"
+ myFunction: function (param) { // คีย์ชื่อ myFunction : ข้อมูลเป็นเมธอด (ฟังก์ชัน)
+ /* ซอร์สโค้ดของเมธอดอยู่นี้ */
+ },
+ option: { // คีย์ชื่อ option : ข้อมูลเป็นอ็อบเจ็กต์ (อ๊อบเจ็กต์ซ้อนอ๊อบเจ็กต์)
+ value: 1
+ }
+};
+```
+
+## การเข้าถึงพร็อพเพอร์ตี้
+
+```js
+var obj = {
+ a: 1, // กำหนดให้ a มีค่าตั้งต้นเป็น 1
+ myFunction : function() {
+ console.log("call myFunction");
+ }
+};
+obj.a = 100; // กำหนดให้ obj.a มีค่าเป็น 100
+console.log(obj.a); // 100
+console.log(typeof obj.myFunction); // "function"
+obj.myFunction(); // "call myFunction"
+```
+
+## การใช้วงเล็บเหลี่ยม
+
+```js
+var student = {
+ "First name": "Somchai",
+ "Last name": "Jaidee",
+ "Who are you": function() {
+ console.log("I'm a student");
+ },
+ nickname: "Tom"
+};
+console.log(student["First name"]); // "Somchai"
+var lastName = "Last name";
+console.log(student[lastName]); // "Jaidee"
+student["Who are you"](); // "I'm a student"
+console.log(student.nickname); // "Tom"
+console.log(student["nickname"]); // "Tom"
+```
+
+```js
+var obj = {
+ 1: 1,
+ true: 2,
+ null : 3,
+ undefined: 4
+};
+console.log(obj[1 + 0]); // 1
+console.log(obj[true && true]); // 2
+console.log(obj[null]); // 3
+console.log(obj[undefined]); // 4
+```
+
+```js
+var obj = {
+ { }: 1 // เกิด SyntaxError ไม่สามารถใช้อ็อบเจ็กต์เป็นคีย์โดยตรง
+};
+```
+
+## เพิ่มพร็อพเพอร์ตี้เข้าไปทีหลัง
+
+```js
+var obj = { };
+obj.a = 1; // เพิ่มพร็อพเพอร์ตี้ที่เป็นตัวแปร a
+obj[1]=100; // เพิ่มพร็อพเพอร์ตี้ที่มีคีย์เป็นตัวเลข 1
+obj["property name"]= 200; // เพิ่มพร็อพเพอร์ตี้ที่มีคีย์เป็นสตริง "property name"
+obj.myFunction = function() { // เพิ่มพร็อพเพอร์ตี้ที่เป็นเมธอด
+ console.log("to do something");
+};
+console.log(obj.a); // 1
+console.log(obj[1]); // 100
+console.log(obj["property name"]); // 200
+obj.myFunction(); // "to do something"
+```
+
+```js
+var obj = { };
+var key = { };
+obj[key] = 100; // มีคีย์เป็นอ็อบเจ็กต์ว่าง
+console.log(obj[key]); // 100
+```
+
+## การส่งค่าให้ตัวแปร
+
+```js
+function myFunction(param1, param2) {
+ param1.a = 3; // pass by reference
+ param2 = 200; // pass by value
+}
+var obj = {a:1, b:2}, value = 100;
+myFunction(obj, value);
+console.log(obj.a); // 3
+console.log(value); // 100
+```
+
+```js
+var obj1 = {a:1, b:2};
+var obj2 = obj1; // บรรทัด a -- pass by reference
+obj2.a = 3; // บรรทัด b
+console.log(obj1.a); // 3
+var value1 = 1;
+var value2 = value1; // บรรทัด d -- pass by value
+value2 = 3; // บรรทัด e
+console.log(value1); // 1
+```
+
+## การเปรียบเทียบความเท่ากัน
+
+```js
+console.log( {a:1} == {a:1} ); // false
+console.log( {a:1} === {a:1} ); // false
+```
+
+```js
+var a = 1, b = 1;
+console.log(a == b); // true
+console.log(a === b); // true
+```
+
+## this
+
+```js
+var obj = {
+ a: 1,
+ foo: function() {
+ return 2;
+ },
+ bar: function() {
+ console.log(this.a);
+ },
+ zoo: function() {
+ console.log(this.foo());
+ }
+};
+obj.bar(); // 1
+obj.zoo(); // 2
+```
+
+```js
+var obj = {
+ foo: function () {
+ this.a = 1; // เพิ่มตัวแปร a เข้าไปในอ็อบเจ็กต์
+ console.log(this.a);
+ },
+ bar: function() {
+ console.log(this.a);
+ }
+};
+obj.foo(); // 1
+obj.bar(); // 1
+console.log(obj.a); // 1
+```
+
+### การผูก this ไว้กับอ็อบเจ็กต์
+
+```js
+var obj1 = { };
+var obj2 = {
+ a: 1,
+ bar : function() {
+ console.log("this.a =", this.a);
+ obj1.foo = function() { // บรรทัด a
+ console.log("this.a =", this.a);
+ } // สิ้นสุดการประกาศฟังก์ชัน foo()
+ } // สิ้นสุดการประกาศฟังก์ชัน bar()
+};
+obj2.bar(); // "this.a = 1"
+obj1.foo(); // "this.a = undefined"
+```
+
+### this ในฟังก์ชัน
+
+```js
+//"use strict";
+function myFunction() {
+ return this;
+}
+var obj = myFunction();
+console.log(typeof obj);
+// แสดงผลลัพธ์เป็น
+// undefined (ถ้าเป็นโหมดสตริคท์)
+// "object" (ถ้าไม่ใช่โหมดสตริคท์)
+```
+
+### เมธอด call() apply() และ bind()
+
+```js
+var obj1 = {
+ value: 20
+};
+var obj2 = {
+ myFunction: function(param1, param2) {
+ var value = this.value; // this จะชี้ไปยัง obj1
+ console.log(param1, param2, value);
+ }
+}
+obj2.myFunction(1, 10); // 1 10 undefined
+obj2.myFunction.call(obj1, 1, 10); // 1 10 20
+obj2.myFunction.apply(obj1, [1, 10]); // 1 10 20
+var f = obj2.myFunction.bind(obj1, 1, 10);
+f(); // 1 10 20
+```
+
+## พร็อพเพอร์ตี้แอคเซสเซอร์
+
+```js
+var font = { color: "red" } ;
+font.color = "blue";
+```
+
+```js
+var font = {
+ set color(param) { // ประกาศเมธอด setter โดยมีพารามิเตอร์ ได้เพียงตัวเดียว
+ this.col = param; // กำหนดค่าให้กับข้อมูลภายในอ็อบเจ็กต์
+ }
+};
+font.color = "blue"; // แก้ไขค่าได้
+console.log(font.color) // undefined
+```
+
+```js
+var font = {
+ col: "red",
+ get color() { // ประกาศเมธอด getter โดยไม่ต้องมีพารามิเตอร์
+ return this.col; // รีเทิร์นข้อมูลภายในอ็อบเจ็กต์ออกไป
+ }
+};
+console.log(font.color); // "red"
+font.color = "blue"; // ไม่มีผลอะไรเกิดขึ้น หรือเกิด TypeError ในโหมดสตริคท์
+console.log(font.color); // "red"
+```
+
+```js
+var font = {
+ col: "red",
+ set color(param) {
+ this.col = param;
+ },
+ get color() {
+ return this.col;
+ }
+};
+console.log(font.color); // "red"
+font.color = "blue";
+console.log(font.color); // "blue"
+```
+
+## โอเปอเรเตอร์ delete
+* หมายเหตุ โค้ดนี้ควรรันผ่านเว็บเบราเซอร์ หรือ Node.js จะดีกว่า เพราะถ้ากดปุ่มรัน ตัวแปร a จะไม่ใช่ตัวแปรของอ็อบเจ็กต์โกลบอล จึงทำให้ประโยคคำสั่ง delete a ได้คำตอบเป็น true
+```js
+var obj = {x:1 ,y:2};
+console.log(delete obj.x); // true
+console.log(delete obj["y"]); // true
+console.log(obj); // {}
+var a = 1;
+console.log(delete a); // false หรือเกิด SyntaxError ในโหมดสตริคท์
+```
+
+```js
+console.log(delete Number.MAX_VALUE); // false หรือเกิด TypeError โหมดสตริคต์
+```
+
+```js
+var a = [1, "Hi"];
+console.log(a.length); // 2
+console.log(delete a[0]); // true
+console.log(delete a[1]); // true
+console.log(a[0]); // undefined
+console.log(a[1]); // undefined
+console.log(a.length); // 2
+```
+
+## Descriptor
+
+```js
+var obj1 = { };
+Object.defineProperty(obj1, "foo", { // อ็อบเจ็กต์ descriptor
+ value: 100,
+ writable: true
+});
+console.log(obj1.foo); // 100
+console.log(Object.getOwnPropertyDescriptor(obj1,"foo")); // รีเทิร์น descriptor
+// { value: 100, writable: true, enumerable: false, configurable: false }
+var obj2 = { };
+Object.defineProperties(obj2, {
+ "foo": { // อ็อบเจ็กต์ descriptor
+ value: "fooValue",
+ writable: true
+ },
+ "bar": { // อ็อบเจ็กต์ descriptor
+ value: "barValue",
+ writable: false
+ }
+ // พร็อพเพอร์ตี้อื่น ๆ
+});
+console.log(obj2.foo, obj2.bar); // "fooValue barValue"
+console.log(Object.getOwnPropertyDescriptor(obj2,"foo")); // รีเทิร์น descriptor
+// { value: "fooValue", writable: true, enumerable: false, configurable: false }
+console.log(Object.getOwnPropertyDescriptor(obj2,"bar")); // รีเทิร์น descriptor
+// { value: "barValue", writable: false, enumerable: false, configurable: false }
+```
+
+## ฟังก์ชันคอนสตรัคเตอร์
+
+```js
+function Car(color) {
+ this.color = color;
+ return true; // เขียนเกินมา ไม่มีผลอะไรต่อการทำงาน
+}
+var redCar = new Car("red");
+var blueCar = new Car("blue");
+//… สร้างอ็อบเจ็กต์ใหม่ได้เรื่อยด้วยโอเปอเรเตอร์ new
+console.log(redCar.color); // "red"
+console.log(blueCar.color); // "blue"
+```
+
+```js
+function Car(color) {
+ this.color = color; // ถ้าเป็นโหมดสตริคท์จะเกิด TypeError ขึ้นได้
+ return true;
+}
+var blueCar = Car("blue"); // เป็นการเรียกฟังก์ชันธรรดา
+console.log(blueCar); // true
+```
+
+```js
+function Car(color) {
+ console.log("constructor");
+}
+var redCar = new Car(); // "constructor"
+var blueCar = new Car; // "constructor"
+```
+
+## เมธอด Object.create()
+
+```js
+var car = {
+ drive: function() { console.log("driving a car") ; }
+}
+var redCar = Object.create(car);
+var blueCar = Object.create(car,
+{ // เพิ่มพร็อพเพอร์ตี้เข้าไป ด้วยการระบุ descriptor
+ foo: { writable: true, configurable: true, value: "fooValue" }, // descriptor
+ bar:{ writable: true, configurable: true, value: "barValue" } // descriptor
+}
+);
+// สร้างอ็อบเจ็กต์ใหม่ได้เรื่อย ๆ ด้วย Object.create()
+// …
+redCar.drive(); // "driving a car"
+blueCar.drive(); // "driving a car"
+console.log(blueCar.foo); // "fooValue"
+console.log(blueCar.bar); // "barValue"
+```
+
+```js
+var car = { }
+var redCar = Object.create(car);
+var blueCar = Object.create(car);
+car.drive = function() {
+ console.log("driving a car");
+}
+redCar.drive(); // "driving a car"
+blueCar.drive(); // "driving a car"
+
+console.log( Object.getPrototypeOf(redCar) === car ); // true (เพราะโปรโตไทป์คือ car)
+console.log( Object.getPrototypeOf(blueCar) === car ); // true (เพราะโปรโตไทป์คือ car)
+```
+
+```js
+var obj1 = Object.create(null); // ไม่มีโปรโตไทป์
+console.log(obj1); // {}
+console.log(Object.getPrototypeOf(obj1)); // null
+var obj2 = Object.create(Object.prototype); // จะเหมือนสร้างอ็อบเจ็กต์ด้วยวิธีนี้ var obj = {}
+console.log(obj2); // {}
+console.log(Object.getPrototypeOf(obj2) === Object.prototype); // true
+```
+
+## prototype
+
+```js
+function Car(color) {
+ this.color = color;
+}
+var redCar = new Car("red");
+console.log( Object.getPrototypeOf(redCar) === Car.prototype); // true
+```
+
+```js
+function Car(color) {
+ this.color = color;
+}
+Car.prototype.drive = function() {
+ console.log("Drive a", this.color, "car"); // this จะชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
+};
+var redCar = new Car("red");
+```
+
+```js
+function Car(color) {
+ this.color = color;
+}
+Car.prototype.drive = function() {
+ console.log("Drive a", this.color, "car"); // this จะชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
+};
+var redCar = new Car("red");
+redCar.drive(); // "Drive a red car"
+var blueCar = new Car("blue");
+blueCar.drive(); // "Drive a blue car"
+console.log( Object.getPrototypeOf(redCar) === Car.prototype); // true
+console.log( Object.getPrototypeOf(blueCar) === Car.prototype); // true
+```
+
+```js
+function Car(color) {
+ this.color = color;
+}
+Car.drive = function() {
+ console.log("driving a car");
+};
+Car.drive(); // "driving a car"
+var redCar = new Car("red");
+console.log(typeof redCar.drive); // undefined
+```
+
+## การสืบทอดสมาชิกหลายระดับชั้น
+
+```js
+var extend = {
+ drive: function() {
+ console.log("Drive a", this.color, "car");
+ }
+}
+function Car(color) {
+ this.color = color;
+}
+Car.prototype = extend; // บรรทัด a
+Car.prototype.stop = function() { // บรรทัด b
+ console.log("Stop a", this.color, "car");
+};
+var redCar = new Car("red");
+console.log( Object.getPrototypeOf(redCar) === extend ); // true
+redCar.drive(); // "Drive a red car"
+redCar.stop(); // "Stop a red car"
+```
+
+```js
+function Car(color) { }
+Car.prototype.drive = function() {
+ console.log("Drive a", this.color, "car"); // this ชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
+};
+function RedCar(color) {
+ this.color = color;
+}
+RedCar.prototype = Object.create(Car.prototype); // บรรทัด a
+console.log( Object.getPrototypeOf(RedCar.prototype) === Car.prototype ); // true
+RedCar.prototype.stop = function() {
+ console.log("Stop a", this.color, "car"); // this ชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
+}
+var redCar = new RedCar("red");
+console.log( Object.getPrototypeOf(redCar) === RedCar.prototype ); // true
+redCar.drive(); // "Drive a red car"
+redCar.stop(); // "Stop a red car"
+```
+
+## โอเปอรเตอร์ instanceof
+
+```js
+function Foo() { }
+var obj = new Foo();
+console.log(obj instanceof Foo); // true
+console.log(Object.getPrototypeOf(obj) === Foo.prototype); // true
+```
+
+```js
+function Foo() { }
+var obj = new Foo();
+console.log(obj instanceof Foo); // true
+console.log(Object.getPrototypeOf(obj) === Foo.prototype); // true
+console.log(obj instanceof Object); // true
+console.log(Foo.prototype instanceof Object); // true
+console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // true
+console.log(Object.getPrototypeOf(obj) === Object.prototype); // false
+```
+
+## prototype ที่มีอยู่ในภาษา
+
+```js
+console.log( Object.getPrototypeOf(function(){ }) === Function.prototype); // true
+console.log( Object.getPrototypeOf([ ]) === Array.prototype); // true
+console.log( Object.getPrototypeOf({ }) === Object.prototype); // true
+console.log( Object.getPrototypeOf('') === String.prototype); // true
+console.log( Object.getPrototypeOf(true) === Boolean.prototype); // true
+console.log( Object.getPrototypeOf(1) === Number.prototype); // true
+console.log(function(){ } instanceof Function); // true
+console.log([ ] instanceof Array); // true
+console.log({ } instanceof Object); // true
+console.log('' instanceof String); // false
+console.log(true instanceof Boolean); // false
+console.log(1 instanceof Number); // false
+```
+
+```js
+// ฟังก์ชัน
+Function.prototype.sayMsg = function(msg) {
+ console.log("Function say:", msg);
+};
+function myFunction() { }
+myFunction.sayMsg("Hello"); // "Function say: Hello"
+// อาร์เรย์
+Array.prototype.sayMsg = function(msg) {
+ console.log("Array say:", msg);
+};
+[ ].sayMsg("Hello"); // "Array say: Hello"
+// อ็อบเจ็กต์
+Object.prototype.sayMsg = function(msg) {
+ console.log("Object say:", msg);
+};
+var obj = { };
+obj.sayMsg("Hello"); // "Object say: Hello"
+({ }).sayMsg("Hello"); // "Object say: Hello"
+// สตริง
+String.prototype.sayMsg = function(msg) {
+ console.log("String say:", msg);
+};
+"123".sayMsg("Hello"); // "String say: Hello"
+// บูลีน
+Boolean.prototype.sayMsg = function(msg) {
+ console.log("Boolean say:", msg);
+}
+true.sayMsg("Hello"); // "Boolean say: Hello"
+// ตัวเลข
+Number.prototype.sayMsg = function(msg) {
+ console.log("Number say:", msg);
+}
+var num = 123;
+num.sayMsg("Hello"); // "Number say: Hello"
+(123).sayMsg("Hello"); // "Number say: Hello"
+```
+
+* หมายเหตุ เพื่อป้องกันความผิดจากการรันโคดด้านล่าง ก็ควรจะลบ sayMsg ก่อนหน้านี้ออกไปก่อน ด้วยโค้ดต่อไปนี้ (ในหนังสือไม่มีโค้ดชุดนี้)
+```js
+delete Function.prototype.sayMsg;
+delete Array.prototype.sayMsg;
+delete Object.prototype.sayMsg
+delete String.prototype.sayMsg
+delete Boolean.prototype.sayMsg
+delete Number.prototype.sayMsg
+```
+
+## โอเปอเรเตอร์ in
+
+```js
+var obj = {x: 1, y: 2};
+console.log("x" in obj); // true
+console.log("xyz" in obj); // false (อ็อบเจ็กต์ไม่มีพร็อพเพอร์ตี้ xyz)
+var a = ["a", "b", "c"];
+console.log(0 in a); // true (อาร์เรย์นี้มีอินเด็กซ์ 0)
+console.log(5 in a); // false (อาร์เรย์ไม่มีอินเด็กซ์ 5)
+console.log("1" in a); // true (อาร์เรย์นี้มีอินเด็กซ์ 1)
+console.log("length" in a); // true (อาร์เรย์จะมี length เป็นพร็อพเพอร์ตี้)
+```
+
+```js
+var parent = {x:1};
+var obj = Object.create(parent);
+console.log("x" in obj); // true
+```
+
+## ประโยคคำสั่ง for …in
+
+```js
+function Font() {
+ this.color = "red";
+ this.size = 200;
+}
+var coordinate = {x: 1, y: 1, z: 1}
+Font.prototype = Object.create(coordinate);
+Font.prototype.myFunction = function(){ };
+var font = new Font();
+font[1] = "fontValue";
+for(var prop in font) {
+ console.log(prop);
+}
+/* แสดงผลลัพธ์เป็น
+"1"
+"color"
+"size"
+"myFunction"
+"x"
+"y "
+"z " */
+```
+
+```js
+function Font() {
+ this.color = "red";
+ this.size = 200;
+}
+var coordinate = {x: 1, y: 1, z: 1}
+Font.prototype = Object.create(coordinate);
+Font.prototype.myFunction = function(){ };
+var font = new Font();
+font[1] = "fontValue";
+for(var prop in font) {
+ if(font.hasOwnProperty( prop ) ) { // เข้าถึงคีย์ที่อยู่ในอ็อบเจ็กต์เท่านั้น
+ console.log("font." + prop, "=", font[prop]);
+ }
+}
+/* แสดงผลลัพธ์เป็น
+"font.1 = fontValue"
+"font.color = red"
+"font.size = 200" */
+```
+
+## Object.preventExtensions() กับ Object.isExtensions()
+
+```js
+var obj1 = {};
+var obj2 = Object.preventExtensions(obj1);
+console.log(obj1 === obj2); // true
+obj1.a = 1; // จะเพิกเฉย แต่ถ้าอยู่ในโหมดสตริคท์จะเกิด TypeError
+var obj3 = Object.create(obj1);
+console.log(obj3); // {}
+obj3.a = 1; // เพิ่มพร็อพเพอร์ตี้เข้าไปได้
+console.log(Object.getPrototypeOf(obj3) === obj1); // true
+```
+
+```js
+var obj = {};
+console.log(Object.isExtensible(obj)); // true
+Object.preventExtensions(obj);
+console.log(Object.isExtensible(obj)); // false
+```
+
+## ฟังก์ชันคอนสตรัคเตอร์ที่มีในภาษา
+
+### Object
+
+```js
+var obj1 = new Object(1234);
+var obj2 = new Object(); // อ็อบเจ็กต์ว่าง
+var obj3 = new Object(undefined); // อ็อบเจ็กต์ว่าง
+var obj4 = new Object(null); // อ็อบเจ็กต์ว่าง
+var obj5 = Object(1); // เรียกแบบฟังก์ชัน (ค่าอากิวเมนต์เป็นอะไรก็ได้)
+console.log(typeof obj5); // "object"
+```
+
+### Boolean
+
+```js
+var obj = new Boolean(true);
+console.log(typeof obj); // "object"
+var b = Boolean(true);
+console.log(typeof b); // "boolean"
+console.log(b); // true
+console.log(obj == b); // true
+console.log(obj === b); // false
+```
+
+```js
+var false1 = Boolean(); // false
+var false2 = Boolean(false); // false
+var false3 = Boolean(0); // false
+var false4 = Boolean(-0); // false
+var false5 = Boolean(null); // false
+var false6 = Boolean(''); // false
+var false7 = Boolean(NaN); // false
+var false8 = Boolean(undefined); // false
+var true1 = Boolean(true); // true
+var true2 = Boolean("Hi"); // true
+var true3 = Boolean("true"); // true
+var true4 = Boolean("false"); // true
+var true5 = Boolean([]); // true
+var true6 = Boolean({}); // true
+var true7 = Boolean(true4); // true
+```
+
+### Number
+
+```js
+var obj = new Number(1);
+console.log(typeof obj); // "object"
+var n1 = Number("1"); // รับค่าเป็นสตริงก็ได้เช่นกัน
+var n2 = Number("a"); // "a" ไม่ใช่ตัวเลข จึงทำให้ตัวแปร n2 มีค่าเป็น NaN
+console.log(typeof n1, typeof n2); // "number number"
+console.log(n1, n2); // 1 NaN
+console.log(obj == n1); // true
+console.log(obj === n1); // false
+```
+
+### String
+
+```js
+var str1 = new String("MyString");
+console.log(typeof str1); // "object"
+console.log(str1 === "MyString"); // false
+var str2 = String("MyString");
+console.log(typeof str2); // "string"
+console.log(str2 === "MyString"); // true
+console.log(str1 == str2); // true
+console.log(str1 === str2); // false
+```
+
+### Array
+
+```js
+var array1 = Array( 3 ); // เรียกแบบฟังก์ชัน
+console.log(array1.length); // 3
+console.log(array1); // [ <3 empty slots> ]
+var array2 = new Array(3);
+console.log(array2.length); // 3
+console.log(array2); // [ <3 empty slots> ]
+```
+
+### Date
+
+```js
+console.log(Date()); // "Fri Sep 08 2023 21:33:45 GMT+0700 (Indochina Time)"
+console.log(new Date()); // "Fri Sep 08 2023 21:33:45 GMT+0700 (Indochina Time)"
+```
+
+```js
+console.log(new Date("05-31-2023")) // "Wed May 31 2023 00:00:00 GMT+0700 (Indochina Time)"
+console.log(new Date("09/30/2023")) // "Sat Sep 30 2023 00:00:00 GMT+0700 (Indochina Time)"
+console.log( new Date("October 20, 2023 11:13:00") );
+// "Fri Oct 20 2023 11:13:00 GMT+0700 (Indochina Time)"
+```
+
+## เมธอดของสตริง
+
+```js
+console.log( " Learning JavaScript ".trim() ); // แสดงผลเป็น "Learning JavaScript"
+```
+
+```js
+console.log( "foo_foo_foo_".indexOf("foo") ); // 0
+console.log("foo_foo_foo_".lastIndexOf("foo") ); // 8
+```
+
+```js
+"use strict";
+var str = "MyString";
+console.log(str.length) // 8
+str.length = 0; // TypeError (ถ้าไม่ใช่โหมดสตริคท์จะไม่เกิด error แต่จะเพิกเฉย)
+str.func = function(){ }; // TypeError (ถ้าไม่ใช่โหมดสตริคท์จะไม่เกิด error แต่จะเพิกเฉย)
+```
+
+## เมธอดของอาร์เรย์
+
+```js
+var array = ["a","b","c","d"];
+var str = array.join("->");
+console.log(str); // "a->b->c->d"
+```
+
+```js
+var array = [ ];
+array.push("a","b","c","d"); // เพิ่มสมาชิกกี่ตัวก็ได้
+console.log(array); // [ 'a', 'b', 'c', 'd' ]
+console.log(array.pop()); // "d"
+console.log(array); // [ 'a', 'b', 'c' ]
+```
+
+```js
+var array = ["a","b","c","d"];
+console.log(array.indexOf("c" )); // 2
+console.log(array.indexOf("e" )); // -1
+```
+
+```js
+var array = ["a","b","c","d"];
+var result = array.some( function (value, index, arrayObj) {
+ // value คือค่าสมาชิกของอาร์เรย์
+ // index คืออินเด็กซ์ของอาร์เรย์
+ // arrayObj คือ ["a", "b", "c", "d"]
+ return value == "c";
+} );
+console.log(result) // true
+```
+
+```js
+var array = ["a","b","c","d"];
+array.forEach(function (value, index, arrayObj) {
+ // value คือค่าสมาชิกของอาร์เรย์
+ // index คืออินเด็กซ์ของอาร์เรย์
+ // arrayObj คือ ["a", "b", "c", "d"]
+ console.log("a[", index, "] = ", value);
+});
+/* แสดงผลลัพธ์
+"a[ 0 ] = a"
+"a[ 1 ] = b"
+"a[ 2 ] = c"
+"a[ 3 ] = d" */
+```
+
+## ฟังก์ชันก็เป็นอ็อบเจ็กต์
+
+```js
+function foo() {
+ console.log(foo.x) // อ้างถึงพร๊อพเพอร์ตี้ x
+}
+
+foo(); // undefined
+
+foo.x = 100; // เพิ่มเข้าไป เพื่อให้ a.x หาเจอ
+console.log(foo.x) // 100
+foo(); // เรียกใช้ได้ โดยจะแสดง 100 ออกมา
+foo["x"] = true // ใช้วงเล็บเหลี่ยมในการเข้าถึง x
+foo["name"] = "My function"; // ใช้วงเล็บเหลี่ยมเพิ่มพร๊อพเพอร์ตี้ name เข้าไป
+```
+
+## เกร็ดความรู้
+
+```js
+function showData(person) {
+ console.log("Person is", person.name, ", age is", person.age );
+}
+let person = { // บรรทัด a
+ name: "Somchai",
+ age: 23
+}
+showData(person) // บรรทัด b
+/* แสดงผลลัพธ์
+"Person is Somchai , age is 23" */
+```
+
+```js
+function showData(person) {
+ console.log("Person is", person.name, ", age is", person.age );
+}
+showData({ // บรรทัด a
+ name: "Somchai",
+ age: 23
+})
+/* แสดงผลลัพธ์
+"Person is Somchai , age is 23" */
+```
+
+```js
+let obj = { first: "Jane", last: "Doe" };
+```
+
+```js
+let obj = {
+ first: "Jane",
+ last: "Doe"
+};
+```
+
+## ปูพื้นฐาน JSON
+
+### เมธอด JSON.parse() กับ JSON.stringify()
+
+```js
+// ใช้ \ เชื่อมสตริงแต่ละบรรทัดเข้าดัวยกัน
+var json = '{"bold": true,\
+ "color": "red",\
+ "size": 100\
+}';
+var obj = JSON.parse(json); // obj คืออ็อบเจ็กต์ที่ใช้แทนข้อมูลแบบ JSON
+console.log(typeof obj); // "object"
+console.log(obj);
+// แสดงผลลัพธ์เป็น
+// { bold: true, color: 'red', size: 100 }
+```
+
+* ตัวอย่าง จะทำการแปลงสตริงที่เขียนอยู่ในรูป JSON ซึ่งคราวนี้จะซับซ้อนหน่อยตรงที่คีย์ชื่อ "people" จะมีส่วน value เป็นอาร์เรย์ที่มีสมาชิกเป็นอ็อบเจ็กต์ (JSON) แล้วจะใช้เมธอด JSON.parse() แปลงให้กลายเป็นอ็อบเจ็กต์ที่อยู่ในรูปอ็อบเจ็กต์ของจาวาสคริปต์
+
+```js
+// ใช้ \ เชื่อมสตริงแต่ละบรรทัดเข้าดัวยกัน
+var json = '{"people":[\
+ {"firstName":"Somchai", "lastName":"Jaidee"},\
+ {"firstName":"Mana", "lastName":"Dekdee"},\
+ {"firstName":"Surat", "lastName":"Khonthai"}\
+]}';
+var obj = JSON.parse(json); // obj คืออ็อบเจ็กต์ที่ใช้แทนข้อมูลแบบ JSON
+console.log(typeof obj); // "object"
+console.log(obj);
+/* แสดงผลลัพธ์เป็น
+{ people:
+ [ { firstName: 'Somchai', lastName: 'Jaidee' },
+ { firstName: 'Mana', lastName: 'Dekdee' },
+ { firstName: 'Surat', lastName: 'Khonthai' } ] } */
+```
+
+* ตัวอย่าง ใช้ JSON.stringify() จะแปลงอ็อบเจ็กต์ในจาวาสคริปต์ ให้เป็นสตริงที่อยู่ในรูป JSON
+
+
+```js
+var obj = {
+ bold: true,
+ color: "red",
+ size: 100
+};
+console.log(JSON.stringify(obj));
+// แสดงผลลัพธ์เป็น
+// {"bold":true,"color":"red","size":100}
+```
+
+* ตัวอย่าง ใช้ JSON.stringify() จะแปลง value ที่เป็นอาร์เรย์ ให้เป็นสตริงที่อยู่ในรูป JSON
+
+```js
+var obj = {
+ "cars": ["Toyota", "BMW", "Tesla"]
+}
+console.log(JSON.stringify(obj));
+// แสดงผลลัพธ์เป็น
+// {"cars":["Toyota","BMW","Tesla"]}
+```
+
+```js
+var obj = {
+ people: [
+ { firstName: "Somchai", lastName: "Jaidee" },
+ { firstName: "Mana", lastName: "Dekdee" },
+ { firstName: "Surat", lastName: "Khonthai" }
+ ] ,
+ age: Symbol("1")
+};
+console.log(JSON.stringify(obj));
+/* แสดงผลลัพธ์เป็น
+{"people":[{"firstName":"Somchai","lastName":"Jaidee"},{"firstName":"Mana",
+ "lastName":"Dekdee"},{"firstName":"Surat","lastName":"Khonthai"}]} */
+```
+
+```js
+var obj = {
+ people: [
+ { firstName: "Somchai", lastName: "Jaidee" },
+ { firstName: "Mana", lastName: "Dekdee" },
+ { firstName: "Surat", lastName: "Khonthai" }
+ ]
+};
+console.log(JSON.stringify(obj, null, 2)); // ระบุค่าอากิวเมนต์ตัวที่สาม
+/* แสดงผลลัพธ์เป็น
+{
+ "people": [
+ {
+ "firstName": "Somchai",
+ "lastName": "Jaidee"
+ },
+ {
+ "firstName": "Mana",
+ "lastName": "Dekdee"
+ },
+ {
+ "firstName": "Surat",
+ "lastName": "Khonthai"
+ }
+ ]
+} */
+```
+
+```js
+var obj = {
+ name: "Somchai",
+ func: function() { },
+ age: Symbol("25")
+};
+console.log(JSON.stringify(obj));
+// แสดงผลลัพธ์
+// {"name":"Somchai"}
+```
+
+```js
+var obj = {
+ name: "Somchai",
+ today: new Date()
+};
+console.log(JSON.stringify(obj));
+// แสดงผลลัพธ์
+// {"name":"Somchai","today":"2023-02-06T02:10:39.018Z"}
+```
diff --git a/examples_book/Chapter06.md b/examples_book/Chapter06.md
new file mode 100644
index 0000000..91315a0
--- /dev/null
+++ b/examples_book/Chapter06.md
@@ -0,0 +1,854 @@
+# โค้ดบทที่ 6 ทบทวน Regex
+
+## Regular Expression
+
+* 1. สร้างโดยใช้ฟังก์ชันคอนสตรัคเตอร์ RegExp ตามตัวอย่าง
+
+```js
+var myRegex = new RegExp("Hello+");
+console.log(myRegex.toString()); // /Hello+/
+```
+
+* 2. สร้างโดยใช้เครื่องหมาย /…/ มาครอบข้อความ regex ตามตัวอย่าง
+```js
+var myRegex = /Hello+/;
+// ข้อความ regex ก็คืออ็อบเจ็กต์ตัวหนึ่ง
+// จึงสามารถแชร์ใช้งานเมธอด RegExp.prototype.toString()
+console.log(/Hello+/.toString()); // /Hello+/
+```
+
+### เมธอด test() กับ exec()
+
+ตัวอย่าง 6.1 การใช้งานเมธอด test() เพื่อค้นหาข้อความในสตริง
+```js
+console.log( /Hello+/.test("Hellooooo") ); // true
+console.log( (new RegExp("Hello+")).test("Hellooooo") ); // true
+```
+
+ตัวอย่าง 6.2 เนื่องจากข้อความแบบ regex สามารถนำไปประยุกต์ใช้งานได้หลายกรณี และตัวอย่างต่อไปนี้จะเป็นการใช้ regex มาตรวจสอบข้อความว่าเป็นอีเมลหรือไม่
+```js
+var myRegex = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
+console.log(myRegex.test("xxxxxx.yyyyyy_zzzzz@abc.com")); // true
+```
+
+ตัวอย่าง 6.3 ข้อความแบบ regex สามารถนำไปใช้ตรวจสอบตัวเลข
+```js
+var myRegex = /^(\-?|\+?)\d*$/;
+console.log(myRegex.test("-987")); // true
+```
+
+ตัวอย่าง 6.4 การใช้งานเมธอด exec() เพื่อค้นหาข้อความในสตริง
+```js
+var result = /(foo).(bar)/.exec("0123foo_bar");
+console.log(result.index); // 4
+console.log(result[0]); // "foo_bar"
+console.log(result[1]); // "foo"
+console.log(result[2]); // "bar"
+console.log(result.input); // "0123foo_bar"
+```
+
+## รูปแบบการใช้งาน regex ต่างๆ
+
+### การระบุคำที่ต้องการค้นหา
+
+ตัวอย่าง 6.5 ใช้ /like/ เป็น regex เพื่อจับคู่ลำดับตัวอักษร "like" ในสตริง "I like u" ซึ่งเจอชุดตัวอักษร "like" ที่อินเด็กซ์ 2
+```js
+var re = /like/;
+console.log(re.exec("I like u")); // [ 'like', index: 2, input: 'I like u', groups: undefined ]
+```
+
+ตัวอย่าง 6.6 ใช้ /html|div|br/ เป็น regex เพื่อจับคู่ลำดับตัวอักษร "html" หรือ "div" หรือ "br" อย่างใดอย่างหนึ่ง ในสตริง "<div>" ซึ่งเจอชุดอักษร "div" ที่อินเด็กซ์ 1
+```js
+var re = /html|div|br/;
+console.log(re.exec("
")); // [ 'div', index: 1, input: '
', groups: undefined ]
+```
+
+### การระบุช่วงตัวอักษรที่จับคู่
+
+ตัวอย่าง 6.7 ใช้ regex เป็น /[abc]/ หมายถึงจะจับคู่ตัวอักษร a หรือ b หรือ c โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "b" ในสตริง "feb" ที่อินเด็กซ์ 2
+```js
+var re = /[abc]/;
+console.log(re.exec("feb")); // [ 'b', index: 2, input: 'feb', groups: undefined ]
+```
+
+ตัวอย่าง 6.8 ใช้ regex เป็น /[7-9]/ หมายถึงจะจับคู่ตัวเลขในช่วง 7 ถึง 9 โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษรเลข "8" ในสตริง "2+8" ที่อินเด็กซ์ 2
+```js
+var re = /[7-9]/;
+console.log(re.exec("2+8")); // [ '8', index: 2, input: '2+8', groups: undefined ]
+```
+
+ตัวอย่าง 6.9 ใช้ regex เป็น /[a-c]/ หมายถึงจะจับคู่ตัวอักษรตัวพิมพ์เล็ก ตั้งแต่ a ถึง c โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษรเลข "a" ในสตริง "rat" ที่อินเด็กซ์ 1
+```js
+var re = /[a-c]/;
+console.log(re.exec("rat")); // [ 'a', index: 1, input: 'rat', groups: undefined ]
+```
+
+ตัวอย่าง 6.10 ใช้ regex เป็น /[A-C]/ หมายถึงจะจับคู่ตัวอักษรตัวพิมพ์ใหญ่ ตั้งแต่ A ถึง C โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษรเลข "C" ในสตริง "COM" ที่อินเด็กซ์ 0
+```js
+var re = /[A-C]/;
+console.log(re.exec("COM")); // [ 'C', index: 0, input: 'COM', groups: undefined ]
+```
+
+ตัวอย่าง 6.11 ใช้ regex เป็น /[a-cA-C]/ หมายถึงจะจับคู่ตัวอักษรตัวพิมพ์เล็ก ตั้งแต่ a ถึง c หรือตัวอักษรตัวพิมพ์ใหญ่ ตั้งแต่ A ถึง C โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "A" ในสตริง "AND" ที่อินเด็กซ์ 0
+```js
+var re = /[a-cA-C]/;
+console.log(re.exec("AND")); // [ 'A', index: 0, input: 'AND', groups: undefined ]
+```
+
+ตัวอย่าง 6.12 ใช้ regex เป็น /[^cat]/ หมายถึงจะจับคู่ตัวอักษร ที่ไม่ใช่ c และไม่ใช่ a และไม่ใช่ t โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "s" ในสตริง "cats" ที่อินเด็กซ์ 3
+```js
+var re = /[^cat]/;
+console.log(re.exec("cats")); // [ 's', index: 3, input: 'cats', groups: undefined ]
+```
+
+ตัวอย่าง 6.13 ใช้ regex เป็น /[^0-3]/ หมายถึงจะจับคู่ตัวอักษร ที่ไม่ใช่เลข 0 ถึง 3 โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "k" ในสตริง "20k" ที่อินเด็กซ์ 2
+```js
+var re = /[^0-3]/;
+console.log(re.exec("20k")); // [ 'k', index: 2, input: '20k', groups: undefined ]
+```
+
+ตัวอย่าง 6.14 ใช้ regex เป็น /[^w-z]/ หมายถึงจะจับคู่ตัวอักษร ที่ไม่ใช่ตัวอักษร w ถึง z โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจอเลข 1 ในสตริง "xy12" ที่อินเด็กซ์ 2
+```js
+var re = /[^w-z]/;
+console.log(re.exec("xy12")); // [ '1', index: 2, input: 'xy12', groups: undefined ]
+```
+
+ตัวอย่าง 6.15 ใช้ regex เป็น /[^m-oM-O]/ หมายถึงจะจับคู่ตัวอักษร ที่ไม่ใช่ตัวอักษร m ถึง o และไม่ใช่ M ถึง O โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจอเลข "!" ในสตริง "Moon!" ที่อินเด็กซ์ 4
+```js
+var re = /[^m-oM-O]/;
+console.log(re.exec("Moon!")); // [ '!', index: 4, input: 'Moon!', groups: undefined ]
+```
+
+ตัวอย่าง 6.16 เป็นการประยุกต์ใช้ regex ที่ดูซับซ้อนขึ้น ได้แก่ /[a-zB-Mxyz157]/ หมายถึงจะจับคู่ตัวอักษรระหว่าง a ถึง z หรือ B ถึง M หรือ x หรือ y หรือ z หรือ 1 หรือ 5 หรือ 7 โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษรเลข "5" ในสตริง "3-5" ที่อินเด็กซ์ 2
+```js
+var re = /[a-zB-Mxyz157]/;
+console.log(re.exec("3-5")); // [ '5', index: 2, input: '3-5', groups: undefined ]
+```
+
+### การระบุความถี่ของลำดับตัวอักษรที่จับคู่
+
+ตัวอย่าง 6.17 ใช้ regex เป็น /3+/ หมายถึงจะจับคู่ลำดัับตัวเลข 3 ตั้งแต่ 1 ตัวขึ้นไป โดยจะเจออักษร "3" ในสตริง "123" ที่อินเด็กซ์ 2
+```js
+var re = /3+/;
+console.log(re.exec("123")); // [ '3', index: 2, input: '123', groups: undefined ]
+```
+
+ตัวอย่าง 6.18 ใช้ regex เป็น /p+/ หมายถึงจะจับคู่ลำดับตัวอักษร "p" ตั้งแต่ 1 ตัวขึ้นไป โดยจะเจออักษร "pp" ในสตริง "app" ที่อินเด็กซ์ 1
+```js
+var re = /p+/;
+console.log(re.exec("app")); // [ 'pp', index: 1, input: 'app', groups: undefined ]
+```
+
+ตัวอย่าง 6.19 ใช้ regex เป็น /3*/ หมายถึงจะจับคู่ลำดับตัวเลข 3 ตั้งแต่ศูนย์ตัวขึ้นไป ในตัวอย่างนี้ใช้ตริงตั้งต้นเป็น "12" ก็จะถือว่าเจอสตริงว่าง '' ที่อินเด็กซ์ 0
+```js
+var re = /3*/;
+console.log(re.exec("12")); // [ '', index: 0, input: '12', groups: undefined ]
+```
+
+ตัวอย่าง 6.20 ใช้ regex เป็น /b*/ หมายถึงจะจับคู่ลำดับตัวอักษร "b" ตั้งแต่ศูนย์ตัวขึ้นไป โดยจะเจออักษร "bb" ในสตริง "bbc" ที่อินเด็กซ์ 0
+```js
+var re = /b*/;
+console.log(re.exec("bbc")); // [ 'bb', index: 0, input: 'bbc', groups: undefined ]
+```
+
+ตัวอย่าง 6.21 ใช้ regex เป็น /p*/ หมายถึงจะจับคู่ลำดับตัวอักษร "p" ตั้งแต่ศูนย์ตัวขึ้นไป ในตัวอย่างนี้ใช้สตริงตั้งต้นเป็น "app" ก็จะถือว่าเจอสตริงว่าง '' ที่อินเด็กซ์ 0 เพราะเวลา regex จับคู่ในสตริง ก็จะมองจากตัวอักษรซ้ายมือสุดไปขวามือ พอเจอ "a" ก่อนตัวอักษรอื่นๆ จึงเข้าใจว่า p มีแค่ศูนย์ตัว จะไม่มองหา p ที่อยู่ในอินเด็กซ์ 1 กับ 2 ดังนั้นการใช้ * จึงต้องระวังให้ดี อาจทำให้เข้าใจผิดได้
+```js
+var re = /p*/;
+console.log(re.exec("app")); // [ '', index: 0, input: 'app', groups: undefined ]
+```
+
+ตัวอย่าง 6.22 ใช้ regex เป็น /b?/ หมายถึงจะจับคู่ลำดับตัวอักษร "b" ตั้งแต่ศูนย์ตัว ถึง 1 ตัว โดยจะเจออักษร "b" ในสตริง "bed" ที่อินเด็กซ์ 0
+```js
+var re = /b?/;
+console.log(re.exec("bed")); // [ 'b', index: 0, input: 'bed', groups: undefined ]
+```
+
+ตัวอย่าง 6.23 ใช้ regex เป็น /b?/ หมายถึงจะจับคู่ลำดับตัวอักษร "b" ตั้งแต่ศูนย์ตัว ถึง 1 ตัว โดยจะเจออักษร "b" ในสตริง "bbc" ที่อินเด็กซ์ 0 (เจอ "b" ตัวแรกแล้ว ก็จะไม่ค้นหา "b" ตัวถัดไป)
+```js
+var re = /b?/;
+console.log(re.exec("bbc")); // [ 'b', index: 0, input: 'bbc', groups: undefined ]
+```
+
+ตัวอย่าง 6.24 ใช้ regex เป็น /p?/ หมายถึงจะจับคู่ลำดับตัวอักษร "p" ตั้งแต่ศูนย์ตัว ถึง 1 ตัว ตัวอย่างนี้ใช้สตริงตั้งต้นเป็น "app" ก็จะถือว่าเจอสตริงว่าง '' ที่อินเด็กซ์ 0 เพราะเวลา regex จับคู่ในสตริง ก็จะมองจากตัวอักษรซ้ายมือสุดไปขวามือ พอเจอ "a" ก่อนตัวอักษรอื่นๆ จึงเข้าใจว่า p มีแค่ศูนย์ตัว จะไม่มองหา p ที่อยู่ในอินเด็กซ์ 1 กับ 2 ดังนั้นการใช้ ? ก็เหมือน * จึงต้องระวังให้ดี อาจทำให้เข้าใจผิดได้
+```js
+var re = /p?/;
+console.log(re.exec("app")); // [ '', index: 0, input: 'app', groups: undefined ]
+```
+
+ตัวอย่าง 6.25 ใช้ regex เป็น /g{2}/ หมายถึงจะจับคู่ลำดับตัวอักษร "g" จำนวน 2 ตัว โดยจะเจออักษร "gg" ในสตริง "egg" ที่อินเด็กซ์ 1
+```js
+var re = /g{2}/;
+console.log(re.exec("egg")); // [ 'gg', index: 1, input: 'egg', groups: undefined ]
+```
+
+ตัวอย่าง 6.26 ใช้ regex เป็น /5{2}/ หมายถึงจะจับคู่ลำดับตัวเลข 5 จำนวน 2 ตัว โดยจะเจออักษร "55" ในสตริง "555" ที่อินเด็กซ์ 0 (เจอ 5 แค่สองตัว ไม่ใช่เจอ "555")
+```js
+var re = /5{2}/;
+console.log(re.exec("555")); // [ '55', index: 0, input: '555', groups: undefined ]
+```
+
+ตัวอย่าง 6.27 ใช้ regex เป็น /e{1,3}/ หมายถึงจะจับคู่ลำดับตัวอักษร "e" จำนวนอย่างน้อย 1 ตัว และมากสุด 3 ตัว โดยจะเจออักษร "ee" ในสตริง "deep" ที่อินเด็กซ์ 1 (เจอ "e" สองตัว)
+```js
+var re = /e{1,3}/;
+console.log(re.exec("deep")); // [ 'ee', index: 1, input: 'deep', groups: undefined ]
+```
+
+ตัวอย่าง 6.28 ใช้ regex เป็น /x{1,3}/ หมายถึงจะจับคู่ลำดับตัวอักษร "x" จำนวนอย่างน้อย 1 ตัว และมากสุด 3 ตัว โดยจะเจออักษร "xxx" ในสตริง "xxxx" ที่อินเด็กซ์ 0 (เจอ "x" แค่สามตัว ไม่ใช่เจอ "xxxx")
+```js
+var re = /x{1,3}/;
+console.log(re.exec("xxxx")); // [ 'xxx', index: 0, input: 'xxxx', groups: undefined ]
+```
+
+ตัวอย่าง 6.29 ใช้ regex เป็น /a{2,}/ หมายถึงจะจับคู่ลำดับตัวอักษร "a" จำนวนอย่างน้อย 2 ตัว โดยจะเจออักษร "aaa" ในสตริง "zaaa" ที่อินเด็กซ์ 1 (เจอ "a" สามตัว)
+```js
+var re = /a{2,}/;
+console.log(re.exec("zaaa")); // [ 'aaa', index: 1, input: 'zaaa', groups: undefined ]
+```
+
+### การจับคู่แบบ assertions
+
+ตัวอย่าง 6.30 ใช้ regex เป็น /^x/ หมายถึงจะจับคู่ตัวอักษร x จำนวน 1 ตัว ที่วางไว้ด้านหน้าสุด โดยจะเจอในสตริง "x-ray" ที่อินเด็กซ์ 0
+```js
+var re = /^x/;
+console.log(re.exec("x-ray")); // [ 'x', index: 0, input: 'x-ray', groups: undefined ]
+```
+ตัวอย่าง 6.31 ใช้ regex เป็น /r$/ หมายถึงจะจับคู่ตัวอักษร r จำนวน 1 ตัว ที่วางไว้ด้านท้ายสุด โดยจะเจอในสตริง "car" ที่อินเด็กซ์ 2
+```js
+var re = /r$/;
+console.log(re.exec("car")); // [ 'r', index: 2, input: 'car', groups: undefined ]
+```
+
+ตัวอย่าง 6.32 ใช้ regex เป็น /\bfa/ หมายถึงจะจับคู่ชุดตัวอักษร "fa" ที่วางไว้ด้านหน้าสุดของคำใดคำหนึ่ง โดยจะเจอ "fa" ภายในคำ "father" ที่อินเด็กซ์ 2 (สตริงต้นทางคือ "A father is")
+```js
+var re = /\bfa/;
+console.log(re.exec("A father is")); // [ 'fa', index: 2, input: 'A father is', groups: undefined ]
+```
+
+ตัวอย่าง 6.33 ใช้ regex เป็น /\bth/ หมายถึงจะจับคู่ชุดตัวอักษร "th" ที่วางไว้ด้านหน้าสุดของคำใดคำหนึ่ง ซึ่งปรากฏว่าไม่เจอชุดอักษรใดที่ตรงเงื่อนไข (สตริงต้นทางคือ "A father is")
+```js
+var re = /\bth/;
+console.log(re.exec("A father is")); // null
+```
+
+ตัวอย่าง 6.34 ใช้ regex เป็น /er\b/ หมายถึงจะจับคู่ชุดตัวอักษร "er" ที่วางไว้ด้านหลังสุดของคำใดคำหนึ่ง โดยจะเจอ "er" ภายในคำ "father" ที่อินเด็กซ์ 6 (สตริงต้นทางคือ "A father is")
+```js
+var re = /er\b/;
+console.log(re.exec("A father is")); // [ 'er', index: 6, input: 'A father is', groups: undefined ]
+```
+
+ตัวอย่าง 6.35 ใช้ regex เป็น /th\b/ หมายถึงจะจับคู่ชุดตัวอักษร "th" ที่วางไว้ด้านหลังสุดของคำใดคำหนึ่ง ซึ่งปรากฏว่าไม่เจอชุดอักษรใดที่ตรงเงื่อนไข (สตริงต้นทางคือ "A father is")
+```js
+var re = /th\b/;
+console.log(re.exec("A father is")); // null
+```
+
+ตัวอย่าง 6.36 ใช้ regex เป็น /\Bfa/ หมายถึงจะจับคู่ชุดตัวอักษร "fa" ที่ไม่ได้วางไว้ด้านหน้าสุดของคำใดคำหนึ่ง ซึ่งปรากฏว่าไม่เจอชุดอักษรใดที่ตรงเงื่อนไข (สตริงต้นทางคือ "A father is")
+```js
+var re = /\Bfa/;
+console.log(re.exec("A father is")); // null
+```
+
+ตัวอย่าง 6.37 ใช้ regex เป็น /\Bth/ หมายถึงจะจับคู่ชุดตัวอักษร "th" ที่ไม่ได้วางไว้ด้านหน้าสุดของคำใดคำหนึ่ง โดยจะเจอ "th" ภายในคำ "father" ที่อินเด็กซ์ 4 (สตริงต้นทางคือ "A father is")
+```js
+var re = /\Bth/;
+console.log(re.exec("A father is")); // [ 'th', index: 4, input: 'A father is', groups: undefined ]
+```
+
+ตัวอย่าง 6.38 ใช้ regex เป็น /\Ber/ หมายถึงจะจับคู่ชุดตัวอักษร "er" ที่ไม่ได้วางไว้ด้านหน้าสุดของคำใดคำหนึ่ง โดยจะเจอ "er" ภายในคำ "father" ที่อินเด็กซ์ 6 (สตริงต้นทางคือ "A father is")
+```js
+var re = /\Ber/;
+console.log(re.exec("A father is")); // [ 'er', index: 6, input: 'A father is', groups: undefined ]
+```
+
+ตัวอย่าง 6.39 ใช้ regex เป็น /er\B/ หมายถึงจะจับคู่ชุดตัวอักษร "er" ที่ไม่ได้วางไว้ด้านหลังสุดของคำใดคำหนึ่ง ซึ่งปรากฏว่าไม่เจอชุดอักษรใดที่ตรงเงื่อนไข (สตริงต้นทางคือ "A father is")
+```js
+var re = /er\B/;
+console.log(re.exec("A father is")); // null
+```
+
+ตัวอย่าง 6.40 ใช้ regex เป็น /th\B/ หมายถึงจะจับคู่ชุดตัวอักษร "th" ที่ไม่ได้วางไว้ด้านหลังสุดของคำใดคำหนึ่ง โดยจะเจอ "th" ภายในคำ "father" ที่อินเด็กซ์ 4 (สตริงต้นทางคือ "A father is")
+
+```js
+var re = /th\B/;
+console.log(re.exec("A father is")); // [ 'th', index: 4, input: 'A father is', groups: undefined ]
+```
+
+ตัวอย่าง 6.41 ใช้ regex เป็น /fa\B/ หมายถึงจะจับคู่ชุดตัวอักษร "fa" ที่ไม่ได้วางไว้ด้านหลังสุดของคำใดคำหนึ่ง โดยจะเจอ "fa" ภายในคำ "father" ที่อินเด็กซ์ 2 (สตริงต้นทางคือ "A father is")
+```js
+var re = /fa\B/;
+console.log(re.exec("A father is")); // [ 'fa', index: 2, input: 'A father is', groups: undefined ]
+```
+
+1) วิธี lookahead assertion จะมีรูปแบบ x(?=y) ดังตัวอย่าง
+ตัวอย่าง 6.42 ใช้ regex เป็น /Java(?=Script)/ หมายถึงจะจับคู่คำว่า "Java" แต่ต้องตามด้วยคำว่า "Script" ด้วยรูปแบบ Java แล้วมีรูปแบบ (?=Script) แปะท้าย จึงเจอ "Java" ที่อินเด็กซ์ 10
+```js
+let re = /Java(?=Script)/;
+console.log(re.exec("This is a JavaScript book"));
+// [ 'Java', index: 10, input: 'This is a JavaScript book', groups: undefined ]
+```
+
+ตัวอย่าง 6.43 ใช้ regex เป็น /[wW]atch(?=ed|ing)/ หมายถึงจะจับคู่คำว่า "watch" หรือ "Watch" แต่ต้องตามด้วย "ed" หรือ "ing" ด้วยรูปแบบ [wW]atch แล้วมีรูปแบบ (?=ed|ing) แปะท้าย จึงเจอ "watch" ที่อินเด็กซ์ 2
+```js
+let re = /[wW]atch(?=ed|ing)/;
+console.log(re.exec("I watched TV"));
+// [ 'watch', index: 2, input: 'I watched TV', groups: undefined ]
+```
+2) วิธี negative lookahead assertion จะมีรูปแบบ x(?!y) ดังตัวอย่าง
+ตัวอย่าง 6.44 ใช้ regex เป็น /test_(?!js|txt)/ หมายถึงจะจับคู่คำว่า "test_" แล้วตามหลังด้วยรูปแบบ (?!js|txt) หรือก็คือต้องไม่ต่อท้ายด้วย "js" หรือ "txt" จึงเจอ "test_" ที่อินเด็กซ์ 17
+```js
+let re = /test_(?!js|txt)/;
+console.log(re.exec("test_js test_txt test_html"));
+// [ 'test_', index: 17, input: 'test_js test_txt test_html', groups: undefined ]
+```
+
+1) วิธี lookbehind assertion จะมีรูปแบบ (?<=y)x ดังตัวอย่าง
+ตัวอย่าง 6.45 ใช้ regex เป็น /(?<=Java)Script/ หมายถึงจะจับคู่คำว่า "Script" แต่ต้องขึ้นต้นตัวหน้าเป็น "Java" ด้วยรูปแบบ (?<=Java) และมีรูปแบบ Script แปะท้าย จึงเจอ "Script" ที่อินเด็กซ์ 14
+```js
+let re = /(?<=Java)Script/;
+console.log(re.exec("This is a JavaScript book"));
+// [ 'Script', index: 14, input: 'This is a JavaScript book', groups: undefined ]
+```
+
+ตัวอย่าง 6.46 ใช้ regex เป็น /(?<=Java)[a-zA-Z\s]+/ หมายถึงจะจับคู่คำด้วยรูปแบบ [a-zA-Z\s]+ แต่ต้องขึ้นต้นตัวหน้าเป็น "Java" ด้วยรูปแบบ (?<=Java) และมีรูปแบบ [a-zA-Z\s]+ แปะท้าย จึงเจอ "Script book" ที่อินเด็กซ์ 14
+
+```js
+let re = /(?<=Java)[a-zA-Z\s]+/;
+console.log(re.exec("This is a JavaScript book"));
+// [ 'Script book', index: 14, input: 'This is a JavaScript book', groups: undefined ]
+```
+
+2) วิธี negative lookbehind assertion จะมีรูปแบบ (?<!y)x ดังตัวอย่าง
+ตัวอย่าง 6.47 ใช้ regex เป็น /(?<!test).js/ หมายถึงจะจับคู่ด้วยคำว่า ".js" ด้วยรูปแบบ .js แต่ต้องไม่ขึ้นต้นด้วยคำว่า "test" ด้วยรูปแบบ (?<!test) จึงเจอคำว่า ".js" ที่อินเด็กซ์ 14
+```js
+let re = /(?")); // [ ' ', index: 1, input: '< >', groups: undefined ]
+```
+
+ตัวอย่าง 6.49 ใช้ regex เป็น /\x41/ ซึ่งรหัส \x41 ก็คืออักษร "A" หมายถึงจะจับคู่อักษร "A" ในสตริง โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "A" ในสตริง "THAI" ที่อินเด็กซ์ 2
+```js
+var re = /\x41/;
+console.log(re.exec("THAI")); // [ 'A', index: 2, input: 'THAI', groups: undefined ]
+```
+
+ตัวอย่าง 6.50 ใช้ regex เป็น /\u0E14/ ซึ่งรหัส \u0E14 ก็คืออักษร "ด" หมายถึงจะจับคู่อักษร "ด" ในสตริง โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "ด" ในสตริง "แดง" ที่อินเด็กซ์ 1
+```js
+var re = /\u0E14/;
+console.log(re.exec("แดง")); // [ 'ด', index: 1, input: 'แดง', groups: undefined ]
+```
+
+ตัวอย่าง 6.51 ใช้ regex เป็น /\+/, /\*/,/\?/, /\\/, /\./ โดยต้องมีเครื่องหมาย \ วางนำหน้า เพื่อจับคู่อักษร "+", "*", "?", "\", "." ไม่เช่นนั้นจะจับคู่ไม่ได้ เพราะอักษรพวกนี้ถูกใช้เป็นสัญลักษณ์หนึ่งภายใน regex จึงจับคู่โดยตรงไม่ได้
+```js
+console.log(/\+/.test("+")); // true
+console.log(/\*/.test("*")); // true
+console.log(/\?/.test("?")); // true
+console.log(/\\/.test("\x5C")); // true -- x5C คือค่า ASCII ของ "\"
+console.log(/\./.test(".")); // true
+```
+
+ตัวอย่าง 6.52 ใช้ regex เป็น /./ หมายถึงจะจับคู่ตัวอักษรใดๆ จำนวน 1 ตัว โดยจะค้นหาตัวแรกที่พบเจอ ซึ่งจะเจออักษร "d" ในสตริง "dog" ที่อินเด็กซ์ 0
+```js
+var re = /./;
+console.log(re.exec("dog")); // [ 'd', index: 0, input: 'dog', groups: undefined ]
+```
+
+ตัวอย่าง 6.53 ใช้ regex เป็น /.ox/ หมายถึงจะจับคู่ตัวอักษรที่ขึ้นต้นด้วยอะไรก็ได้ แต่ขอให้ตามด้วย ox โดยจะค้นหาคำแรกที่พบเจอ ซึ่งจะเจออักษร "box" ในสตริง "boxes" ที่อินเด็กซ์ 0
+```js
+var re = /.ox/;
+console.log(re.exec("boxes")); // [ 'box', index: 0, input: 'boxes', groups: undefined ]
+```
+
+ตัวอย่าง 6.54 ใช้ regex เป็น /\d/ หมายถึงจะจับคู่ตัวเลขใดๆ จำนวน 1 ตัว โดยจะค้นหาคำแรกที่พบเจอ ซึ่งจะเจออักษรเลข "8" ในสตริง "x86" ที่อินเด็กซ์ 1 (ไม่เจอเลข 6)
+```js
+var re = /\d/;
+console.log(re.exec("x86")); // [ '8', index: 1, input: 'x86', groups: undefined ]
+```
+
+ตัวอย่าง 6.55 ใช้ regex เป็น /..\d/ หมายถึงจะจับคู่ลำดับตัวอักษรทั้งหมด 3 ตัว โดยสองตัวแรกเป็นตัวอักษรใดๆ ก็ได้ (ใช้จุดสองอันติดกัน) ส่วนตัวอักษรที่สาม จะเป็นตัวเลข (ใช้ \d) โดยจะค้นหาคำแรกที่พบเจอ ซึ่งจะเจอคำว่า "em1" ในสตริง "item1" ที่อินเด็กซ์ 2
+```js
+var re = /..\d/;
+console.log(re.exec("item1")); // [ 'em1', index: 2, input: 'item1', groups: undefined ]
+```
+
+ตัวอย่าง 6.56 ใช้ regex เป็น /\D/ หมายถึงจะจับคู่ตัวอักษรใดๆ จำนวน 1 ตัว ที่ไม่ใช่ตัวเลข โดยจะค้นหาคำแรกที่พบเจอ ซึ่งจะเจออักษรเลข "p" ในสตริง "100px" ที่อินเด็กซ์ 3 (ไม่เจออักษร "x")
+```js
+var re = /\D/;
+console.log(re.exec("100px")); // [ 'p', index: 3, input: '100px', groups: undefined ]
+```
+
+ตัวอย่าง 6.57 ใช้regex เป็น /\w/ หมายถึงจะจับคู่ตัวอักษรใดๆ จำนวน 1 ตัว ได้แก่ ตัวอักษร a ถึง z หรือ A ถึง Z หรือ 0 ถึง 9 รวมทั้งตัวอักษร _ โดยจะค้นหาคำแรกที่พบเจอ ซึ่งในตัวอย่างนี้จะเจอหลายตัวอักษรที่อินเด็กซ์ 1 (ไม่จับคู่ "$")
+```js
+var re = /\w/;
+console.log(re.exec("$a")); // [ 'a', index: 1, input: '$a', groups: undefined ]
+console.log(re.exec("$T")); // [ 'T', index: 1, input: '$T', groups: undefined ]
+console.log(re.exec("$7")); // [ '7', index: 1, input: '$7', groups: undefined ]
+console.log(re.exec("$_")); // [ '_', index: 1, input: '$_', groups: undefined ]
+```
+
+ตัวอย่าง 6.58 ใช้ regex เป็น /\W/ หมายถึงจะจับคู่ตัวอักษรใดๆ จำนวน 1 ตัว ที่ไม่ใช่ตัวอักษร a ถึง z และไม่ใช่ A ถึง Z และไม่ใช่ 0 ถึง 9 รวมทั้งไม่ใช่ตัวอักษร _ โดยจะค้นหาคำแรกที่พบเจอ ซึ่งในตัวอย่างนี้ก็จะเจออักษร "$" ที่อินเด็กซ์ 1
+```js
+var re = /\W/;
+console.log(re.exec("a$")); // [ '$', index: 1, input: 'a$', groups: undefined ]
+console.log(re.exec("T$")); // [ '$', index: 1, input: 'T$', groups: undefined ]
+console.log(re.exec("7$")); // [ '$', index: 1, input: '7$', groups: undefined ]
+console.log(re.exec("_$")); // [ '$', index: 1, input: '_$', groups: undefined ]
+```
+
+ตัวอย่าง 6.59 ใช้ regex เป็น /\s/ หมายถึงจะจับคู่ตัวอักษรช่องว่าง โดยจะค้นหาคำแรกที่พบเจอ ซึ่งจะเจอช่องว่าง " " ในสตริง "^ ^" ที่อินเด็กซ์ 1
+```js
+var re = /\s/;
+console.log(re.exec("^ ^")); // [ ' ', index: 1, input: '^ ^', groups: undefined ]
+```
+
+ตัวอย่าง 6.60 เราสามารถพิมพ์ช่องว่างเว้นวรรคภายใน regex โดยไม่ต้องใช้ \s ก็ได้
+```js
+var re = / /;
+console.log(re.exec("^ ^")); // [ ' ', index: 1, input: '^ ^', groups: undefined ]
+```
+
+ตัวอย่าง 6.61 ใช้ regex เป็น /\S/ หมายถึงจะจับคู่ตัวอักษรใดๆ ที่ไม่ใช่อักษรว่าง จำนวน 1 ตัว โดยจะค้นหาคำแรกที่พบเจอ ซึ่งจะเจออักษร "@" ในสตริง " @" ที่อินเด็กซ์ 1 (มีช่องว่างนำหน้า @)
+```js
+var re = /\S/;
+console.log(re.exec(" @")); // [ '@', index: 1, input: ' @', groups: undefined ]
+```
+
+ตัวอย่าง 6.62 ประยุกต์ใช้ . ร่วมกับ * เพื่อจับคู่ตัวอักษรตั้งแต่ศูนย์ตัวขึ้นไป โดยต้องมี <p> ครอบเปิด และปิดท้ายด้วย </p> โดยในตัวอย่างนี้จะเจอข้อความ "<p>@test</p>" ที่อินเด็กซ์ 5
+```js
+var re = /
.*<\/p>/;
+console.log(re.exec("
"));
+// [ '
@test
', index: 5, input: '
', groups: undefined ]
+```
+
+ตัวอย่าง 6.63 ประยุกต์ใช้ \d ร่วมกับ ^ และ \w ร่วมกับ {1,} เพื่อจับคู่สตริงที่ต้องขึ้นต้นด้วยตัวเลข แล้วตามด้วยอักษรที่อยู่ในช่วง a ถึง z หรือ A ถึง Z หรือ 0 ถึง 9 รวมทั้งตัวอักษร _ ที่มีตั้งแต่ 1 ตัวขึ้นไป โดยในตัวอย่างนี้จะเจอข้อความ "1_log" ที่อินเด็กซ์ 0
+```js
+var re = /^\d\w{1,}/;
+console.log(re.exec("1_log.txt")); // [ '1_log', index: 0, input: '1_log.txt', groups: undefined ]
+```
+
+### Unicode character properties
+
+ตัวอย่าง 6.64 ระบุพร็อพเพอร์ตี้ของยูนิโคดป็น Script
+```js
+var result = /\p{Script=Greek}+/u.test("μετά");
+console.log(result); // true
+var result = /\p{Script=Thai}+/u.test("หนังสือไทย");
+console.log(result); // true
+```
+
+ตัวอย่าง 6.65 ระบุพร็อพเพอร์ตี้ของยูนิโคดป็น Uppercase_Letter
+```js
+var result = /\p{Uppercase_Letter}/u.test( "THAI" );
+console.log(result); // true
+```
+
+ตัวอย่างข้างต้นจะเสมือนเขียนซอร์สโค้ดดังนี้
+```js
+var result = /\p{General_Category=Uppercase_Letter}/u.test( "THAI" );
+console.log(result); // true
+```
+
+ตัวอย่าง 6.66 การจับคู่โดยใช้ unicode property escapes แบบต่างๆ
+```js
+var str = "This is a book.";
+var result = /\p{White_Space}/u.test( str );
+console.log(result); // true
+var result = /\p{Lowercase_Letter}/u.test (str );
+console.log(result); // true
+var result = /\p{Uppercase_Letter}/u.test (str );
+console.log(result); // true
+```
+
+### Capture groups
+
+ตัวอย่าง 6.67 ใช้ regex เป็น /(log)_(html)/ เพื่อทำการ capture groups โดยจะมี 2 กลุ่มย่อยที่ถูก catpure ได้แก่ (log) กับ (html)
+```js
+var result = /(log)_(html)/.exec("save log_html.txt");
+console.log(result.index); // 5
+console.log(result[0]); // "log_html"
+console.log(result[1]); // "log"
+console.log(result[2]); // "html"
+console.log(result.input); // "save log_html.txt"
+```
+
+ตัวอย่าง 6.68 ใช้ regex เป็น /file{2}/ เปรียบเทียบกับ /(file){2}/ เพื่อค้นหาข้อความในสตริง
+```js
+var re = /file{2}/;
+console.log(re.exec("filefile")); // null
+console.log(re.exec("filee")); // [ 'filee', index: 0, input: 'filee', groups: undefined ]
+var re = /(file){2}/;
+console.log(re.exec("filefile")); // [ 'filefile', 'file', index: 0, input: 'filefile', groups: undefined ]
+```
+
+ตัวอย่าง 6.69 ใช้ regex เป็น /(?:<p>)abc(?:</p>)/ เพื่อทำการ capture group โดยจะไม่จำผลการ capture
+```js
+var re = /(?:
)abc(?:<\/p>)/;
+let result = re.exec("
abc
");
+console.log(result[0]); // "
abc
"
+console.log(result[1]); // undefined
+console.log(result[2]); // undefined
+console.log(result); // [ '
abc
', index: 0, input: '
abc
', groups: undefined ]
+```
+
+ตัวอย่าง 6.70 ใช้ regex เป็น /([a-z]+).js/ โดยไม่ได้ตั้งชื่อ group
+```js
+let re = /([a-z]+).js/;
+console.log(re.exec("test index.js"));
+// [ 'index.js', 'index', index: 5, input: 'test index.js', groups: undefined ]
+```
+
+ตัวอย่าง 6.71 ใช้ regex เป็น /(?
[a-z]+).js/
+```js
+let re = /(?[a-z]+).js/;
+let matchObj = re.exec("test index.js")
+console.log(matchObj);
+/* แสดงผลลัพธ์
+[
+ 'index.js',
+ 'index',
+ index: 5,
+ input: 'test index.js',
+ groups: { filename: 'index' }
+] */
+console.log(matchObj .groups.filename); // "index"
+```
+
+ตัวอย่าง 6.72 ใช้ regex เป็น /bk(@)th(->)com\2/ โดยมีการ capture สองกลุ่มย่อย ได้แก่ (@) กับ (.>) แต่ให้สังเกตมีการใช้ \2 หมายถึงชุดตัวอักษรที่ถูกจับคู่ จะใช้ผลการ capture ก่อนหน้านี้ ด้วยวงเล็บอันที่สองก็คือ (.>)
+```js
+var re = /bk(@)th(.>)com\2/;
+console.log(re.exec("bk@th=>com=>mail"));
+// [ 'bk@th=>com=>', '@', '=>', index: 0, input: 'bk@th=>com=>mail', groups: undefined ]
+```
+
+ตัวอย่าง 6.73 ใช้ regex เป็น /talk(?ed|ing) & watch\k/ โดยมีการตั้งชื่อกลุ่มที่ได้จากการ capture เป็น "tense" และมีการอ้างถึงผลการ capture ก่อนหน้านี้ ด้วยการอ้างชื่อกลุ่ม ได้แก่ "tense" ด้วยรูปแบบ \k<tense>
+```js
+var re = /talk(?ed|ing) & watch\k/;
+console.log(re.exec("talked & watched"));
+// [ 'talked & watched', 'ed', index: 0, input: 'talked & watched', groups: { tense: 'ed' } ]
+```
+
+### เมธอดของสตริงที่ใช้งานร่วมกับ regex
+
+ตัวอย่าง 6.74 ลองพิจารณาการใช้เมธอดของสตริงร่วมกับ regex
+```js
+console.log("012Hellooooo".search(/Hello+/)); // 3
+var result = "Hellooooo Hello".match(/Hello+/g);
+console.log(result); // [ 'Hellooooo', 'Hello' ]
+console.log(result.length); // 2
+var str = "Hellooooo".replace(/Hello+/,"Bye");
+console.log(str); // "Bye"
+var split = "1,2,3".split(/,/);
+console.log(split); // [ '1', '2', '3' ]
+```
+
+### ค่าแฟล็ก
+
+
+
+ตัวอย่าง 6.75 ลองพิจารณาการตรวจสอบว่า ตอนนี้ regex ใช้งานแฟล็กอะไรบ้าง
+```js
+var regex = /Hello+/gi;
+console.log(regex.lastIndex); // 0
+console.log(regex.source); // "Hello+"
+console.log(regex.flags); // "gi"
+console.log(regex.global); // true
+console.log(regex.ignoreCase); // true
+console.log(regex.multiline); // false
+console.log(regex.unicode); // false
+console.log(regex.sticky); // false
+console.log(regex.dotAll); // false
+console.log(regex.hasIndices); // false
+```
+
+### พร็อพเพอร์ตี้ flags
+
+ตัวอย่าง 6.76 การใช้งานพร็อพเพอร์ตี้ flags
+```js
+var myRegex = /foo/i;
+console.log(myRegex.source); // "foo"
+console.log(myRegex.flags); // "i"
+```
+
+### แฟล็ก i
+
+ตัวอย่าง 6.77 การใช้งานแฟล็ก i เพื่อค้นหาคำว่า "thai" โดยไม่สนใจตัวพิมพ์ใหญ่หรือเล็ก
+```js
+var re = /thai/i;
+console.log("I' am THAI".search(re)); // 6
+```
+
+### แฟล็ก m
+
+ตัวอย่าง 6.78 เป็นการใช้แฟล็ก m ร่วมกับ $ เพื่อหาคำลงท้ายในแต่ละบรรทัด
+```js
+var str = "I' am Thai.\nI live in Bangkok."
+var re1 = /Thai.$/;
+var re2 = /Thai.$/m;
+console.log(str.search(re1)); // -1 -- หาไม่เจอ
+console.log(str.search(re2)); // 6
+```
+
+ตัวอย่าง 6.79 เป็นการใช้แฟล็ก m ร่วมกับ ^ เพื่อหาคำขึ้นต้นในแต่ละบรรทัด
+```js
+var str = "It's a good job.\nThe best show.";
+var re1 = /^The/;
+var re2 = /^The/m;
+console.log(str.search(re1)); // -1 -- หาไม่เจอ
+console.log(str.search(re2)); // 17
+```
+
+ตัวอย่าง 6.80 ถ้ามีการใช้แฟล็ก m ค่าพร็อพเพอร์ตี้ multiline จะเป็น true
+```js
+let regex = /foo/m;
+console.log(regex.multiline); // true
+```
+
+
+### แฟล็ก g
+
+ตัวอย่าง 6.81 การจับคู่ในสตริงเมื่อปราศจากแฟล็ก g
+```js
+var re = /ok/;
+console.log(re.exec("ok ok ok"));
+// [ 'ok', index: 0, input: 'ok ok ok', groups: undefined ]
+```
+
+ตัวอย่าง 6.82 เป็นการใช้แฟล็ก g ร่วมกับเมธอด exec()
+```js
+var myRegex = /Hello+/g;
+var str = "01Hello Hellooo89";
+var result = myRegex.exec(str); // ค้นหาครั้งแรก
+console.log(result[0]); // "Hello"
+console.log(result.index); // 2
+console.log(myRegex.lastIndex); // 7
+myRegex.exec(str); // ค้นหาครั้งที่ 2
+console.log(result[0]); // "Hello"
+console.log(result.index); // 2
+console.log(myRegex.lastIndex); // 15
+myRegex.exec(str); // ค้นหาครั้งที่ 3
+console.log(result[0]); // "Hello"
+console.log(result.index); // 2
+console.log(myRegex.lastIndex); // 0
+myRegex.exec(str); // ค้นหาครั้งที่ 4
+console.log(result[0]); // "Hello"
+console.log(result.index); // 2
+console.log(myRegex.lastIndex); // 7
+```
+
+ตัวอย่าง 6.83 อยากให้ลองพิจารณา regex ที่มีหน้าตาเหมือนกัน ได้แก่ /Hello+/
+```js
+console.log( /Hello+/g === /Hello+/g); // false
+/Hello+/g.exec("Hello Hello Hello"); // บรรทัด 2
+console.log(/Hello+/g.lastIndex); // 0
+```
+
+ตัวอย่าง 6.84 เป็นการใช้แฟล็ก g ร่วมกับเมธอด match() ของสตริง
+```js
+var myRegex = /Hello+/g;
+var result = "01Hello Hellooo89".match(myRegex);
+console.log(result); // [ 'Hello', 'Hellooo' ]
+console.log(myRegex.lastIndex) // 0
+```
+
+### แฟล็ก u
+
+ตัวอย่าง 6.85 เป็นปัญหาเมื่อใช้ regex จับคู่ข้อความในสตริงที่เป็นภาษาจีน
+```js
+var str = "𠮷";
+console.log(str.length); // 2
+console.log(/^.$/.test(str)); // false
+```
+
+ตัวอย่าง 6.86 เป็นการใช้แฟล็ก u จับคู่ข้อความภายในสตริง
+```js
+var str = "𠮷";
+console.log(/^.$/u.test(str)); // true
+```
+
+ตัวอย่าง 6.87 ประยุกต์ใช้แฟล็ก u เพื่อนับจำนวนตัวอักษรที่เป็นภาษาชาติไหนก็ได้
+```js
+var result1 = "𠮷กขคง𤭢".match(/[\s\S]/gu);
+console.log(result1.length); // 6
+// ถ้าไม่ใช้แฟล็ก u จะนับตัวอักษรผิด
+var result2 = "𠮷กขคง𤭢".match(/[\s\S]/g);
+console.log(result2.length); // 8
+```
+
+ตัวอย่าง 6.88 ถ้ามีการใช้แฟล็ก u ค่าพร็อพเพอร์ตี้ unicode จะเป็น true
+```js
+let regex = /foo/u;
+console.log(regex.unicode); // true
+```
+
+### แฟล็ก y
+
+ตัวอย่าง 6.89 เปรียบเทียบการใช้แฟล็ก g, แฟล็ก y และไม่ได้ใช้แฟล็กใดๆ เลย
+ตัวอย่าง 6.90 จากตัวอย่างก่อนหน้า ถ้าเรียกเมธอด exec() เป็นครั้งที่ 2 จะได้ผลลัพธ์ดังนี้
+```js
+var str = "foo1_foo2_foo3"; // สตริงที่จะค้นหา
+var regex = /foo\d_?/; // ไม่มีแฟล็ก
+var regexG = /foo\d_?/g; // แฟล็ก g
+var regexY = /foo\d_?/y; // แฟลก y
+var result = regex.exec(str);
+var resultG = regexG.exec(str);
+var resultY = regexY.exec(str);
+console.log(result[0]); // "foo1_"
+console.log(resultG[0]); // "foo1_"
+console.log(resultY[0]); // "foo1_"
+console.log(regex.lastIndex); // 0
+console.log(regexG.lastIndex); // 5
+console.log(regexY.lastIndex); // 5
+
+result = regex.exec(str);
+resultG = regexG.exec(str),
+resultY = regexY.exec(str);
+console.log(result[0]); // "foo1_"
+console.log(resultG[0]); // "foo2_"
+console.log(resultY[0]); // "foo2_"
+console.log(regex.lastIndex); // 0
+console.log(regexG.lastIndex); // 10
+console.log(regexY.lastIndex); // 10
+```
+
+ตัวอย่าง 6.91 ทำการระบุ lastIndex ก่อนการจับคู่ในสตริง
+```js
+var str = "foo1_foo2_foo3";
+var regex = /foo\d_?/; // ไม่มีแฟล็ก
+var regexG = /foo\d_?/g; // แฟล็ก g
+var regexY = /foo\d_?/y; // แฟลก y
+regex.lastIndex = 1;
+regexG.lastIndex = 1;
+regexY.lastIndex = 1;
+var result = regex.exec(str);
+var resultG = regexG.exec(str);
+var resultY = regexY.exec(str);
+console.log(result[0]); // "foo1_"
+console.log(resultG[0]); // "foo2_"
+console.log(resultY); // มีค่าเป็น null เพราะค้นหาไม่เจอข้อความ
+```
+
+ตัวอย่าง 6.92 เป็นการอ่านค่าจากพร็อพเพอร์ตี้ sticky
+```js
+var myRegex = /foo+/y;
+console.log(myRegex.sticky); // true
+myRegex.sticky = 1; // ไม่สามารถแก้ไขค่าได้ มีไว้อ่านอย่างเดียว ถ้าอยู่ในโหมดสตริคท์จะเกิด TypeError
+console.log(myRegex.sticky); // true
+```
+
+### แฟล็ก s (dotAll)
+
+ตัวอย่าง 6.93 ปัญหาเมื่อ regex ไม่สามารถจับคู่ตัวอักษร "\n" ได้
+```js
+let regex = /./;
+let result = regex.test("\n");
+console.log(result); // false
+```
+
+ตัวอย่าง 6.94 เป็นการใช้แฟล็ก s เพื่อจับคู่ตัวอักษร "\n"
+```js
+let regex = /./s;
+let result = regex.test("\n");
+console.log(result); // true
+```
+
+ตัวอย่าง 6.95 ถ้ามีการใช้แฟล็ก s ค่าพร็อพเพอร์ตี้ dotAll จะเป็น true
+```js
+let regex = /./s;
+console.log(regex.dotAll); // true
+```
+
+### แฟล็ก d
+
+ตัวอย่าง 6.96 เป็นการใช้แฟล็ก d ร่วมกับเมธอด exec() โดยยังไม่ทำการ capture ใดๆ
+```js
+let matchObj = /bar/d.exec("foo bar");
+console.log(matchObj)
+/* แสดงผลลัพธ์เป็น
+[
+ 'bar',
+ index: 4,
+ input: 'foo bar',
+ groups: undefined,
+ indices: [ [ 4, 7 ], groups: undefined ]
+] */
+console.log(matchObj.indices[0]) // [ 4, 7 ] -- จะเป็นตำแหน่งของคำว่า "bar"
+```
+
+ตัวอย่าง 6.97 ทำการ capture พร้อมกับระบุแฟล็กเป็น d
+```js
+let matchObj = /(foo).(bar)/d.exec("0123foo_bar");
+console.log(matchObj);
+/* แสดงผลลัพธ์
+[
+ 'foo_bar',
+ 'foo',
+ 'bar',
+ index: 4,
+ input: '0123foo_bar',
+ groups: undefined,
+ indices: [ [ 4, 11 ], [ 4, 7 ], [ 8, 11 ], groups: undefined ]
+] */
+console.log(matchObj.indices[0]) // [ 4, 11 ] -- จะเป็นตำแหน่งของคำว่า "foo_bar"
+console.log(matchObj.indices[1]) // [ 4, 7 ] -- จะเป็นตำแหน่งของคำว่า "foo"
+console.log(matchObj.indices[2]) // [ 8, 11 ] -- จะเป็นตำแหน่งของคำว่า "bar"
+```
+
+ตัวอย่าง 6.98 จากตัวอย่างก่อนหน้า เราสามารถ capture ด้วยการะบุชื่อ group และใช้แฟล็ก d ด้วยก็ได้
+```js
+let matchObj = /(?foo).(?bar)/d.exec("0123foo_bar");
+console.log(matchObj);
+/* แสดงผลลัพธ์
+[
+ 'foo_bar',
+ 'foo',
+ 'bar',
+ index: 4,
+ input: '0123foo_bar',
+ groups: { first: 'foo', last: 'bar' },
+ indices: [
+ [ 4, 11 ],
+ [ 4, 7 ],
+ [ 8, 11 ],
+ groups: { first: [ 4, 7 ], last: [ 8, 11 ] }
+ ]
+] */
+console.log(matchObj.indices.groups.first) // [ 4, 7 ]
+console.log(matchObj.indices.groups.last) // [ 8, 11 ]
+```
+
+ตัวอย่าง 6.99 ถ้ามีการใช้แฟล็ก d ค่าพร็อพเพอร์ตี้ hasIndices จะเป็น true
+```js
+let regex = /bar/d;
+console.log(regex.hasIndices); // true
+```
+
+### RegExp
+
+ตัวอย่าง 6.100 การสร้าง regex จาก RegExp
+```js
+var myRegex = /foo/g;
+var regex2 = new RegExp(myRegex);
+console.log(regex2.test("foo")); // true
+console.log(myRegex === regex2); // false
+```
+
+ตัวอย่าง 6.101 การสร้าง regex จาก RegExp พร้อมกับระบุค่าแฟล็ก
+```js
+var myRegex = /foo/i;
+var regex2 = new RegExp(myRegex, "g");
+console.log(myRegex.test("FOO")); // true (ไม่สนใจตัวพิมพ์ใหญ่พิมพ์เล็ก)
+console.log(regex2.test("FOO")); // false
+```
+
+ตัวอย่าง 6.102 การสร้าง regex จากสตริง
+```js
+var myRegex = new RegExp("foo", "y"); // จะเสมือนเขียน var myRegex = /foo/y;
+console.log(myRegex.exec("foo_abc")); // [ 'foo', index: 0, input: 'foo_abc', groups: undefined ]
+```
\ No newline at end of file
diff --git a/examples_book/Chapter07.md b/examples_book/Chapter07.md
new file mode 100644
index 0000000..8b802a0
--- /dev/null
+++ b/examples_book/Chapter07.md
@@ -0,0 +1,668 @@
+# โค้ดบทที่ 7 ทบทวน HTML DOM
+
+## DOM คืออะไร
+```html
+
+
+
+ "My title"
+
+
+ "My head 1"
+ "My head 2"
+
+
+```
+
+## การเข้าถึง element
+
+```html
+
+
+
+
+ My div 1
+ My div 2
+
+
+```
+
+```html
+
+
+
+
+ My div 1
+ My div 2
+
+
+
+```
+
+### ตัวอย่างการใช้งานอ็อบเจ็กต์ที่พบเจอ
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+```html
+
+
+
+
+My head 1
+My paragraph 1
+My paragraph 2
+My paragraph 3
+My paragraph 4
+
+
+
+
+
+
+
+```
+
+### สิ่งที่ควรรู้ HTMLCollection
+
+หมายเหตุ ถ้าจะรันโค้ดชุดนี้ ต้องแก้ไขให้ let all_pTag มีการประกาศแค่ครั้งเดียวพอ
+```html
+
+
+
+
+My First Paragraph 1
+My First Paragraph 2
+My First Paragraph 3
+My First Paragraph 4
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### ตัวอย่างการเข้าถึง <from>...</form>
+
+หมายเหตุ ถ้าจะรันโค้ดชุดนี้ ต้องแก้ไขให้ let elem1, let elem2 มีการประกาศแค่ครั้งเดียวพอ
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+หมายเหตุ ถ้าจะรันโค้ดชุดนี้ ต้องแก้ไขให้ let loginForm มีการประกาศแค่ครั้งเดียวพอ
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+## การเข้าถึงแอตทริบิวต์ของ element
+
+```html
+
+
+
+
+Hello World
+
+
+
+
+
+
+
+
+```
+
+
+```html
+
+
+
+
+Hello World
+
+
+
+
+
+
+
+
+```
+
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### การเพิ่มและลบ element
+### ตัวอย่างเพิ่มและลบ <p>...</p>
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### ตัวอย่างเพิ่มและลบ <option>...</option> ใน select ของ HTML
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## วิธีการแสดงเอาท์พุต
+
+### แสดงเอาท์พุตด้วยวิธีแรก
+
+```html
+
+
+
+My First Web Page
+My First Paragraph
+
+
+
+
+```
+
+### แสดงเอาท์พุตด้วยวิธีที่สอง
+
+```html
+
+
+
+My First Web Page
+My first paragraph
+
+
+
+```
+
+
+```tab.html
+
+
+
+
+
+
+ My First Web Page
+ My first paragraph
+
+
+
+```
+
+หมายเหตุ ถ้าใช้ window.open() เมื่อนั้น document.write() จะไม่เขียนทับ
+```html
+
+
+
+
+
+
+ My First Web Page
+ My first paragraph
+
+
+
+```
+
+### แสดงเอาท์พุตด้วยวิธีที่สาม
+
+```html
+
+
+
+
+
+
+```
+
+## Event คืออะไร
+
+```html
+
+
+
+
+
+
+```
+
+### วิธีแรก HTML Event Attributes
+
+```html
+
+
+
+
+
+
+```
+
+
+```html
+
+
+
+
+
+
+
+```
+
+```html
+
+
+
+
+
+
+
+```
+
+### วิธีที่ 2 ใช้ HTML DOM กำหนดซอร์สโค้ดจัดการ event
+
+```html
+
+
+
+
+
+
+
+```
+
+ตัวอย่างแรก แปะจาวาสคริปต์ไว้ที่แอตทริบิวต์ของ element ใน HTML ได้เลย
+```html
+
+
+
+
+
+
+```
+
+ตัวอย่างที่สอง จับแยกซอร์สโค้ดจาวาสคริปต์กับ HTML ออกจากกัน ไม่ต้องเรียกจาวาสคริปต์ใน element ของ HTML ดังนี้
+
+```html
+
+
+
+
+
+
+
+```
+
+### วิธีที่ 3 ใช้ DOM EventListener
+
+```html
+
+
+
+
+
+
+
+```
+
+```html
+
+
+
+
+
+
+
+
+```
+
+
+```html
+
+
+
+
+
+
+
+
+```
+
+```html
+
+
+
+
+
+
+
+
+```
+
+## Event bubbling หรือ Event capturing
+
+```html
+
+
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/examples_book/Chapter08.md b/examples_book/Chapter08.md
new file mode 100644
index 0000000..06f22e4
--- /dev/null
+++ b/examples_book/Chapter08.md
@@ -0,0 +1,413 @@
+# โค้ดบทที่ 8 ฟีเจอร์ใหม่ของตัวเลข สตริง และ regex
+
+## ตัวเลข
+### การแปลงสตริงเป็นตัวเลข
+
+```js
+console.log(Number.parseInt("15")); // 15
+console.log(Number.parseFloat("123.5")); // 123.5
+console.log(Number.parseInt("abc")); // NaN (แปลงเป็นเลขจำนวนเต็มไม่ได้)
+console.log(Number.parseFloat("abc")); // NaN (แปลงเป็นเลขทศนิยมไม่ได้)
+```
+
+```js
+console.log(parseInt("15")); // 15
+console.log(parseFloat("123.5")); // 123.5
+console.log(typeof window.parseInt); // "function" (บนเว็บบราวเซอร์)
+console.log(typeof window.parseFloat); // "function" (บนเว็บบราวเซอร์)
+//console.log(typeof global.parseInt); // "function" (บน Node.js)
+//console.log(typeof global.parseFloat); // "function" (บน Node.js)
+```
+
+### เลขฐาน 2 ฐาน 8 และฐาน 16
+```js
+console.log(Number("100")); // 100
+console.log(Number("0b111")); // 7
+console.log(Number("0o45")); // 37
+console.log(Number("0x17")); // 23
+// ใช้ Number.parseInt()
+console.log(Number.parseInt("100")); // 100
+console.log(Number.parseInt("0b111")); // 0
+console.log(Number.parseInt("0o45")); // 0
+console.log(Number.parseInt("0x17")); // 23
+```
+
+### เมธอด Number.isFinite() กับ Number.isNaN()
+```js
+console.log(isFinite(2560)); // true
+console.log(isFinite("2560")); // true
+console.log(Number.isFinite(2560)); // true
+console.log(Number.isFinite("2560")); // false
+console.log(isNaN(NaN)); // true
+console.log(isNaN("NaN")); // true
+console.log(Number.isNaN(NaN) ); // true
+console.log(Number.isNaN("NaN")); // false
+console.log(typeof window.isFinite); // "function" (บนเว็บบราวเซอร์)
+console.log(typeof window.isNaN); // "function" (บนเว็บบราวเซอร์)
+//console.log(typeof global.isFinite); // "function" (บน Node.js)
+//console.log(typeof global.isNaN); // "function" (บน Node.js)
+```
+
+### เมธอด Number.isInteger() กับ Number.isSafeInteger()
+```js
+console.log(Number.isInteger(34.6)); // false
+console.log(Number.isInteger(34.0)); // true (เขียนเป็นเลข 34.0 ก็จริง แต่จะถูกจัดเก็บเป็นเลข 34)
+console.log(Number.isInteger(34)); // true
+```
+
+```js
+console.log(Math.pow(2,53)); // 9007199254740992
+console.log(Math.pow(2,53) + 1); // 9007199254740992 -- บรรทัด 2
+console.log(Math.pow(2,53) + 2); // 9007199254740994 -- บรรทัด 3
+console.log(Math.pow(2,53) + 3); // 9007199254740996 -- บรรทัด 4
+console.log(Math.pow(2,53) * 100); // 900719925474099200 -- บรรทัด 5
+```
+
+```js
+var upper = Number.MAX_SAFE_INTEGER;
+console.log(Number.isSafeInteger(upper)); // true
+console.log(Number.isInteger(upper)); // true
+var outside_upper = upper + 1;
+console.log(Number.isSafeInteger(outside_upper)); // false
+console.log(Number.isInteger(outside_upper)); // true
+var lower = Number.MIN_SAFE_INTEGER;
+console.log(Number.isSafeInteger(lower)); // true
+console.log(Number.isInteger(lower)); // true
+var outside_lower = lower - 1;
+console.log(Number.isSafeInteger(outside_lower)); // false
+console.log(Number.isInteger(outside_lower)); // true
+```
+
+### ค่าคงที่ Number.EPSILON
+```js
+console.log(Number.EPSILON); // 2.220446049250313e-16
+```
+### BigInt
+
+```js
+let max = Number.MAX_SAFE_INTEGER;
+console.log(max); // 9007199254740991
+console.log(++max); // 9007199254740992
+console.log(++max); // 9007199254740992
+```
+
+```js
+let big = 9007199254740991n;
+console.log(big) // 9007199254740991n
+console.log(++big); // 9007199254740992n
+console.log(++big); // 9007199254740993n
+console.log(typeof big); // bigint
+```
+
+```js
+let num = 1n; // น้อยกว่า MAX_SAFE_INTEGER
+console.log(num); // 1n
+```
+
+```js
+let num = 1000000000000n;
+console.log(num.toString()); // "1000000000000"
+```
+
+### ใช้เครื่องหมาย Underscores (_) ในตัวเลข
+```js
+let num1 = 128_556_790;
+let num2 = 880_000.71;
+console.log(num1); // 128556790
+console.log(num2); // 880000.71
+```
+
+```js
+let num3 = 1000_000_000_000n;
+console.log(num3.toString()); // "1000000000000"
+```
+
+```js
+let num4 = 177_3;
+console.log(num4); // 1773
+```
+
+```js
+let num5 = _177_3;
+console.log(num5); // จะเกิด ReferenceError
+```
+
+```js
+let num6= 1773_;
+console.log(num6); // จะเกิด SyntaxError
+```
+
+## สตริง
+
+### เมธอด repeat()
+```js
+console.log( "JavaScript".repeat(3) ); // "JavaScriptJavaScriptJavaScript"
+```
+
+### เมธอด startsWith(), endsWith(), กับ includes()
+```js
+console.log("JavaScript".startsWith("Java")); // true (มีคำว่า "Java" อยู่ตำแหน่งแรก)
+console.log("JavaScript".startsWith("world")); // false (ไม่มีคำว่า "world" อยู่ตำแหน่งแรก)
+console.log("JavaScript".endsWith("Script")); // true (มีคำว่า "Script" อยู่ตำแหน่งสุดท้าย)
+console.log("JavaScript".endsWith("Hello")); // false (ไม่มีคำว่า "Hello" อยู่ตำแหน่งสุดท้าย)
+console.log("JavaScript".includes("va")); // true (มีคำว่า "va" อยู่ในสตริง)
+console.log("JavaScript".includes("same")); // false (ไม่มีคำว่า "same" อยู่ในสตริง)
+```
+
+```js
+console.log("JavaScript".startsWith("ri", 6)); // true
+console.log("JavaScript".endsWith("va", 4)); // true
+console.log("JavaScript".includes("ri", 2)); // true
+```
+
+### ยูนิโคด
+```js
+var a = "ABC";
+console.log(a.length); // 3
+console.log(a.codePointAt(0)); // 65
+console.log(a.codePointAt(1)); // 66
+console.log(a.codePointAt(2)); // 67
+console.log(a.codePointAt(3)); // undefined
+```
+
+```js
+var thai = "กขค";
+console.log(thai.length); // 3
+console.log(thai.codePointAt(0).toString(16)); // e01
+console.log(thai.codePointAt(1).toString(16)); // e02
+console.log(thai.codePointAt(2).toString(16)); // e04
+```
+
+```js
+console.log(String.fromCodePoint(42)); // "*"
+console.log(String.fromCodePoint(65, 66, 67)); // "ABC"
+console.log(String.fromCodePoint(0xe01, 0xe02, 0xe04) ); // "กขค"
+// สามารถส่งค่าอากิวเมนต์เป็นสตริงที่เขียนด้วยตัวเลข ก็สามารถทำได้เช่นกัน
+console.log(String.fromCodePoint("97", "98", "99")); // "abc"
+console.log(String.fromCodePoint("0xe07", "0xe08", "0xe09") ); // "งจฉ"
+//String.fromCodePoint('_'); // RangeError
+//String.fromCodePoint(Infinity); // RangeError
+//String.fromCodePoint(-1); // RangeError
+//String.fromCodePoint(NaN); // RangeError
+```
+
+```js
+console.log("\u{e01}"); // "ก"
+console.log("\u{e01}\u{e02}\u{e04}ABC"); // "กขคABC"
+```
+
+```js
+console.log("\u0e01"); // "ก"
+```
+
+```js
+console.log("\u20BB7"); // "₻7"
+console.log("\u{20BB7}"); // "𠮷"
+```
+
+```js
+console.log("a".length); // 1
+console.log("ก".length); // 1
+var char = "𤭢"; // "\u{24b62}" -- เป็นอักษรกลุ่ม CJK
+console.log(char.length); // 2
+```
+
+```js
+console.log("\x41"); // "A"
+console.log("\101"); // "A" - ทำไม่ได้ในโหมดสตริคท์
+```
+
+### การตั้งชื่อด้วยตัวอักษรพิเศษยูนิโคด
+
+```js
+var \u{e01} = 100; // จะเหมือนเขียน var ก = 100
+console.log(\u{e01}); // 100
+console.log("\u{e01}"); // "ก"
+var ข = "JavaScript";
+console.log(ข); // "JavaScript"
+```
+
+```js
+var \u0e01 = 100; // จะเหมือนเขียน var ก = 100
+console.log(\u0e01); // 100
+```
+
+### เมธอด normalize()
+```js
+function toCodePoint(str) { // ฟังก์ชันแสดงค่า code point ของสตริงออกทางหน้าคอนโซล
+ var concat = "";
+ for(var i = 0; i < str.length; i++ ) {
+ concat += "0x" + str.codePointAt(i).toString(16) + " ";
+ }
+ console.log(concat);
+}
+// U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE
+// U+0373: GREEK SMALL LETTER ARCHAIC SAMPI
+var str = "\u{1E9B}\u{0373}";
+var s1= str.normalize("NFC");
+toCodePoint(s1); // 0x1e9b 0x373
+var s2= str.normalize("NFD");
+toCodePoint(s2); // 0x17f 0x307 0x373
+var s3 = str.normalize("NFKC");
+toCodePoint(s3); // 0x1e61 0x373
+var s4 = str.normalize("NFKD");
+toCodePoint(s4); // 0x73 0x307 0x373
+```
+
+
+### เมธอด padStart()
+
+```js
+let str = "x";
+let newStr = str.padStart(5, "ab");
+console.log(newStr); // "ababx"
+console.log(str); // "x"
+```
+
+```js
+let str = "x";
+let newStr = str.padStart(4, "ab");
+console.log(newStr); // "abax"
+```
+
+```js
+let newStr = "abc".padStart(10, "0123456789");
+console.log(newStr); // "0123456abc"
+```
+
+```js
+let newStr = "abcd".padStart(2, "x");
+console.log(newStr); // "abcd"
+```
+
+```js
+let newStr = "x".padStart(3);
+console.log(newStr); // " x"
+console.log(newStr.length); // 3
+```
+
+```js
+let newStr = "x".padStart(3, ' ');
+console.log(newStr); // " x"
+console.log(newStr.length); // 3
+```
+
+### เมธอด padEnd()
+
+```js
+// เติม ab จำนวน 2 ครั้งต่อท้าย x
+let str1 = "x";
+let newStr1 = str1.padEnd(5, "ab");
+console.log(newStr1); // "xabab"
+// เติม ab จำนวน 2 ครั้งต่อท้าย x แต่ครั้งที่สองจะตัดให้ a
+let str2 = "x";
+let newStr2 = str2.padEnd(4, "ab");
+console.log(newStr2); // "xaba"
+// เมื่อ fillString ยาวเท่ากับ maxLength
+let newStr3 = "abc".padEnd(10, "0123456789");
+console.log(newStr3); // "abc0123456"
+// เมื่อสตริงตัวตั้งต้นมีความยาวมากกว่าค่า maxLength
+let newStr4 = "abcd".padEnd(2, "x");
+console.log(newStr4); // "abcd"
+// เมื่อไม่ระบุ fillString
+let newStr5 = "x".padEnd(3);
+console.log(newStr5); // "x "
+console.log(newStr5.length); // 3
+```
+
+```js
+let numStr = "12AF";
+let fillString = "0x";
+let maxLength = numStr.length + fillString.length;
+console.log(numStr.padStart(maxLength, fillString)); // "0x12AF"
+```
+
+```js
+let str1 = "OK";
+let str2 = "Javascript";
+let str3 = "Wow";
+let fillString = " ";
+let maxLength = fillString.length;
+console.log(maxLength); // 15
+console.log(str1.padStart(maxLength, fillString));
+console.log(str2.padStart(maxLength, fillString));
+console.log(str3.padStart(maxLength, fillString));
+/* แสดงผลลัพธ์
+ OK
+ Javascript
+ Wow
+*/
+```
+
+```js
+let filename = "test";
+let fillString = ".js";
+let maxLength = filename.length + fillString.length;
+console.log(filename.padEnd(maxLength, fillString)); // "test.js"
+```
+
+```js
+let numStr = "525";
+let fillString = ".00";
+let maxLength = numStr.length + fillString.length;
+console.log(numStr.padEnd(maxLength, fillString)); // "525.00"
+```
+
+### เมธอด trimStart() กับ trimEnd()
+
+```js
+let str1 = " ฉันรัก JavaScript";
+console.log(str1.trimStart()); // "ฉันรัก JavaScript"
+let str2 = "ฉันรัก JavaScript ";
+console.log(str2.trimEnd()); // "ฉันรัก JavaScript"
+```
+
+```js
+let str = " ฉันรัก JavaScript ";
+console.log(str.trim()); // "ฉันรัก JavaScript"
+```
+
+### เมธอด matchAll()
+
+```js
+let str = "นายไก่ เลี้ยงแต่ไก่ ไม่ขายไข่ไก่";
+for(const c of str.matchAll("ไก่") ) {
+ console.log("เจอคำว่า", c[0], "ที่ตำแหน่ง", c.index )
+}
+/* แสดงผลลัพธ์
+เจอคำว่า ไก่ ที่ตำแหน่ง 3
+เจอคำว่า ไก่ ที่ตำแหน่ง 16
+เจอคำว่า ไก่ ที่ตำแหน่ง 29 */
+```
+
+```js
+let str = "นายไก่ เลี้ยงแต่ไก่ ไม่ขายไข่ไก่";
+for(const c of str.matchAll(/ไก่/g) ) {
+ console.log("เจอคำว่า", c[0], "ที่ตำแหน่ง", c.index )
+}
+/* แสดงผลลัพธ์
+เจอคำว่า ไก่ ที่ตำแหน่ง 3
+เจอคำว่า ไก่ ที่ตำแหน่ง 16
+เจอคำว่า ไก่ ที่ตำแหน่ง 29 */
+```
+
+### เมธอด replaceAll()
+
+```js
+let str = "สมชาย น้องสมปอง มีเพื่อนชื่อ สมชาย";
+let newStr = str.replace("สมชาย", "ประยุทธ์");
+console.log(newStr) // ประยุทธ์ น้องสมปอง มีเพื่อนชื่อ สมชาย
+```
+
+```js
+let str = "สมชาย น้องสมปอง มีเพื่อนชื่อ สมชาย";
+let newStr = str.replace(/สมชาย/g, "ประยุทธ์");
+console.log(newStr) // ประยุทธ์ น้องสมปอง มีเพื่อนชื่อ ประยุทธ์
+```
+
+```js
+let str = "สมชาย น้องสมปอง มีเพื่อนชื่อ สมชาย";
+let newStr = str.replaceAll("สมชาย", "ประยุทธ์");
+console.log(newStr) // ประยุทธ์ น้องสมปอง มีเพื่อนชื่อ ประยุทธ์
+```
+
diff --git a/examples_book/Chapter09.md b/examples_book/Chapter09.md
new file mode 100644
index 0000000..8537cde
--- /dev/null
+++ b/examples_book/Chapter09.md
@@ -0,0 +1,621 @@
+# โค้ดบทที่ 9 การประกาศตัวแปร และการกำหนดค่า
+
+## การประกาศตัวแปรแบบ let
+
+```js
+function calculate(num) {
+ if (num > 10) {
+ let value = num*10; // ประกาศตัวแปรแบบ let
+ // ซอร์สโค้ดส่วนที่เหลือ
+ console.log(value); // มองเห็นตัวแปร value
+ } else {
+ // มองไม่เห็นตัวแปร value
+ }
+ // มองไม่เห็นตัวแปร value
+}
+```
+
+### การใช้ตัวแปรแบบ var เปรียบเทียบกับ let
+
+```js
+var a = 1;
+console.log(a); // 1
+{
+ var a = 2;
+ console.log(a); // 2
+}
+console.log(a); // 2
+```
+
+```js
+var a = 1;
+console.log(a); // 1
+{
+ let a = 2;
+ console.log(a); // 2
+}
+console.log(a); // 1
+```
+
+### var กับ let ในประโยควนลูป
+
+```js
+for(var i=0; i < 10; i++) { // วนลูป 10 ครั้ง
+ // ซอร์สโค้ด
+}
+// สามารถเข้าถึงตัวแปร i ที่ตอนนี้มีค่าเป็น 10 ได้
+console.log(i); // 10
+```
+
+```js
+for(let i=0; i < 10; i++) { // วนลูป 10 ครั้ง
+ // ซอร์สโค้ด
+}
+console.log(i); // จะเกิด ReferenceError เพราะมองไม่เห็นตัวแปร i
+```
+
+```js
+var array = [ ];
+for(var i=0; i < 5; i++) {
+ // เพิ่มฟังก์ชันเข้าไป เพื่อให้เป็นสมาชิกของอาร์เรย์
+ array.push( function () { console.log(i) } );
+}
+array.forEach( function(printLog) {
+ // เรียกสมาชิกของอาร์เรย์ที่เป็นฟังก์ชัน ให้ทำงาน
+ printLog(); // จะแสดงค่าของตัวแปร i เป็นเลข 5 ทั้งหมดห้ารอบด้วยกัน
+});
+/*แสดงผลลัพธ์เป็น
+5
+5
+5
+5
+5 */
+```
+
+```js
+var array = [ ];
+for(var i=0; i< 5; i++) {
+ array.push(
+ function(item) {
+ // รีเทิร์นฟังก์ชันออกไป เพื่อให้เป็นสมาชิกของอาร์เรย์
+ return function() { console.log(item); } ;
+ } ( i ) // ใช้เทคนิค IIFE
+ );
+}
+array.forEach( function(printLog) {
+ printLog(); // รอบแรกแสดงค่าเป็น 0 รอบที่สองเป็น 1 รอบที่สามเป็น 2 …จนถึงรอบที่ห้าจะแสดงค่าเป็น 4
+});
+/*แสดงผลลัพธ์เป็น
+0
+1
+2
+3
+4 */
+```
+
+```js
+var array = [ ];
+for(let i=0; i<5; i++) { // ประกาศตัวแปร i แบบ let
+ array.push( function () { console.log(i); } );
+}
+array.forEach(function(printLog){
+ printLog(); // รอบแรกแสดงค่าเป็น 0 รอบที่สองเป็น 1 รอบที่สามเป็น 2 …จนถึงรอบที่ห้าจะแสดงค่าเป็น 4
+});
+/*แสดงผลลัพธ์เป็น
+0
+1
+2
+3
+4 */
+```
+
+
+### สรุปขอบเขตการมองเห็นตัวแปรแบบ let
+
+```js
+console.log(count); // เกิด ReferenceError
+let count = 89; // จะมองเห็นตัวแปร count ตั้งแต่จุดนี้เป็นต้นไป
+if(true) {
+ console.log(count); // 89
+}
+```
+
+```js
+var count = 89;
+let count = 12; // เกิด SyntaxError เพราะประกาศชื่อตัวแปรซ้ำกัน
+```
+
+```js
+var count = 89;
+if(true) {
+ let count = 12; // จะไม่เกิด error
+ // จากนี้ไปจะมองเห็นตัวแปร count ที่ประกาศแบบ let เท่านั้น
+ console.log(count); // 12
+}
+// มองเห็นและเข้าถึงตัวแปร count ที่อยู่นอกบล็อกของ if
+console.log(count); // 89
+```
+
+## ตัวแปรค่าคงที่
+
+```js
+const MAX_COUNT = 100; // ประกาศถูกต้องตามไวยากรณ์
+const MAX_VALUE; // เกิด SyntaxError เพราะไม่ได้กำหนดค่าตั้งต้นให้แต่แรก
+const MESSAGE = "Hello"; // ประกาศถูกต้องตามไวยากรณ์
+MESSAGE = "Bye"; // เกิด TypeError เพราะไปแก้ไขตัวแปรค่าคงที่ภายหลังประกาศใช้งานแล้ว ซึ่งจะทำไม่ได้
+```
+
+```js
+console.log(count); // เกิด ReferenceError
+const count = 89; // จะมองเห็นตัวแปร count ตั้งแต่จุดนี้เป็นต้นไป
+if(true) {
+ console.log(count); // 89
+}
+```
+
+```js
+var message = "foo";
+let count = 100;
+// ประกาศตัวแปรค่าคงที่
+const message = "bar"; // เกิด SyntaxError เพราะประกาศตัวแปรชื่อซ้ำกัน
+const count = 1; // เกิด SyntaxError เพราะประกาศตัวแปรชื่อซ้ำกัน
+```
+
+```js
+var message = "foo";
+let count = 100;
+if(true) {
+ const message = "bar";
+ const count = 1;
+ // มองเห็นตัวแปร message และ count ที่ประกาศเป็นค่าคงที่เท่านั้น
+ console.log(message); // "bar"
+ console.log(count); // 1
+}
+// มองเห็นและเข้าถึง message และ count ที่อยู่นอกบล็อกของ if
+console.log(message); // "foo"
+console.log(count); // 100
+```
+
+### ข้อควรระวังเกี่ยวกับตัวแปรค่าคงที่
+
+```js
+const obj = {
+ value: 100
+};
+obj.value = 1; // สามารถแก้ไขค่าพร็อพเพอร์ตี้ภายในอ็อบเจ็กต์ได้
+console.log(obj.value); // 1
+obj = 10; // จะเกิด TypeError เพราะแก้ไขตัวแปรค่าคงที่ไม่ได้
+```
+
+```js
+for (const i=0; i < 10; i++) { // เกิด TypeError เพราะ i++ ไปแก้ไขตัวแปร i ซึ่งเป็นค่าคงที่ จะทำไม่ได้
+ // ซอร์สโค้ด
+}
+```
+
+```js
+let obj = {
+ key1: true,
+ key2: true
+};
+for (const key in obj) {
+ console.log(key);
+}
+/*แสดงผลลัพธ์เป็น
+"key1"
+"key2" */
+```
+
+```js
+for (const value of [1, 2]) {
+ console.log(value);
+}
+/*แสดงผลลัพธ์เป็น
+1
+2 */
+```
+
+## ดีสตรัคเตอร์ริ่ง
+
+```js
+let f = {
+ color: "red",
+ size: "200",
+ icon: "small",
+ style: "normal",
+ lang: "thai"
+} ;
+// การแกะข้อมูลภายในอ็อบเจ็กต์ เพื่อไปกำหนดค่าให้กับตัวแปรทีละตัว จะดูยุ่งยากมาก
+let color = f.color, size = f.size, icon = f.icon, style=f.style, lang= f.lang;
+console.log(color, size, icon, style, lang); // "red 200 small normal thai"
+```
+
+```js
+let f = ["red", "200", "small", "normal", "thai"];
+// การนำข้อมูลจากอาร์เรย์ เพื่อไปกำหนดค่าให้กับตัวแปรทีละตัว จะดูยุ่งยากมาก
+let color = f[0], size = f[1], icon = f[2], style =f[3], lang=f[4];
+console.log(color, size, icon, style, lang); // "red 200 small normal thai"
+```
+
+### ดีสตรัคเตอร์ริ่งจากอ็อบเจ็กต์
+
+```js
+let font = {
+ color: "red",
+ size: 200
+} ;
+let fontColor = font.color, fontSize = font.size;
+```
+
+```js
+let font = {
+ color: "red",
+ size: 200
+} ;
+// กำหนดค่าให้กับตัวแปร ด้วยวิธีดีสตรัคเตอร์ริ่ง
+// จะเสมือนประกาศแบบนี้
+// let fontColor = font.color, fontSize = font.size;
+let {color: fontColor, size: fontSize } = font;
+// จะประกาศตัวแปรเป็นแบบ var หรือ const ก็ทำได้เช่นกัน
+// var {color: fontColor, size: fontSize } = font;
+// const {color: fontColor, size: fontSize } = font;
+console.log(fontColor); // "red" จะมีค่าเท่ากับ font.color
+console.log(fontSize); // 200 จะมีค่าเท่ากับ font.size
+```
+
+```js
+let font = {
+ color: "red",
+ size: 200
+};
+// จะเสมือนประกาศแบบนี้
+// let color = font.color, size = font.size;
+let {color, size} = font; // กำหนดค่าให้กับตัวแปร ด้วยวิธีดีสตรัคเตอร์ริ่งแบบย่อ
+console.log(color); // "red
+console.log(size); // 200
+```
+
+
+```js
+let font = {
+ color: "red",
+ size: 200
+};
+let { color, size, style } = font;
+console.log(color); // "red"
+console.log(size); // 200
+console.log(style); // undefined
+```
+
+### อ็อบเจ็กต์ซ้อนอ็อบเจ็กต์
+```js
+let font = {
+ color: "red",
+ size: 200,
+ text : {
+ name: "thai"
+ }
+} ;
+// จะเสมือนประกาศแบบนี้
+// let color = font.color, size = font.size, name = font.text.name;
+let {color, size, text: {name} } = font;
+console.log(color, size, name); // "red 200 thai"
+```
+
+## ดีสตรัคเตอร์ริ่งจากอาร์เรย์
+
+```js
+let font = [ "red", "bold", "thai"];
+// กำหนดค่าให้กับตัวแปร ด้วยวิธีดีสตรัคเตอร์ริ่ง
+// จะเสมือนประกาศตัวแปรแบบนี้
+// let color = font[0], style = font[1];
+let [ color, style] = font;
+// จะประกาศตัวแปรเป็นแบบ var หรือ const ก็ทำได้เช่นกัน
+// var [color, style] = font;
+// const [color, style] = font;
+console.log(color); // "red" จะมีค่าเท่ากับ font[0]
+console.log(style); // "bold" จะมีค่าเท่ากับ font[1]
+```
+
+```js
+let font = [ "red", "bold", "thai"];
+let [ , style , ] = font;
+console.log(style); // "bold"
+```
+
+### อาร์เรย์ซ้อนอาร์เรย์
+
+```js
+let font = [ "red", ["200", "thai"], "bold"];
+let [ color, [size, lang], style, option] = font;
+console.log(color); // "red"
+console.log(color === font[0]); // true
+console.log(size); // "200"
+console.log(size === font[1][0]); // true
+console.log(lang); // "thai"
+console.log(lang === font[1][1]); // true
+console.log(style); // "bold"
+console.log(style === font[2]); // true
+console.log(option); // undefined
+```
+
+```js
+let font = [ "red", ["200", "thai"], "bold"];
+let [ color, option , style] = font;
+console.log(color, style); // "red bold"
+console.log(option[0]); // "200"
+console.log(option[1]); // "thai"
+console.log(option === font[1]); // true (เพราะมันอ้างอิงไปที่อาร์เรย์ตำแหน่งเดียวกัน)
+```
+
+## ข้อควรรู้เพิ่มเติมของวิธีดีสตรัคเตอร์ริ่ง
+
+```js
+let action = {
+ save: true,
+ undo: false
+};
+let save, undo;
+{save, undo} = action; // เกิด SyntaxError
+```
+
+```js
+let action = {
+ save: true,
+ undo: false
+};
+let save, undo;
+({save, undo} = action); // ใส่วงเล็บครอบทั้งประโยคจะไม่เกิด error
+console.log(save, undo); // true false
+```
+
+```js
+let font = [ "red", "bold"];
+let color, style;
+[color, style] = font; // ไม่เกิด error
+console.log(color, style); // "red bold"
+```
+
+### การระบุค่าดีฟอลต์ให้กับตัวแปร
+
+```js
+let { color, size = 200 } = {color:"red"}
+console.log(color) // "red"
+console.log(size) // 200
+```
+
+```js
+let [ , ,lang = "thai"] = []
+console.log(lang); // "thai"
+```
+
+### ข้อมูลผสมระหว่างอ็อบเจ็กต์และอาร์เรย์
+
+```js
+let action = {
+ save : "success",
+ undo : "none",
+ option : ["move", "stop", "slow"]
+};
+// กำหนดค่าให้กับตัวแปรด้วยวิธีดีสตรัคเตอร์ริ่ง
+let {save, undo, option: [ moveOption, stopOption]} = action;
+console.log(save, undo, moveOption, stopOption); // "success none move stop"
+```
+
+```js
+let action = {
+ save : "success",
+ undo : "none",
+ option : ["move", "stop", "slow"]
+};
+let {save, undo, option} = action; // บรรทัด a
+console.log(save, undo); // "success none"
+console.log(option[0]); // "move"
+console.log(option[1]); // "stop"
+console.log(option[2]); // "slow"
+console.log(option === action.option); // true (เพราะมันอ้างอิงไปที่อาร์เรย์ตำแหน่งเดียวกัน)
+```
+
+### การสลับข้อมูล
+
+```js
+let a = 1, b =2
+let temp = a; // temp เป็นตัวแปรชั่วคราวที่ใช้เก็บค่าของ a เอาไว้ก่อน
+a = b;
+b = temp;
+console.log(a); // 2
+console.log(b); // 1
+```
+
+```js
+let a = 1, b =2;
+[b , a] = [a , b]; // ดีสตรัคเตอร์ริ่งจากอาร์เรย์
+console.log(a); // 2
+console.log(b); // 1
+```
+
+```js
+let a = 1, b = 2, c = 3, d = 4;
+console.log(a, b, c, d); // 1 2 3 4
+[d, c, b ,a] = [a, b, c, d]; // ดีสตรัคเตอร์ริ่งจากอาร์เรย์
+console.log(a, b, c, d); // 4 3 2 1
+```
+
+### รับค่าจากฟังก์ชัน
+
+```js
+function myFunctin() {
+ return {a:1 ,b: 2};
+}
+let {a, b} = myFunctin();
+console.log(a, b); // 1, 2
+```
+
+```js
+function myFunctin() {
+ return [1, 2] ;
+}
+let [a, b] = myFunctin();
+console.log(a, b); // 1 2
+```
+
+### ข้อมูล JSON
+
+```js
+// เป็นข้อมูล JSON ซึ่งเขียนด้วยเทมเพลตสตริง (บทที่ 11)
+let jsonText = `{
+ "file": "index.html",
+ "menu": [
+ {"value": "New", "onclick": "createDoc"},
+ {"value": "Open", "onclick": "openDoc"}
+ ]
+}`;
+let jsonObj = JSON.parse(jsonText); // อ็อบเจ็กต์ที่ใช้เป็นตัวแทนของ JSON
+console.log(jsonObj);
+/* แสดงผลลัพธ์เป็น
+{
+ file: 'index.html',
+ menu: [
+ { value: 'New', onclick: 'createDoc' },
+ { value: 'Open', onclick: 'openDoc' }
+ ]
+} */
+let {file, menu:[ menu1, menu2] } = jsonObj;
+console.log(file); // "index.html"
+console.log(menu1.value); // "New"
+console.log(menu1.onclick); // "createDoc"
+console.log(menu2.value); // "Open"
+console.log(menu2.onclick); // "openDoc"
+```
+
+### พร็อพเพอร์ตี้แบบเรสต์
+
+```js
+let obj = {foo: 1, bar: 2, zoo: 3};
+let {foo, ...rest} = obj;
+console.log(foo); // 1
+console.log(rest) // { bar: 2, zoo: 3 }
+```
+
+```js
+let obj = {foo: 1, bar: 2, zoo: 3};
+let {...rest, zoo} = obj; // ...rest วางไว้ด้านหน้าไม่ได้ จะเกิด SyntaxError
+let {foo, ...rest1, ...rest2} = obj; // ...rest1 , ...rest2 ใช้ซ้ำกันไม่ได้ จะเกิด SyntaxError
+```
+
+
+### Nullish Coalescing operator
+
+
+```js
+console.log(null ?? 555); // 555
+```
+
+```js
+console.log(undefined ?? 666); // 666
+```
+
+```js
+let x; // x = undefined
+let a = x ?? 10;
+console.log(a); // 10
+```
+
+```js
+let x; // undefined
+let a = x || 10; // เมื่อยังไม่มีโอเปเรเตอร์ ? ให้ใช้งาน
+console.log(a); // 10
+```
+
+```js
+let x = null;
+let a = x || 10; // เมื่อยังไม่มีโอเปเรเตอร์ ? ให้ใช้งาน
+console.log(a); // 10
+```
+
+```js
+let x = 5;
+let a = x || 10; // เมื่อยังไม่มีโอเปเรเตอร์ ? ให้ใช้งาน
+console.log(a); // 5
+```
+
+```js
+let x = 0;
+let a = x || 10; // เกิดปัญหา เพราะ x มีค่าเป็น 0 ซึ่งเทียบเท่า false
+console.log(a); // 10
+a = x ?? 10; // ไม่มีปัญหาเหมือน ||
+console.log(a); // 0
+```
+
+```js
+let x; // x = undefined
+let a = x ?? 10;
+console.log(a); // 10
+```
+
+```js
+let x; // x = undefined
+let a;
+if ( x==null || x == undefined) {
+ a = 10; // default
+} else {
+ a = x;
+}
+console.log(a); // 10
+```
+
+```js
+let x; // x = undefined
+let a = (x !== undefined && x !== null) ? x : 10; // ยุบเหลือบรรทัดเดียว
+console.log(a); // 10
+```
+
+### Logical Assignment Operator
+
+* ตัวอย่างโอเปอเรเตอร์ &&=
+
+```js
+let x = true;
+let y = 555;
+x &&= y; // เสมือนเขียน x && (x=y);
+console.log(x); // 555
+```
+
+```js
+let x = false;
+let y = 555;
+x &&= y; // เสมือนเขียน x && (x=y);
+console.log(x); // false
+```
+
+* ตัวอย่างโอเปอเรเตอร์ ||=
+
+```js
+let x = false;
+let y = 666;
+x ||= y; // เสมือนเขียน x || (x=y);
+console.log(x) // 666
+```
+
+```js
+let x = true;
+let y = 555;
+x ||= y; // เสมือนเขียน x || (x=y);
+console.log(x); // true
+```
+
+* ตัวอย่างโอเปอเรเตอร์ ??=
+
+```js
+let x; // x = undefined
+let y = 777
+x ??= y; // เสมือนเขียน x = x ?? (x=y);
+console.log(x) // 777
+```
+
+```js
+let x=10;
+let y = 777
+x ??= y; // เสมือนเขียน x = x ?? (x=y);
+console.log(x) // 10
+```
diff --git a/examples_book/Chapter1.md b/examples_book/Chapter1.md
deleted file mode 100644
index 3227e64..0000000
--- a/examples_book/Chapter1.md
+++ /dev/null
@@ -1,114 +0,0 @@
-
-# บทที่ 1 แนะนำภาษาจาวาสคริปต์
-
-## จาวาสคริปต์บนเว็บเบราเซอร์
-```html
-
-
-
-
-
- Hello, world!
-
-
-```
-
-```html
-
-
-
-
-
-
-
-
-
-```
-
-## จาวาสคริปต์ฝั่งเซิร์ฟเวอร์
-```js
-var http = require('http');
-http.createServer(function (request, response) {
- response.writeHead(200, {'Content-Type': 'text/plain'});
- response.end("Hello, world!");
-}).listen(8001, '127.0.0.1');
-console.log('Server running at http://127.0.0.1:8001/');
-```
-
-## Traceur
-```html
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-## ตัวอย่าง Babel
-```html
-
-
-
-
-
-
-
-
-
-
-
-```
-
-## ตัวอย่าง ES6 นอกเว็บเบราเซอร์
-```js
-class Chat{
- constructor(message) {
- this.message = message;
- }
- say(){
- console.log(this.message);
- }
-};
-let chat = new Chat("Hello, world!");
-chat.say();
-```
diff --git a/examples_book/Chapter10.md b/examples_book/Chapter10.md
new file mode 100644
index 0000000..fc11461
--- /dev/null
+++ b/examples_book/Chapter10.md
@@ -0,0 +1,954 @@
+# โค้ดบทที่ 10 ฟังก์ชัน
+
+## นิพจน์ฟังก์ชัน
+
+```js
+let f1 = function () {
+ // ซอร์สโค้ด
+}
+const f2 = function() {
+ // ซอร์สโค้ด
+}
+var f3 = function() {
+ // ซอร์สโค้ด
+}
+f1();
+f2();
+f3();
+```
+
+## พารามิเตอร์แบบดีฟอลต์
+
+```js
+function sendMessage(ipaddress, message = "Hello" , callback = function() {}) {
+ // ถ้าไม่ส่งค่าอากิวเมนต์มาให้พารามิเตอร์ message จะมีค่าเป็น "Hello"
+ /* ถ้าไม่ส่งค่าอากิวเมนต์มาให้พารามิเตอร์ callback จะได้เป็นฟังก์ชันว่างที่ไม่ได้ทำงานอะไรเลย
+ แต่จะรีเทิร์นค่าเป็น undefined */
+ console.log(ipaddress, message, callback() );
+}
+
+// ใช้ค่าดีฟอลต์ของพารามิเตอร์ message กับ callback
+sendMessage("127.0.0.1"); // "127.0.0.1 Hello undefined"
+// ใช้ค่าดีฟอลต์ของพารามิเตอร์ callback
+sendMessage("127.0.0.1", "Good bye!"); // "127.0.0.1 Good bye! undefined"
+// ไม่ได้ใช้ค่าดีฟอลต์อะไรเลย
+sendMessage("127.0.0.1", "Good bye!", function() {
+ return "toDoSomething";
+}); // "127.0.0.1 Good bye! toDoSomething"
+```
+
+```js
+function sendMessage(ipaddress, message = "Hello", callback = function() {}) {
+ console.log(ipaddress, message, callback() );
+}
+// จะใช้ค่าดีฟอลต์ของพารามิเตอร์ callback เพียงตัวเดียวเท่านั้น
+sendMessage("127.0.0.1", null, undefined); // "127.0.0.1 null undefined"
+```
+
+### ตำแหน่งการวางพารามิเตอร์แบบดีฟอลต์
+
+```js
+function sendMessage(ipaddress, message = "Hello" , callback) {
+ console.log(ipaddress, message, typeof callback);
+}
+
+// จะใช้ค่าดีฟอลต์ของพารามิเตอร์ message เพียงตัวเดียวเท่านั้น
+sendMessage("127.0.0.1"); // "127.0.0.1 Hello undefined"
+
+sendMessage("127.0.0.1", "Hello", function() {}); // "127.0.0.1 Hello function"
+// พารามิเตอร์ message จะได้ค่าเป็น null
+sendMessage("127.0.0.1",null, function() {}); // "127.0.0.1 null function"
+// พารามิเตอร์ message จะใช้ค่าดีฟอลต์
+sendMessage("127.0.0.1", undefined, function() {}); // "127.0.0.1 Hello function"
+```
+
+```js
+function sendMessage(ipaddress, callback, message = "Hello") {
+ console.log(ipaddress, message, typeof callback);
+}
+sendMessage("127.0.0.1", function() {}); // "127.0.0.1 Hello function"
+```
+
+### ประโยชน์ของพารามิเตอร์แบบดีฟอลต์
+
+```js
+function sendMessage(ipaddress, message , callback) {
+ message = message || "Hello";
+ callback = callback || function() { return "callback";};
+ console.log(ipaddress, message, callback());
+}
+// message กับ callback จะใช้ค่าดีฟลอต์
+sendMessage("127.0.0.1"); // "127.0.0.1 Hello callback"
+sendMessage("127.0.0.1", 0, null); // "127.0.0.1 Hello callback"
+sendMessage("127.0.0.1", NaN, ''); // "127.0.0.1 Hello callback"
+```
+
+```js
+let value = 1;
+function getMessage() {
+ return "My_message_" + (value++);
+}
+function createCallback() {
+ return function() {
+ return "callback";
+ };
+}
+function sendMessage(message = getMessage(), callback = createCallback() ) {
+ console.log(message, callback());
+}
+sendMessage(); // "My_message_1 callback"
+sendMessage(); // "My_message_2 callback"
+```
+
+```js
+function add(value) {
+ return value + 10;
+}
+function calculate(a, b = add(a), c = a * b) {
+ console.log(a, b, c) ;
+}
+calculate(1,1,1); // 1 1 1
+calculate(10); // 10 20 200
+calculate(20); // 20 30 600
+calculate(30); // 30 40 1200
+```
+
+## พารามิเตอร์แบบเรสต์
+
+```js
+function iterateItem(item) {
+ console.log(item); // แสดงค่าอากิวเมนต์ตัวแรกออกมาก่อน
+ let result = 0;
+ let len = arguments.length;
+ for(let i=1; i {
+ return value;
+};
+// เรียกใช้ฟังก์ชันได้เหมือนปกติธรรมดา
+console.log(arrowFunc(122)); // 122
+```
+
+* ตัวอย่างที่ 2 ถ้าบอดี้ของฟังก์ชันลูกศรมีนิพจน์เพียงตัวเดียว ก็ไม่ต้องมีเครื่องหมายปีกกาครอบตัวบอดี้ และค่าของนิพจน์ดังกล่าวจะถูกรีเทิร์นออกมา (ไม่ต้องมีคีย์เวิร์ด return)
+
+```js
+// เหมือนในตัวอย่างที่ 1 แต่การเขียนจะสั้นและกระชับกว่า
+// ไม่ต้องมีเครื่องหมายปีกกาครอบบอดี้ฟังก์ชัน รวมทั้งไม่ต้องเขียนประโยคคำสั่ง return
+let arrowFunc = value => value;
+console.log(arrowFunc(122)); // 122
+/* จะเสมือนเขียนเป็น
+let arrowFunc = function(value) {
+ return value;
+};*/
+let arrowFunc2 = value => console.log(value);
+arrowFunc2(122); // 122
+/* จะเสมือนเขียนเป็น
+let arrowFunc2 = function(value) {
+ return console.log(value);
+};*/
+```
+
+* ตัวอย่างที่ 3 ถ้าฟังก์ชันลูกศรไม่มีการประกาศพารามิเตอร์ ก็ต้องใส่วงเล็บเข้าไปแทน
+
+```js
+// ฟังก์ชันลูกศรที่ไม่มีการประกาศพารามิเตอร์อะไรเลย
+let arrowFunc = () => 122;
+console.log(arrowFunc()); // 122
+/* จะเสมือนเขียนเป็น
+let arrowFunc = function() {
+ return 122;
+};*/
+```
+
+* ตัวอย่างที่ 4 จากตัวอย่างหน้าก่อนนี้ ถ้าฟังก์ชันลูกศรไม่ได้ทำงานอะไรเลย (ตัวบอดี้ไม่มีซอร์สโค้ด) ก็ต้องใส่ {} ปิดท้าย
+
+```js
+// ฟังก์ชันลูกศรที่ไม่มีพารามิเตอร์ และตัวบอดี้ของฟังก์ชันก็ว่างเปล่า
+let arrowFunc = () => {};
+arrowFunc();
+// จะเสมือนเขียนเป็น
+// var arrowFunc = function(){};
+```
+
+* ตัวอย่างที่ 5 ถ้าฟังก์ชันลูกศรรีเทิร์นค่าเป็นอ็อบเจ็กต์ จะต้องใส่วงเล็บครอบอ็อบเจ็กต์เสมอ เพราะถ้าไม่ใส่จะเกิด error เนื่องจากมันจะสับสนกับเครื่องหมายปีกกาของตัวบอดี้ฟังก์ชัน
+
+```js
+// ใส่เครื่องหมายวงเล็บ เพื่อครอบอ็อบเจ็กต์ที่ถูกรีเทิร์นออกมา
+let getFont = () => ( { color: "red", size: 200 } );
+console.log(getFont()); // { color: 'red', size: 200 }
+/* จะเสมือนเขียนเป็น
+let getFont = function() {
+ return {color: "red", size: 200};
+};*/
+```
+
+* ตัวอย่างที่ 6 ถ้าฟังก์ชันลูกศรมีพารามิเตอร์ตั้งแต่ 2 ตัวขึ้นไป จะต้องมีวงเล็บครอบพารามิเตอร์ และคั่นด้วยเครื่องหมายจุลภาค (,)
+
+```js
+// มีวงเล็บครอบพารามิเตอร์เอาไว้
+let sum = (val1, val2, val3) => val1 + val2 + val3;
+console.log(sum(1,2,3)); // 6
+/* จะเสมือนเขียนเป็น
+let sum = function(val1, val2, val3) {
+ return val1 + val2 +val3;
+};*/
+```
+
+* ตัวอย่างที่ 7 ฟังก์ชันลูกศรสามารถประกาศใช้พารามิเตอร์แบบดีฟอลต์
+
+```js
+// ฟังก์ชันลูกศรที่ใช้พารามิเตอร์แบบดีฟอลต์
+let sum = (val1 = 1, val2 = 2, val3 = 3) => val1 + val2 + val3;
+console.log(sum()); // 6
+/* จะเสมือนเขียนเป็น
+let sum = function(val1 = 1, val2 = 2, val3 = 3) {
+ return val1 + val2 +val3;
+};*/
+```
+
+* ตัวอย่างที่ 8 ฟังก์ชันลูกศรสามารถประกาศใช้พารามิเตอร์แบบเรสต์
+
+```js
+// ฟังก์ชันลูกศรที่ใช้พารามิเตอร์แบบเรสต์
+let max = (...value) => Math.max(...value);
+console.log(max(1, 2, 3, 6)); // 6
+/* จะเสมือนเขียน
+let max = function(...value) { // พารามิเตอร์แบบเรสต์
+ return Math.max(...value); // โอเปอเรเตอร์สเปรด
+};*/
+```
+
+### ฟังก์ชันลูกศรต่างจากฟังก์ชันธรรมดาอย่างไร
+
+```js
+let arrowFunc = value => value;
+console.log(typeof arrowFunc); // "function"
+console.log(arrowFunc instanceof Function); // true
+```
+
+```js
+let arrowFunc = () => {};
+console.log(arrowFunc.name); // จะแสดงชื่อ "arrowFunc" (ขึ้นอยู่กับจาวาสคริปต์เอ็นจิ้น)
+```
+
+### อ็อบเจ็กต์ arguments ในฟังก์ชันลูกศร
+
+```js
+// เขียนแบบฟังก์ชันลูกศร
+var arrowFunc = () => console.log(arguments); // ไม่สามารถใช้อ็อบเจ็กต์ arguments ได้
+arrowFunc(1, 2, 3); // ถ้ารันบนเว็บเบราเซอร์จะเกิด ReferenceError แต่บน Node.js ไม่เกิด error
+// เขียนแบบฟังก์ชันธรรมดา
+var arrowFunc2 = function() {
+ return console.log(arguments); // ฟังก์ชันธรรมดาสามารถใช้อ็อบเจ็กต์ arguments ได้ตามปกติ
+};
+arrowFunc2(1, 2, 3); // [Arguments] { '0': 1, '1': 2, '2': 3 }
+```
+
+```js
+function createArrow(value) {
+ // ฟังก์ชันลูกศรสามารถเรียกใช้ arguments ของฟังก์ชัน createArrow()
+ return () => arguments[0];
+}
+let arrowFunc = createArrow(1);
+console.log(arrowFunc()) // 1
+```
+
+### เทคนิคการเขียน IIFE
+```js
+// เทคนิค IIFE กับฟังก์ชันลูกศร
+var printItem = (
+(item) => function() { console.log(item); }
+)("IIFE");
+printItem(); // "IIFE"
+/* จะเสมือนใช้เทคนิค IIFE กับฟังก์ชันธรรมดา
+var printItem = function(item) {
+ return function() { console.log(item); };
+}("IIFE");
+printItem(); // "IIFE" */
+```
+
+### ฟังก์ชันคอลแบ็ค
+
+```js
+var array = [1, 2, 3, 4];
+array.forEach( (value, index, arr) => arr[index] = value *2 );
+console.log(array); // [ 2, 4, 6, 8 ]
+/* จะเสมือนใช้ฟังก์ชันคอลแบ็คแบบปกติ
+var array = [1, 2, 3, 4];
+array.forEach(function(value, index, arr) {
+ return arr[index] = value * 2;
+});
+console.log(array); // [ 2, 4, 6, 8 ] */
+```
+
+### การใช้ this ในฟังก์ชันลูกศร
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+* หมายเหตุ วิธีรันโค้ดนี้ให้ copy โค้ดจาวาสคริปต์ข้างล่าง ไปแปะไว้ในโครงสร้าง HTML ข้างบน แล้วถึงกดรันได้
+
+```js
+let obj ={
+ value : "JavaScript",
+ printValue: function() {
+ console.log("Message:", this.value); // this จะชี้ไปยังอ็อบเจ็กต์ obj
+ },
+ handle : function() {
+ console.log("Press a button");
+ },
+ init : function() {
+ let element = document.querySelector("#b1"); // ปุ่ม "Try it"
+ element.addEventListener("click", function(event) {
+ this.handle(); // this จะชี้ไปยังอ็อบเจ็กต์ obj
+ }.bind(this), false); // บรรทัด a -- this จะชี้ไปยังไปอ็อบเจ็กต์ obj
+ //}.bind(obj), false); // จะใช้บรรทัดนี้ก็ได้ มีความหมายเหมือนกัน
+ }
+}; // สิ้นสุดการประกาศอ็อบเจ็กต์
+obj.printValue(); // "Message: JavaScript"
+obj.init();
+```
+
+* หมายเหตุ วิธีรันโค้ดนี้ให้ copy โค้ดจาวาสคริปต์ข้างล่าง ไปแปะไว้ในโครงสร้าง HTML ข้างบน แล้วถึงกดรันได้
+
+```js
+let obj ={
+ value : "JavaScript",
+ printValue: function() {
+ console.log("Message:", this.value); // this จะชี้ไปยังอ็อบเจ็กต์ obj
+ },
+ handle : function() {
+ console.log("Press a button");
+ },
+ init : function() {
+ let element = document.querySelector("#b1"); // ปุ่ม "Try it"
+ element.addEventListener("click", (event)=> this.handle()); //this จะชี้ไปยัง obj
+ }
+}; // สิ้นสุดการประกาศอ็อบเจ็กต์
+obj.printValue(); // "Message: JavaScript"
+obj.init();
+```
+
+### เมธอด apply(), call() และ bind()
+
+```js
+let sum = (val1, val2) => console.log(val1 + val2) ;
+sum.apply(null, [5, 5] ); // 10
+sum.call(null, 5, 5); // 10
+let resultSum = sum.bind(null, 5, 5);
+resultSum(); // 10
+```
+
+```js
+let objA = {value: "access objA"};
+let objB = {
+ value: "access objB",
+ myFunction() {
+ console.log("this.value in myFunction:", this.value);
+ // this ในฟังก์ชันลูกศร จะเห็นเหมือนกับที่ myFunction() มองเห็น
+ let arrowFunc = () => console.log("Arrow function:", this.value);
+ let func = function() { // this ในฟังก์ชันปกติ สามารถเปลี่ยนไปชี้อ็อบเจ็กตัวอื่นได้
+ console.log("Normal function:", this.value);
+ }
+ arrowFunc.call(objA); // บรรทัด a –- ไม่สามารถเปลี่ยนค่า this ได้
+ func.call(objA); // บรรทัด b -- สามารถเปลี่ยนค่า this ให้ชี้ไปยังอ็อบเจ็กต์ objA ได้
+ }
+}
+objB.myFunction(); // บรรทัด c
+/*แสดงผลลัพธ์
+"this.value in myFunction: access objB"
+"Arrow function: access objB"
+"Normal function: access objA" */
+objB.myFunction.call(objA); // บรรทัด d
+/*แสดงผลลัพธ์
+"this.value in myFunction: access objA"
+"Arrow function: access objA"
+"Normal function: access objA" */
+```
+
+## Tail call optimization
+
+```js
+function foo(a) {
+ return a; // บรรทัด a
+}
+function bar(b) {
+ let c = b + 100;
+ return foo(c); // บรรทัด b
+}
+console.log( bar(30) ); // บรรทัด c แสดงผลลัพธ์เป็น 130
+```
+
+### ตำแหน่ง Tail call
+
+* กรณีที่ 1
+
+```js
+function foo() {
+ bar(); // เรียกฟังก์ชันแบบนี้จะไม่ใช่ตำแหน่งสุดท้าย
+ // ถ้าเขียนเป็น return bar(); จะเป็นการเรียกฟังก์ชันในตำแหน่งสุดท้าย
+}
+```
+
+```js
+function foo() {
+ bar();
+ return undefined;
+}
+```
+
+* กรณีที่ 2
+
+```js
+function foo() {
+ return 1+ bar(); // เรียกฟังก์ชันแบบนี้จะไม่ใช่ตำแหน่งสุดท้าย
+}
+```
+
+```js
+function foo() {
+ let result = bar();
+ return 1 + result;
+}
+```
+
+* กรณีที่ 3
+
+```js
+function foo(condition) {
+ if(condition) {
+ return bar(); // บรรทัด a -- เรียกฟังก์ชันในตำแหน่งสุดท้าย
+ } else {
+ bar(); // บรรทัด b -- เรียกฟังก์ชันแบบนี้จะไม่ใช่ตำแหน่งสุดท้าย
+ }
+}
+```
+
+### รีเคอร์ซีพ
+
+```js
+function factorial(value) {
+ if (value <= 0) {
+ return 1;
+ } else {
+ return value * factorial(value-1); // บรรทัด a -- ไม่ใช่การเรียกฟังก์ชันในตำแหน่งสุดท้าย
+ }
+ }
+console.log(factorial(4)); // จะได้ค่าเป็น 24 เพราะ 4! = 4 x 3 x 2 x 1 = 24
+// จะเกิด RangeError เพราะ stack frame โตมากเกินไป จนใช้หน่วยความจำหมด
+console.log(factorial(200000));
+```
+
+```js
+// ต้องประกาศเพื่อทำ TCO แต่ถ้าเขียนบน Traceur หรือ Babel ซอร์สโค้ดจะเป็นสตริคท์โหมดโดยอัตโนมัติ
+"use strict";
+function factorial(value) {
+ return callFac(1, value);
+}
+function callFac(temp, val) {
+ if (val <= 1) {
+ return temp;
+ } else {
+ return callFac(temp * val, val-1); // บรรทัด a -- เรียกฟังก์ชันในตำแหน่งสุดท้าย
+ }
+}
+console.log(factorial(4)); // 24
+console.log(factorial(200000)); // infinity
+```
+
+### นิพจน์อื่นที่เป็น Tail call
+
+* กรณีที่ 1
+
+```js
+let arrowFunc = param => param ? foo() : bar();
+```
+
+```js
+let arrowFunc = param => {
+ if(param) {
+ return foo(); // เรียกฟังก์ชันในตำแหน่งสุดท้าย
+ } else {
+ return bar(); // เรียกฟังก์ชันในตำแหน่งสุดท้าย
+ }
+};
+```
+กรณีที่ 2
+
+```js
+let arrowFunc = () => (foo(), bar(), zoo());
+```
+
+```js
+let arrowFunc = () => {
+ foo();
+ bar();
+ return zoo(); // เรียกฟังก์ชันในตำแหน่งสุดท้าย
+};
+```
+
+กรณีที่ 3
+
+```js
+let arrowFunc = () => foo() || bar();
+```
+
+```js
+let arrowFunc = () => {
+ let temp = foo();
+ if (temp) {
+ return temp;
+ } else {
+ return bar(); // เรียกฟังก์ชันในตำแหน่งสุดท้าย
+ }
+};
+```
+
+กรณีที่ 4
+
+```js
+let arrowFunc = () => foo() && bar();
+```
+
+```js
+let arrowFunc = () => {
+ let temp = foo();
+ if (!temp) {
+ return temp;
+ } else {
+ return bar(); // เรียกฟังก์ชันในตำแหน่งสุดท้าย
+ }
+};
+```
+
+## การใช้คอมมา (,)
+
+```js
+let arr = [ "red", "green", "blue", ];
+```
+
+```js
+let arr = [ "green", "blue", "red", ];
+```
+
+```js
+let obj = {
+ foo: 1,
+ bar: 2,
+};
+```
+
+```js
+let obj = {
+ bar: 2,
+ foo: 1,
+};
+```
+
+```js
+let obj = { foo: 1, bar: 2, };
+```
+
+```js
+let arr = [
+ "green",
+ "blue",
+ "red",
+ ];
+```
+
+```js
+function foo(param1, param2, ) {
+ console.log(arguments);
+}
+
+foo( "abc", "def", ); // [Arguments] { '0': 'abc', '1': 'def' }
+```
+
+```js
+// ตอนประกาศฟังก์ชัน
+function foo(
+ param2,
+ param1,
+) {
+ console.log(arguments);
+}
+// ตอนเรียกฟังก์ชัน
+foo(
+ "def",
+ "abc",
+);
+// แสดงผลลัพธ์
+// [Arguments] { '0': 'def', '1': 'abc' }
+```
diff --git a/examples_book/Chapter11.md b/examples_book/Chapter11.md
new file mode 100644
index 0000000..06e1538
--- /dev/null
+++ b/examples_book/Chapter11.md
@@ -0,0 +1,231 @@
+# โค้ดบทที่ 11 เทมเพลตสตริง
+
+## เทมเพลตสตริงคืออะไร
+
+```js
+let msg = `JavaScript`;
+console.log(msg); // "JavaScript"
+console.log(msg.length); // 10
+console.log(typeof msg); // "string"
+```
+
+```js
+let msg = `\`One\` "Two" ‘Three’`;
+console.log(msg); // แสดงคำว่า `One` "Two" ‘Three’
+```
+
+### เขียนสตริงหลายบรรทัด
+
+```js
+let div = `
+
Hello world
+`;
+console.log(div);
+/* แสดงผลลัพธ์เป็น
+
+
Hello world
+
+*/
+```
+
+```js
+let div = "\n\t
Hello world
\n";
+console.log(div);
+/* แสดงผลลัพธ์เป็น
+
+
Hello world
+
+*/
+```
+
+```js
+let div = "\n" +
+"
Hello world
\n" +
+"";
+console.log(div);
+/* แสดงผลลัพธ์เป็น
+
+
Hello world
+
+*/
+```
+
+```js
+let div = ["", "\t
Hello world
", ""].join("\n");
+console.log(div);
+/* แสดงผลลัพธ์เป็น
+
+
Hello world
+
+*/
+```
+
+```js
+let div = "\
+
Hello world
\
+";
+console.log(div);
+// แสดงผลลัพธ์เป็น
+// Hello world
+```
+
+```js
+let msg = `Hello\nworld`;
+console.log(msg);
+/* แสดงผลลัพธ์เป็น
+Hello
+world
+*/
+```
+
+### คอมเมนต์ในเทมเพลตสตริง
+
+```js
+let msg = `First line // This is not a comment
+/*
+This is not a comment
+*/
+Last line`;
+console.log(msg);
+```
+
+* โค้ดข้างบนจะแสดงผลดังนี้
+```notrun
+First line // This is not a comment
+/*
+This is not a comment
+*/
+Last line
+```
+
+### ความยาวของเทมเพลตสตริง
+
+```js
+let msg = `
+JavaScript
+ String`;
+console.log(msg.length); // 20
+console.log(msg.trim().length); // 19
+```
+
+## นิพจน์ในเทมเพลตสตริง
+```notrun
+${นิพจน์}
+```
+
+```js
+let name = "Somchai";
+let msg = `My name is ${name}`;
+console.log(msg) // "My name is Somchai"
+```
+
+```js
+let a = 5, b = 10, c = 100;
+console.log("Price $" + ((a*b).toFixed(2)) + ", not " + (c + a) );
+// แสดงผลลัพธ์เป็น
+// "Price $50.00, not 105"
+```
+
+```js
+let a = 5, b = 10, c = 100;
+console.log(`Price $${(a*b).toFixed(2)}, not ${c + a}` );
+// แสดงผลลัพธ์เป็น
+// "Price $50.00, not 105"
+```
+
+```js
+function myFunction() {
+ let name = "Somchai";
+}
+console.log(`My name is ${name}`);
+// อาจเกิด ReferenceError หรือไม่มีค่า name (ขึ้นอยู่กับจาวาสคริปต์เอนจิน)
+```
+
+## การติดแท็ก
+```notrun
+let n = 1, a = 3, b = 6;
+console.log(divTag`${n}) Hello world : ${a * b} items`); // บรรทัด 2
+```
+
+```js
+function divTag(strings, ...values) {
+ //console.log(strings[0]); // ""
+ //console.log(strings[1]); // ") Hello world world : "
+ //console.log(strings[2]); // " items"
+ //console.log(values[0]); // 1 (เป็นค่าของนิพจน์ ${n} )
+ //console.log(values[1]); // 18 (เป็นค่าของนิพจน์ ${a * b} )
+ let result = "";
+ for (let i = 0; i < values.length; i++) {
+ result += strings [i];
+ result += values [i];
+ }
+ if(values.length < strings.length){
+ result += strings[values.length]; // ต่อท้ายสตริงด้วยข้อความที่เหลือคือ " items"
+ }
+// เมื่อโปรแกรมทำงานถึงตรงนี้ ค่าของตัวแปร result ก็คือสตริงตัวเดิมที่ถูกส่งเข้ามา
+// ส่วนค่าที่รีเทิร์นออกมา จะเป็นสตริงตัวใหม่ที่มี กับ
ครอบเปิดและปิดท้ายสตริงตัวเดิม
+ return `${result}
`;
+}
+let n = 1, a = 3, b = 6;
+console.log(divTag`${n}) Hello world : ${a * b} items`);
+// แสดงผลลัพธ์เป็น
+// "1) Hello world : 18 items
"
+```
+
+```notrun
+divTag`${n}) Hello world : ${a * b} items`
+```
+
+### String.raw
+```js
+console.log(`One\tTwo\nThree`);
+/* เมื่อตัวอักษรพิเศษถูกประมวลผล ก็จะแสดงผลลัพธ์เป็น
+"One Two
+Three"
+*/
+```
+
+```js
+console.log(String.raw `One\tTwo\nThree`);
+// แสดงผลลัพธ์เป็น
+// "One\tTwo\nThree"
+```
+
+```js
+function rawTag(strings, ...values) {
+ let result = "";
+ for (let i = 0; i < strings.length; i++) {
+ result += strings.raw[i]; // บรรทัด a
+ }
+ return result;
+}
+console.log(rawTag`One\tTwo\nThree`);
+// แสดงผลลัพธ์เป็น
+// "One\tTwo\nThree"
+```
+
+```js
+console.log(`\u{004B}`); // ’K’
+console.log(`\u004B`); // ’K’
+console.log(`\x4B`); // ’K’
+```
+
+```js
+console.log("C:\unit\x-ray\12"); // เกิด SyntaxError
+console.log(`C:\unit\x-ray\12`); // เกิด SyntaxError
+```
+
+```js
+function windowPath(str) {
+ console.log(str[0]) // ถ้าใช้ \ ผิด ก็จะได้สตริงเป็น undefined
+ }
+windowPath `C:\unit\x-ray\12`; // undefined
+```
+
+```js
+function windowPath(str) {
+ return str.raw[0];
+ }
+let str = windowPath `C:\unit\x-ray\12`;
+console.log(str) // C:\unit\x-ray\12
+```
\ No newline at end of file
diff --git a/examples_book/Chapter12.md b/examples_book/Chapter12.md
new file mode 100644
index 0000000..5fa53c3
--- /dev/null
+++ b/examples_book/Chapter12.md
@@ -0,0 +1,176 @@
+# โค้ดบทที่ 12 ซิมโบล
+
+## การใช้งานซิมโบล
+
+```js
+let sym1 = Symbol(); // ไม่มี description
+let sym2 = Symbol("example"); // มี description เป็น "example"
+let sym3 = Symbol("example"); // มี description เป็น "example"
+console.log(sym2 === sym3); // false
+```
+
+```js
+let sym = Symbol("example");
+console.log(sym.toString()); // Symbol(example)
+console.log(sym); // Symbol(example)
+```
+
+```js
+console.log( typeof Symbol() ); // "symbol"
+console.log( typeof Symbol("example") ); // "symbol"
+```
+
+```js
+let uid = Symbol.for("uid");
+console.log( uid && true ); // true
+console.log( !true ); // false
+```
+
+## ข้อควรระวังการใช้ซิมโบล
+
+```js
+let bool = new Boolean(); // สามารถทำได้
+let str = new String(); // สามารถทำได้
+let num = new Number(); // สามารถทำได้
+let sym = new Symbol(); // จะเกิด TypeError
+```
+
+```js
+let sym = Symbol("example");
+let symObj1 = Object(sym);
+let symObj2 = new Object(sym);
+console.log(typeof sym); // "symbol"
+console.log(typeof symObj1); // "object"
+console.log(typeof symObj2); // "object"
+```
+
+```js
+let sym1 = Symbol("example1");
+let sym2 = Symbol("example2");
+console.log(sym1 == Object(sym1)); // true
+console.log(sym2 == Object(sym1)); // false
+```
+
+## ใช้ซิมโบลเป็นคีย์ในอ็อบเจ็กต์
+
+```js
+let sym = Symbol("first symbol");
+let obj = { [sym]: 100 }; // ใช้ซิมโบลเป็นชื่อคีย์ในอ็อบเจ็กต์
+console.log(obj[sym]); // 100
+obj[sym] = 200;
+console.log(obj[sym]); // 200
+let lastSym = Symbol("last symbol");
+Object.defineProperties(obj, {
+ [lastSym]: { // ใช้ซิมโบลเป็นชื่อคีย์ในอ็อบเจ็กต์
+ value: 300,
+ writable: true
+ }
+});
+console.log(obj[lastSym]); // 300
+Object.defineProperty(obj, sym, { writable: false }); // กำหนดให้พร็อพเพอร์ตี้ ไม่สามารถแก้ไขค่าได้
+obj[sym] = 1; // ถ้าอยู่ในโหมดสตริคท์ จะเกิด TypeError เพราะไม่สามารถแก้ไขค่าได้
+```
+
+## การแชร์ซิมโบล
+
+```js
+let uid = Symbol.for("uid"); // มีค่า description เป็น "uid"
+console.log(uid); // Symbol(uid)
+```
+
+```js
+let sym1 = Symbol.for("uid"); // ค้นหาซิมโบลครั้งแรก
+let sym2 = Symbol.for("uid"); // ค้นหาซิมโบลครั้งที่สอง
+console.log(sym1 === sym2); // true (เพราะ sym1 กับ sym2 คือซิมโบลตัวเดียวกัน)
+console.log(sym1); // Symbol(uid)
+// เนื่องจาก sym1 กับ sym2 คือซิมโบลตัวเดียวกัน จึงสามารถใช้แทนกันได้
+let obj = {[sym1]: 100};
+console.log(obj[sym2]); // 100
+```
+
+```js
+let sym1 = Symbol.for("uid");
+console.log(Symbol.keyFor(sym1)); // "uid"
+let sym2 = Symbol("uid");
+console.log(Symbol.keyFor(sym2)); // undefined
+```
+
+```js
+Symbol.for("dojo.uid");
+Symbol.for("jquery.uid");
+```
+
+## ซิมโบลในประโยค for...in
+
+```js
+let obj = { };
+obj.car = "100";
+obj["zoo"] = "200";
+obj[Symbol("foo")] = "foo";
+obj[Symbol("bar")] = "bar";
+for (let i in obj) {
+ console.log(i);
+}
+// ประโยค for จะแสดงผลลัพธ์
+// "car"
+// "zoo"
+console.log(Object.getOwnPropertyNames(obj)); // [ 'car', 'zoo' ]
+console.log(Object.keys(obj)); // [ 'car', 'zoo' ]
+```
+
+```js
+let obj = {};
+obj.car = "100";
+obj["zoo"] = "200";
+obj[Symbol("foo")] = "foo";
+obj[Symbol("bar")] = "bar";
+let keys = Object.getOwnPropertySymbols(obj);
+console.log(keys); // [ Symbol(foo), Symbol(bar) ]
+```
+
+## JSON.stringify()
+
+```js
+let obj = {
+[Symbol("example")]: "100",
+"bar" : "200"
+}
+// จะได้เป็นสตริงที่เขียนอยู่ในรูปแบบของ JSON
+console.log(JSON.stringify(obj)); // {"bar":"200"}
+```
+
+## แปลงซิมโบลเป็นสตริง
+
+```js
+let sym = Symbol("foo");
+++sym; // TypeError
+sym + 0; // TypeError
+```
+
+```js
+Symbol("foo") + "bar"; // TypeError
+```
+
+```js
+let sym = Symbol("foo");
+console.log(sym.toString()); // Symbol(foo)
+console.log(String(sym)); // Symbol(foo)
+new String(sym); // TypeError
+```
+
+```js
+let sym = Symbol("foo");
+console.log(`${sym.toString()}`); // Symbol(foo)
+console.log(`${String(sym)}`); // Symbol(foo)
+console.log(`${sym}`) // TypeError
+```
+
+## พร็อพเพอร์ตี้ description
+
+```js
+let sym= Symbol("foo");
+console.log(sym) // Symbol(foo)
+console.log(String(sym) === `Symbol(${"foo"})`); // true
+console.log(sym.toString()); // Symbol(foo)
+console.log(sym.description); // "foo"
+```
\ No newline at end of file
diff --git a/examples_book/Chapter13.md b/examples_book/Chapter13.md
new file mode 100644
index 0000000..e35f0f7
--- /dev/null
+++ b/examples_book/Chapter13.md
@@ -0,0 +1,763 @@
+# โค้ดบทที่ 13 ฟีเจอร์ใหม่ของอ็อบเจ็กต์
+
+## กำหนดค่าให้พร็อพเพอร์ตี้แบบย่อ
+
+```js
+let color = "red";
+let size = 200;
+let font = {
+ color: color, // คีย์กับข้อมูล ชื่อซ้ำกัน
+ size: size // คีย์กับข้อมูล ชื่อซ้ำกัน
+};
+console.log(font.color); // "red"
+console.log(font.size); // 200
+```
+
+```js
+let color = "red";
+let size = 200;
+let font = { color, size}; // พร็อพเพอร์ตี้ของอ็อบเจ็กต์แบบย่อ
+console.log(font.color); // "red"
+console.log(font.size); // 200
+```
+
+## การประกาศเมธอดแบบย่อ
+```js
+let obj = {
+ myFunction: function (param) { // ประกาศเมธอดเต็มรูปแบบ
+ console.log(param);
+ }
+};
+obj.myFunction(200); // 200
+```
+
+```js
+let obj = {
+ myFunction(param) { // ประกาศเมธอดแบบย่อ
+ console.log(param);
+ }
+} ;
+obj.myFunction(200); // 200
+```
+
+## ชื่อคีย์ซ้ำกัน
+
+```js
+let font = {
+ color: "red",
+ color: "green", // เลือกใช้ตัวนี้
+ myFunction() {
+ console.log("myFunction1");
+ },
+ myFunction() { // เลือกใช้ตัวนี้
+ console.log("myFunction2");
+ }
+} ;
+console.log(font.color); // "green"
+font.myFunction(); // "myFunction2"
+```
+
+## ประกาศชื่อคีย์แบบวงเล็บเหลี่ยม
+
+```js
+let name = "name"
+let student = {
+ ["First " + name] : "Somchai", // ประกาศชื่อคีย์แบบวงเล็บเหลี่ยม
+ [ `Last ${name}`] : "Jaidee" // ประกาศชื่อคีย์แบบวงเล็บเหลี่ยม (ใช้เทมเพลตสตริง)
+};
+console.log(student["First name"]); // "Somchai"
+let lastName = `Last ${name}`;
+console.log(student[lastName]); // "Jaidee"
+```
+
+```js
+let key1 = {a:1};
+let key2 = {b:2};
+let obj = {
+ [key1] : 100,
+ [key2]: 200 // ใช้คีย์ตัวนี้
+}
+console.log(obj[key1], obj[key2]); // 200 200
+console.log(obj[key1] === obj[key2]); // true
+```
+
+
+```js
+let name = "myFunction";
+let obj = {
+ [name]: function(param) { // ประกาศเมธอดโดยใช้วงเล็บเหลี่ยม
+ console.log(param);
+ }
+};
+obj[name](200); // 200
+obj.myFunction(200); // 200
+```
+
+```js
+let name = "myFunction";
+let obj = {
+ [name](param) { // ประกาศเมธอดแบบย่อ
+ console.log(param);
+ }
+};
+obj[name](200); // 200
+obj.myFunction(200); // 200
+```
+
+## เมธอด Object.assign()
+
+```js
+let obj = { x: 1, y: 2 };
+let cloned1 = Object.assign({}, obj);
+let cloned2 = Object.assign({}, obj);
+//สร้างอ็อบเจ็กต์ใหม่ได้เรื่อย ๆ ที่เหมือนกับอ็อบเจ็กต์ต้นแบบ obj ทุกประการ
+console.log(cloned1); // { x: 1, y: 2 }
+console.log(cloned2); // { x: 1, y: 2 }
+console.log(cloned1 === cloned2); // false
+```
+
+```js
+let obj1 = { x: 1 };
+let obj2 = { y: 2 };
+let obj3 = { z: 3 };
+let merged = Object.assign(obj1, obj2, obj3);
+console.log(merged); // { x: 1, y: 2, z: 3 }
+console.log(obj1); // { x: 1, y: 2, z: 3 }
+console.log(merged === obj1); // true
+console.log(merged === obj2); // false
+console.log(merged === obj3); // false
+```
+
+```js
+let person1 = {};
+let person2 = {
+ firstName: "Somchai",
+ lastName: "Jaidee"
+};
+let person3 = {
+ lastName: "Dekdee"
+};
+let person4 = {
+ lastName: "Rakdee" // ถ้าชื่อคีย์มันซ้ำกัน จะเลือกก็อปปี้จากอ็อบเจ็กต์ตัวล่าสุดเท่านั้น
+};
+Object.assign(person1, person2, person3, person4);
+console.log(person1.firstName); // "Somchai"
+console.log(person1.lastName); // "Rakdee"
+```
+
+```js
+let sym = Symbol("example");
+let name = "to do";
+let obj = {
+ myFunction(param) {
+ console.log(param);
+ },
+ [ `${name}`]( ) {
+ console.log("to do something");
+ },
+ x : null,
+ y : undefined,
+ [sym] : 100
+};
+let cloned = Object.assign({}, obj);
+cloned.myFunction(200); // 200
+cloned[`${name}`](); // "to do something"
+console.log(cloned.x); // null
+console.log(cloned.y); // undefined
+console.log(cloned[sym]); // 100
+```
+
+```js
+let person = {
+ set firstName(param) {
+ this.fname = param;
+ },
+ get firstName() {
+ return this.fname;
+ }
+};
+person.firstName = "Somchai";
+let target = Object.assign({}, person);
+let descriptor = Object.getOwnPropertyDescriptor(target, "firstName");
+console.log(descriptor.value); // "Somchai"
+console.log(typeof descriptor.set); // undefined
+console.log(typeof descriptor.get); // undefined
+console.log(target.firstName); // "Somchai"
+```
+
+```js
+let font = {} ;
+Object.defineProperties (font, {
+ color: {
+ value : "red",
+ writable: false // ไม่สามารถก็อปปี้ได้
+ },
+ size: {
+ value : 200,
+ enumerable: false // ไม่สามารถก็อปปี้ได้
+ }
+});
+let obj = Object.assign({}, font);
+console.log(typeof obj.color); // undefined
+console.log(typeof obj.size); // undefined
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car") ;
+ }
+};
+let taxi = Object.create(car); // กำหนดให้ taxi มีโปรโตไทป์เป็น car
+taxi.drive(); // "Drive a car"
+let driver = Object.assign({}, taxi); // driver โคลนนิ่งมาจาก taxi
+console.log(typeof driver.drive); // undefined
+```
+
+## การเปลี่ยนโปรโตไทป์
+```js
+let car = {
+ drive() {
+ console.log("Drive a car") ;
+ }
+};
+let taxi = {
+ drive() {
+ console.log("Drive a taxi") ;
+ }
+};
+let driver = Object.create(car); // บรรทัด a -- โปรโตไทป์คือ car
+console.log( Object.getPrototypeOf(driver) === car); // true
+driver.drive(); // "Drive a car"
+Object.setPrototypeOf(driver, taxi); // บรรทัด b -- เปลี่ยนโปรโตไทป์เป็น taxi
+console.log( Object.getPrototypeOf(driver) === taxi); // true
+driver.drive(); // "Drive a taxi"
+```
+
+## '__proto__'
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car") ;
+ }
+};
+let taxi = {
+ drive() {
+ console.log("Drive a taxi") ;
+ }
+};
+let driver ={
+ __proto__ : car // โปรโตไทป์คือ car
+}
+console.log(driver.__proto__ === car); // true
+driver.drive(); // "Drive a car"
+driver.__proto__ = taxi; // เปลี่ยนโปรโตไทป์เป็น taxi
+console.log(driver.__proto__ === taxi); // true
+driver.drive(); // "Drive a taxi"
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car") ;
+ }
+};
+let driver ={
+ __proto__ : car,
+ __proto__ : car // SyntaxError
+}
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car") ;
+ }
+};
+let driver = {
+ ["__proto__"]: car
+}
+console.log(typeof driver.drive); // undefined
+console.log(driver["__proto__"] === car); // true
+```
+
+## การใช้ supper
+
+```js
+let car = {
+ speed: 100,
+ drive() {
+ return "Car speed: ";
+ }
+};
+let driver = {
+ __proto__: car,
+ drive() {
+ return "Car speed: " + this.speed ;
+ }
+};
+console.log(driver.speed); // 100
+console.log(driver.drive()); // "Car speed: 100"
+```
+
+```js
+let car = {
+ speed: 100,
+ drive() {
+ return "Car speed: " ;
+ }
+};
+let driver = {
+ __proto__: car,
+ drive() {
+ return super.drive() + super.speed ; // เรียกใช้งาน super
+// อาจเรียกวิธีนี้แทนก็ได้
+// 1) return Object.getPrototypeOf(this).drive.call(this) + this.__proto__.speed;
+// 2) return this.__proto__. drive.call(this) + this.__proto__.speed;
+ } // สิ้นสุดการประกาศ drive()
+};
+console.log(driver.speed); // 100
+console.log(driver.drive()); // "Car speed: 100"
+```
+
+```js
+let car = {
+ ["car speed"]: 100,
+ ["drive a car"] ( ) {
+ return "Car speed: " ;
+ }
+};
+let driver = {
+ __proto__: car,
+ speed: 900,
+ drive() {
+ return super["drive a car"]() + super["car speed"] ; // เรียกใช้งาน super
+ }
+};
+console.log(driver.speed); // 900
+console.log(driver.drive()); // "Car speed: 100"
+```
+
+```js
+let car = {
+ drive() {
+ return "is driving";
+ }
+};
+let taxi = {
+ __proto__ : car, // โปรโตไทป์คือ car
+ drive() {
+ return super.drive() + " a taxi";
+ }
+};
+let driver ={
+ __proto__ : taxi, // โปรโตไทป์คือ taxi
+ drive() {
+ return "Someone " + super.drive();
+ }
+}
+console.log(car.drive()); // "is driving"
+console.log(taxi.drive()); // "is driving a taxi"
+console.log(driver.drive()); // "Someone is driving a taxi"
+```
+
+```js
+let car = {
+ drive() {
+ return "Driving";
+ }
+};
+let taxi = {
+ __proto__ : car, // โปรโตไทป์คือ car
+ drive() {
+ return super.drive() + " a taxi"; // บรรทัด a
+ }
+};
+let driver = {
+ __proto__ : taxi // โปรโตไทป์คือ taxi
+}
+console.log(car.drive()); // "Driving"
+console.log(taxi.drive()); // "Driving a taxi"
+console.log(driver.drive()); // "Driving a taxi"
+```
+
+```js
+let car = {
+ drive() {
+ return "Driving";
+ }
+};
+let taxi = {
+ __proto__ : car, // โปรโตไทป์คือ car
+ drive() {
+ return Object.getPrototypeOf(this).drive.call(this) + " a taxi";
+ }
+};
+let driver ={
+ __proto__ : taxi // โปรโตไทป์คือ taxi
+}
+console.log(car.drive()); // "Driving"
+console.log(taxi.drive()); // "Driving a taxi"
+console.log(driver.drive()); // RangeError: Maximum call stack size exceeded
+```
+
+### เบื้องหลังการใช้งาน super
+
+```js
+function drive() {
+ console.log("Drive a taxi");
+}
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car");
+ }
+};
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car. It has speed:", this.speed ) ;
+ }
+};
+let driver = {
+ __proto__: car,
+ speed: 100,
+ drive() { // บรรทัด a
+ super.drive(); // บรรทัด b
+ // จะเหมือน Object.getPrototypeOf(driver).drive.call(this);
+ } // สิ้นสุดการประกาศ drive()
+};
+driver.drive(); // "Drive a car. It has speed: 100"
+```
+
+```js
+function startCar() {
+ console.log( super.drive()); // เกิด SyntaxError
+}
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car. It has speed:", this.speed ) ;
+ }
+};
+let driver = {
+ __proto__: car,
+ speed: 100,
+ drive() {
+ console.log("Drive a taxi") ;
+ }
+};
+function startCar() {
+ return super.drive() + " :100"; // บรรทัด a - เกิด SyntaxError
+}
+driver.drive = startCar; // กำหนดค่าทับพร็อพเพอร์ตี้ driver.drive
+driver.drive();
+```
+
+```js
+let car = {
+ drive() {
+ console.log("Drive a car. It has speed:", this.speed ) ;
+ }
+};
+let driver = {
+ __proto__: car,
+ speed: 100,
+ drive: function() { // บรรทัด a -- ไม่ได้ประกาศเมธอดแบบย่อ
+ super.drive(); // บรรทัด b - เกิด SyntaxError
+ } // สิ้นสุดการประกาศ drive()
+};
+driver.drive();
+```
+
+## เมธอด Object.is()
+```js
+console.log(NaN === NaN); // false
+console.log(-0 === +0); // true
+```
+
+```js
+// เปรียบเทียบค่า NaN
+console.log(NaN === NaN); // false
+console.log(NaN === 0/0); // false
+console.log(Object.is(NaN, NaN)); // true
+console.log(Object.is(NaN, 0/0)); // true
+// เปรียบเทียบเลข 0
+console.log(+0 === -0); // true
+console.log(Object.is(+0, -0)); // false
+// เปรียบเทียบตัวเลข
+console.log(10 === 10); // true
+console.log(10 === "10"); // false
+console.log(Object.is(10, 10)); // true
+console.log(Object.is(10, "10")); // false
+// เปรียบเทียบอ็อบเจ็กต์
+console.log([] === []); // false
+console.log({} === {}); // false
+console.log(Object.is([], [])); // false
+console.log(Object.is({}, {})); // false
+var obj = { x: 1, y: 2 };
+console.log(obj === obj); // true
+console.log(Object.is(obj, obj)); // true
+// เปรียบเทียบค่า undefinded และ null
+console.log(undefined === undefined); // true
+console.log(null === null); // true
+console.log(Object.is(undefined, undefined)); // true
+console.log(Object.is(null, null)); // true
+// เปรียบเทียบสตริง
+console.log("Hello" === "Hello"); // true
+console.log(Object.is("Hello", "Hello")); // true
+// เปรียบเทียบบูลีน
+console.log("" === false); // false
+console.log(0 === false); // false
+console.log(0 === ""); // false
+console.log(false === false); // true
+console.log(Object.is("", false)); // false
+console.log(Object.is(0, false)); // false
+console.log(Object.is(0, "")); // false
+console.log(Object.is(false, false)); // true
+```
+## เมธอด Object.values()
+
+```js
+let obj = { foo: 1, bar: 2 };
+let array = Object.values(obj);
+console.log(array); // [ 1, 2 ]
+```
+
+```js
+let foo = Symbol("foo");
+let obj = {
+ [foo]: 1,
+ bar: 2,
+ };
+let array = Object.values(obj);
+console.log(array); // [ 2 ]
+```
+
+```js
+let obj = { foo: 1, bar: 2 };
+for (let v of Object.values(obj)) { // สกัดส่วนข้อมูลจากอ็อบเจ็กต์ obj ออกมา
+ console.log(v);
+}
+/* แสดงผลลัพธ์
+1
+2 */
+```
+
+## เมธอด Object.entries()
+
+```js
+let obj = { foo: 1, bar: 2 };
+let array = Object.entries(obj);
+console.log(array); // [ [ 'foo', 1 ], [ 'bar', 2 ] ]
+```
+
+```js
+let foo = Symbol("foo");
+let obj = {
+ [foo]: 1, // มีคีย์เป็นซิมโบล
+ bar: 2,
+ };
+let array = Object.entries(obj);
+console.log(array); // [ [ 'bar', 2 ] ]
+```
+
+```js
+let obj = { foo: 1, [Symbol("bar")]: 2 };
+// เข้าถึงคีย์ของ obj รวมทั้งคีย์ที่เป็นซิมโบลด้วย
+console.log(Reflect.ownKeys(obj).map( (k)=>[k, obj[k]])); // [ [ 'foo', 1 ], [ Symbol(bar), 2 ] ]
+// เข้าถึงคีย์ของ obj ที่เป็นซิมโบลอย่างเดียว
+console.log(Object.getOwnPropertySymbols(obj).map( (k)=>[k, obj[k]])); // [ [ Symbol(bar), 2 ] ]
+```
+
+```js
+let obj = { foo: 1, bar: 2 };
+for (let [k, v] of Object.entries(obj)) { // สกัดคีย์กับข้อมูลจากอ็อบเจ็กต์ obj ออกมา
+ console.log(`${k}: ${v}`);
+}
+/* แสดงผลลัพธ์
+foo: 1
+bar: 2 */
+```
+
+```js
+let obj = { foo: 1, bar: 2 };
+let map = new Map(Object.entries(obj));
+console.log(map); // Map(2) { 'foo' => 1, 'bar' => 2 }
+```
+
+## เมธอด Object.getOwnPropertyDescriptors()
+```js
+let obj = {"foo": 100, "bar": 200 };
+console.log( Object.getOwnPropertyDescriptor(obj,"foo")); // รีเทิร์น descriptor
+// { value: 100, writable: true, enumerable: true, configurable: true }
+console.log( Object.getOwnPropertyDescriptor(obj,"bar")); // รีเทิร์น descriptor
+// { value: 200, writable: true, enumerable: true, configurable: true }
+```
+
+```js
+let obj = {
+ foo: 1,
+ get bar() { return 2 },
+ [Symbol("zoo")]: 3
+};
+console.log(Object.getOwnPropertyDescriptors(obj));
+
+/* แสดงผลลัพธ์
+{
+ foo: { value: 1, writable: true, enumerable: true, configurable: true },
+ bar: {
+ get: [Function: get bar],
+ set: undefined,
+ enumerable: true,
+ configurable: true
+ },
+ [Symbol(zoo)]: { value: 3, writable: true, enumerable: true, configurable: true }
+} */
+```
+
+## เมธอด Object.fromEntries()
+
+```js
+let array = [["name", "somchai"], ["age", 65]];
+let obj = Object.fromEntries(array);
+console.log(obj); // { name: 'somchai', age: 65 }
+```
+
+```js
+let map = new Map([["name", "somchai"], ["age", 65]]); // สร้างแม็พขึ้นมาก่อน
+console.log(map); // Map(2) { 'name' => 'somchai', 'age' => 65 }
+let obj = Object.fromEntries(map)
+console.log(obj); // { name: 'somchai', age: 65 }
+```
+
+## เมธอด Object.hasOwn()
+```js
+let foo = {
+ fooProp: 100,
+};
+let bar = {
+ __proto__: foo,
+ barProp: 200,
+};
+
+console.log("fooProp" in bar); // true
+
+console.log( Object.hasOwn(foo, "fooProp") ); // true -- foo เป็นเจ้าของ "fooProp"
+console.log( Object.hasOwn(bar, "fooProp") ); // false -- bar ไม่ใช่เจ้าของ "fooProp"
+
+console.log( foo.hasOwnProperty("fooProp") ); // true -- foo เป็นเจ้าของ "fooProp"
+console.log( bar.hasOwnProperty("fooProp") ); // false -- bar ไม่ใช่เจ้าของ "fooProp"
+```
+
+## การกระจายพร็อพเพอร์ตี้ไปให้อีกอ็อบเจ็กต์
+```js
+let obj1 = {a: "foo", b: "bar"};
+let obj2 = {...obj1 }; // ใช้โอเปอเรเตอร์สเปรด ประกาศสมาชิก
+console.log(obj2) // { a: 'foo', b: 'bar' }
+// แก้ไขอ็อบเจ็กต์ obj1 ก็ไม่กระทบต่อ obj2
+obj1.a = "zoo";
+console.log(obj1); // { a: 'zoo', b: 'bar' }
+console.log(obj2); // { a: 'foo', b: 'bar' }
+```
+
+```js
+let obj1 = {a: "foo", b: "bar"};
+let obj2 = {...obj1, c: "zoo"};
+console.log(obj2) // { a: 'foo', b: 'bar', c: 'zoo' }
+```
+
+```js
+let obj1 = {a:"foo", b:"bar"};
+let obj2 = {x:"zoo", y:"car"};
+let obj3 = {...obj1, d:"car", ...obj2};
+console.log(obj3) // { a: 'foo', b: 'bar', d: 'car', x: 'zoo', y: 'car' }
+```
+
+```js
+let obj1 = {a:"foo", b:"bar"};
+let obj2 = {a:"zoo", ...obj1};
+console.log(obj2) // { a: 'foo', b: 'bar' }
+let obj3 = {...obj1, a:"zoo"};
+console.log(obj3) // { a: 'zoo', b: 'bar' }
+```
+
+```js
+console.log( {...undefined}); // {}
+console.log( {...null} ); // {}
+console.log( {...123} ); // {}
+console.log( {..."abc"} ); // { 0: 'a', 1: 'b', 2: 'c' }
+console.log( {...["foo", "bar"]}); // { 0: 'foo', 1: 'bar' }
+```
+
+## Optional Chaining
+```js
+let data = {
+ parent : {
+ child: {
+ name: {
+ firstName: "สมชาย",
+ lastName : "ใจดี"
+ }
+ }
+ }
+};
+console.log(data.parent.child.name.firstName); // "สมชาย"
+console.log(data.parent.child.name.surname); // undefined
+console.log(data.parent.child.NAME.firstName); // บรรทัด a - เกิด TypeError
+
+console.log(data.parent.child.NAME?.firstName); // undefined
+console.log(data.parent.child.name?.firstName); // "สมชาย"
+
+console.log(data.parent.child.NAME?.["firstName"]); // undefined
+console.log(data.parent.child.name?.["firstName"]); // "สมชาย"
+
+console.log(data.parent.child.name.surname?); // วาง ? ไว้ท้ายสุด เกิด SyntaxError ทำไม่ได้
+```
+
+```js
+function foo (x, y) {
+ return x*y;
+}
+let result1 = foo?.(2, 3); // - บรรทัด a
+console.log(result1); // 6
+```
+
+```js
+let bar; //undefined
+let result2 = bar?.(2, 3);
+console.log(result2); // undefined
+```
+
+```js
+let zoo = null;
+let result3 = zoo?.(2, 3);
+console.log(result3); // undefined
+```
+
+## globalThis
+```js
+function findGlobal () {
+ if (typeof global !== "undefined") {
+ return global;
+ }
+ if (typeof window !== "undefined") {
+ return window
+ };
+ if (typeof self !== "undefined") {
+ return self
+ };
+};
+console.log(findGlobal());
+```
+
+```js
+console.log(globalThis);
+```
\ No newline at end of file
diff --git a/examples_book/Chapter14.md b/examples_book/Chapter14.md
new file mode 100644
index 0000000..21b9aae
--- /dev/null
+++ b/examples_book/Chapter14.md
@@ -0,0 +1,1830 @@
+# โค้ดบทที่ 14 คลาส
+
+## คลาส
+
+```js
+class Car {
+ // สมาชิกภายในคลาส
+}
+```
+
+```js
+class Car {
+ // สมาชิกภายในคลาส
+}
+let car1 = new Car();
+let car2 = new Car();
+let car3 = new Car();
+// สร้างอ็อบเจ็กต์ได้เรื่อยๆ
+```
+
+## โอเปอเรเตอร์ instanceof
+
+```js
+class Car {
+ // สมาชิกภายในคลาส
+}
+let car1 = new Car();
+let car2 = new Car();
+console.log(car1 instanceof Car); // true
+console.log(car2 instanceof Car); // true
+console.log(car1 === car2); // false
+```
+
+## สมาชิกคลาส
+
+### คอนสตรัคเตอร์
+
+```js
+class Car {
+ constructor(param) {
+ // ซอร์สโค้ดอื่นๆ
+ }
+}
+```
+
+```js
+class Car {
+ constructor(param) {
+ console.log(param);
+ }
+}
+let carObj = new Car("red"); // "red"
+```
+
+## ข้อมูลภายในอินสแตนซ์
+
+```js
+class Car {
+ constructor(param) {
+ this.color = param;
+ }
+}
+let carObj = new Car("red");
+console.log(carObj.color); // "red" (ไม่แนะนำให้เข้าถึงโดยตรงด้วยวิธีนี้)
+
+let c1 = new Car("red");
+let c2 = new Car("black");
+let c3 = new Car("white");
+console.log(c1.color); // "red"
+console.log(c2.color); // "black"
+console.log(c3.color); // "white"
+```
+
+```js
+class Car {
+ color = "red"; // บรรทัด a -- ประกาศฟิวด์ color
+ speed = 100; // บรรทัด b -- ประกาศฟิวด์ speed
+ constructor() {
+ console.log(this.color); // "red"
+ console.log(this.speed); // 100
+ }
+}
+new Car();
+// แสดงผลลัพธ์
+// "red"
+// 100
+```
+
+```js
+class Car {
+ color; // undefined
+ var speed = 100; // ทำไม่ได้ เกิด SyntaxError
+ let weight = 50; // ทำไม่ได้ เกิด SyntaxError
+ const height = 1.5; // ทำไม่ได้ เกิด SyntaxError
+}
+```
+
+```js
+class Car {
+ intField(param) {
+ this.color = param; // บรรทัด a
+ }
+}
+let carObj = new Car();
+carObj.intField("red") // this.color ถูกสร้างขึ้นมา
+console.log(carObj.color); // "red" (ไม่แนะนำให้เข้าถึงโดยตรงด้วยวิธีนี้)
+```
+
+### ประกาศเมธอด
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+ drive() {
+ console.log("Driving speed:", this.speed);
+ }
+ stop() {
+ console.log("Stop a car");
+ }
+}
+let carObj = new Car(100);
+carObj.drive(); // "Driving speed: 100"
+carObj.stop(); // "Stop a car"
+```
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+ drive() {
+ console.log("Driving speed:", this.speed);
+ }
+ drive() { // เลือกใช้เมธอดตัวนี้
+ console.log("Stop a car");
+ }
+}
+let carObj = new Car(100);
+carObj.drive(); // "Stop a car"
+```
+
+## เงื่อนไขการประกาศคลาส
+
+* ตัวอย่างที่ 1
+
+```js
+let car = new Car(); // จะเกิด ReferenceError เพราะมองไม่เห็น Car ที่ประกาศอยู่ข้างล่าง
+class Car { // คลาสจะถูกมองเห็นตั้งแต่บรรทัดนี้เป็นต้นไป
+ // สมาชิกคลาส
+}
+```
+
+* ตัวอย่างที่ 2
+
+```js
+class Car {
+}
+let car = Car(); // จะเกิด TypeError เพราะไม่ได้ใช้ new
+```
+
+* ตัวอย่างที่ 3
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+ drive() { /*ซอร์สโค้ด*/ }
+}
+let car = new Car(100);
+for(let c in car) {
+ console.log(c);
+}
+// แสดงผลลัพธ์เป็น
+// "speed"
+```
+
+* ตัวอย่างที่ 4
+
+```js
+class Car {
+ constructor() {
+ Car = 100; // ไม่สามารถเปลี่ยนแปลง Car ได้เลย
+ }
+}
+Car = 100; // กำหนดค่าใหม่ให้กับตัวแปร Car จากข้างนอกคลาส จะสามารถทำได้
+```
+
+## เบื้องหลังของคลาส
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+ drive() {
+ console.log("Driving speed:", this.speed);
+ }
+}
+let carObj = new Car(100);
+carObj.drive(); // "Driving speed: 100"
+console.log(typeof carObj); // "object"
+console.log(carObj instanceof Car); // true
+console.log(carObj instanceof Object); // true
+console.log(carObj.drive === Car.prototype.drive); // true
+console.log(typeof Car.prototype.drive); // "function"
+// คลาส Car ก็คือฟังก์ชันคอนสตรัคเตอร์ที่ชื่อ Car
+console.log(typeof Car); // "function"
+console.log(Car.name); // "Car"
+console.log(Car === Car.prototype.constructor); // true
+console.log(Car.prototype.constructor.name); // "Car"
+```
+
+```js
+let Car = function() {
+ "use strict";
+ const Car = function(speed) {
+ if(typeof new.target === "undefined") {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ this.speed = speed;
+ };
+ Object.defineProperty(Car.prototype, "drive", {
+ value: function() {
+ if(typeof new.target !== "undefined") {
+ throw new TypeError("Method cannot be called with new.");
+ }
+ console.log("Driving speed:", this.speed);
+ }
+ ,enumerable: false
+ ,writable: true
+ ,configurable: true
+ });
+ return Car;
+}(); // เทคนิค IIFE
+let carObj = new Car(100);
+carObj.drive(); // "Driving speed: 100"
+```
+
+## เพิ่มสมาชิกเข้าไปในคลาสทีหลัง
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+}
+Car.prototype.drive = function() { // เพิ่มเมธอดเข้าไปทีหลัง
+ console.log("Driving speed:", this.speed);
+};
+let car = new Car(100);
+car.drive();
+// แสดงผลลัพธ์
+// "Driving speed: 100"
+for(let c in car) {
+ console.log(c);
+}
+// ประโยค for ...in จะแสดงผลลัพธ์ดังนี้
+// "speed"
+// "drive"
+```
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+}
+Object.defineProperty(Car.prototype, "drive", {
+ value: function() {
+ console.log("Driving speed:", this.speed);
+ },
+ enumerable: false,
+ writable: true,
+ configurable: true
+ });
+let car = new Car(100);
+car.drive();
+// แสดงผลลัพธ์
+// "Driving speed: 100"
+for(let c in car) {
+ console.log(c);
+}
+// ประโยค for ...in จะแสดงผลลัพธ์ดังนี้
+// "speed"
+```
+
+## นิพจน์คลาส
+
+```js
+let Car = class { // คลาสไร้ชื่อ
+ // สมาชิกคลาส
+};
+console.log(typeof Car); // "function"
+let carObj = new Car();
+console.log(typeof carObj); // "object"
+console.log(carObj instanceof Car); // true
+```
+
+```js
+let Car2 = class Car1 {
+ // สมาชิกคลาส
+};
+console.log(typeof Car2); // "function"
+let carObj = new Car2();
+```
+
+```js
+let carObj = new Car(); // จะเกิด TypeError ได้
+var Car = class{ }; // บรรทัด 2 -- นิพจน์คลาสจะถูกมองเห็นตั้งแต่บรรทัดนี้เป็นต้นไป
+/* จะเสมือนเขียนแบบนี้
+var Car;
+let carObj = new Car();
+Car = class{ }; */
+```
+
+```js
+function myFunction(classExpr) {
+ let c = new classExpr(); // บรรทัด a
+ c.drive(100);
+}
+myFunction( class { // บรรทัด b -- คลาสไร้ชื่อ
+ drive(speed) {
+ console.log("Driving speed:", speed);
+ }
+});
+// แสดงผลลัพธ์เป็น
+// "Driving speed: 100"
+```
+
+```js
+function myFunction(classExpr) {
+ return class {
+ drive(speed) {
+ console.log("Driving speed:", speed);
+ }
+ }
+}
+let Car = myFunction();
+let carObj = new Car();
+carObj.drive(100); // "Driving speed: 100"
+```
+
+```js
+let carObj = new class {
+ constructor (speed) {
+ this.speed = speed;
+ }
+ drive() {
+ console.log("Driving speed:", this.speed);
+ }
+}(100);
+console.log(typeof carObj); // "object"
+carObj.drive(100); // "Driving speed: 100"
+```
+
+## พร็อพเพอร์ตี้แอคเซสเซอร์
+
+```js
+class Car {
+ constructor () {
+ this.speedValue = 100;
+ }
+ get speed() {
+ return this.speedValue;
+ }
+ set speed(speedValue) {
+ this.speedValue = speedValue;
+ }
+}
+let carObj = new Car(100);
+console.log(carObj.speed); // 100
+carObj.speed = 60;
+console.log(carObj.speed); // 60
+console.log(carObj.speedValue); // 60 (เข้าถึงได้ แต่ไม่ควรเข้าถึงด้วยวิธีนี้ โดยตรง)
+
+let desc = Object.getOwnPropertyDescriptor(Car.prototype, "speed");
+console.log("get" in desc); // true
+console.log("set" in desc); // true
+console.log(desc.enumerable); // false
+```
+
+## สมาชิกที่เป็นสแตติก
+
+### ฟิวด์สแตติก
+
+```js
+class Car {
+ static speed = 100;
+ color = "red";
+}
+console.log(Car.speed); // 100
+let carObj = new Car();
+console.log(carObj.color); // "red"
+console.log(typeof carObj.speed); // undefined
+```
+
+```js
+class Car {
+ static speed = 100; // speed เป็นของคลาส
+ speed = Car.speed * 10; // บรรทัด a -- Car.speed * 10 = 1000
+ drive() {
+ console.log("Driving speed:", Car.speed); // บรรทัด b
+ }
+}
+console.log(Car.speed); // 100
+let carObj = new Car();
+console.log(carObj.speed); // 1000
+carObj.drive(); // Driving speed: 100
+```
+
+### เมธอดสแตติก
+
+```js
+class Car {
+ constructor (speed) { // ห้ามมีคำว่า static นำหน้าคอนสตัคเตอร์
+ this.speed = speed;
+ }
+ drive() {
+ console.log("Driving speed:", this.speed);
+ }
+ static stop() { // เมธอดสแตติก
+ console.log("Stop this car");
+ }
+}
+// เมธอดสแตติก
+Car.stop(); // "Stop this car"
+let carObj = new Car(100);
+carObj.drive(); // "Driving speed: 100"
+console.log(typeof carObj.stop); // undefined
+```
+
+```js
+class Car {
+ static constructor () { // จะกลายเป็นเมธอดสแตติกชื่อ constructor
+ console.log("constructor function");
+ }
+}
+Car.constructor(); // "constructor function"
+```
+
+```js
+class Car {
+ static set color(value) {
+ this.value = value; // จะเสมือนเขียนเป็น Car.value = value
+ }
+ static get color() {
+ return this.value; // จะเสมือนเขียนเป็น return Car.value;
+ }
+}
+Car.color = "red";
+console.log(Car.color); // "red"
+console.log(Car.value); // "red"
+let carObj = new Car();
+console.log(typeof carObj.color); // undefined
+```
+
+```js
+class Car {
+ constructor (speed) {
+ this.speed = speed;
+ }
+ drive() {
+ console.log("Driving speed:", this.speed);
+ }
+ static set color(value) { // เมธอด setter
+ this.value = value;
+ }
+}
+let carObj = new Car(100);
+console.log(carObj.value); // undefined
+console.log(carObj.speed); // 100
+carObj.drive(); // "Driving speed: 100"
+Car.color= "red";
+console.log(Car.value); // "red"
+console.log(Car.speed); // undefined
+```
+
+```js
+class Car {
+ static speed = 100;
+ static reduce(val) {
+ // หลีกเลี่ยงใช้ this
+ // return this.speed / val;
+ return Car.speed / val; // บรรทัด a
+ }
+ static drive() {
+ // หลีกเลี่ยงใช้ this
+ console.log("Driving speed:", Car.reduce(10) ); // บรรทัด b
+ }
+}
+Car.drive(); // "Driving speed: 10"
+```
+
+```js
+class Car {
+ static speed = 100;
+ static drive(value) {
+ console.log("Driving speed:", value);
+ }
+}
+let carObj = new Car();
+for (let prop in carObj) {
+ console.log(prop) // จะไม่เข้ามาทำงานในประโยค for
+}
+
+for (let prop in Car) {
+ console.log(prop)
+}
+// แสดงผลลัพธ์
+// "speed"
+```
+
+## การใช้วงเล็บเหลี่ยมในคลาส
+
+```js
+let name1= "speed";
+let name2 = "drive";
+let name3 = "stop";
+let name4 = Symbol("reduce");
+class Car {
+ ["constructor"] (speedValue) { // กลายเป็นเมธอดตัวหนึ่ง ไม่ใช่คอนสตรัคเตอร์
+ this.speedValue = speedValue;
+ console.log("Not a constructor: speed =", this.speedValue);
+ }
+ set [name1](speedValue) { // เมธอด setter
+ this.speedValue = speedValue;
+ }
+ get [name1]() { // เมธอด getter
+ return this. speedValue;
+ }
+ [name2]() { // เมธอดที่ไม่ใช่สแตติก
+ console.log("Driving speed:", this.speedValue);
+ }
+ static [name3]() { // เมธอดสแตติก
+ console.log("Stop this car");
+ }
+ [name4]() { // ชื่อเมธอดเป็นซิมโบล
+ console.log("Reduce speed");
+ }
+ [2+2]() { // ชื่อเมธอดเป็นนิพจน์ 2+2 = 4
+ console.log("Start this car");
+ }
+}
+let carObj = new Car(100);
+console.log(carObj.speedValue); // undefined
+carObj.constructor(100); // "Not a constructor: speed = 100"
+console.log(carObj.speedValue); // 100
+carObj.speed = 60;
+console.log(carObj.speed); // 60
+carObj.drive(); // "Driving speed: 60"
+Car.stop(); // "Stop this car"
+// หรือจะเรียกเมธอดผ่านวงเล็บเหลี่ยมก็ได้
+carObj[name4](); // "Reduce speed"
+carObj[3+1](); // "Start this car"
+```
+
+```js
+let speed= "speed";
+let reduce = Symbol("reduce");
+class Car {
+ [speed] = 100;
+ ["drive"] = "Driving this car";
+ [reduce] = 1;
+ [2+2] = 20.5;
+}
+let carObj = new Car();
+console.log( carObj[speed] ); // 100
+console.log( carObj["drive"] ); // "Driving this car"
+console.log( carObj[reduce] ); // 1
+console.log( carObj[3+1] ); // 20.5
+```
+
+## การสืบทอดคลาส
+
+```js
+class Calculation {
+ constructor (a, b) {
+ this.a = a;
+ this.b = b;
+ }
+ multiply() {
+ return this.a * this.b;
+ }
+}
+class Division extends Calculation { // บรรทัด a -- Division สืบทอดมาจาก Calculation
+ constructor (a, b) {
+ super(a, b); // บรรทัด b -- เรียกใช้คอนสตรัคเตอร์ของ Calculation
+ // สามารถกำหนดค่าให้กับ this.a และ this.b ที่อยู่ในคลาสแม่ได้โดยตรง
+ // แต่การทำเช่นนี้จะไม่ปลอดภัย
+ // this.a = a; // ไม่ควรทำ
+ // this.b = b; // ไม่ควรทำ
+ }
+ divide() {
+ return this.a / this.b;
+ }
+}
+let div = new Division(20,10);
+console.log(div.multiply()); // 200
+console.log(div.divide()); // 2
+console.log(div.a, div.b); // 20 10 (ไม่ควรเข้าถึงข้อมูลอินสแตนซ์โดยตรง ด้วยวิธีนี้)
+console.log(div instanceof Division); // true
+console.log(div instanceof Calculation); // true
+console.log(div instanceof Object); // true
+// เบื้องหลังจะมีการทำ prototype chain
+console.log(Object.getPrototypeOf(div) === Division.prototype); // true
+console.log(Object.getPrototypeOf(Division.prototype) === Calculation.prototype); // true
+```
+
+```js
+function Calculation(a, b) {
+ this.a = a;
+ this.b = b;
+}
+Calculation.prototype.multiply = function() {
+ return this.a * this.b;
+}
+function Division (a, b) {
+ Calculation.call(this, a, b); // เรียกใช้ฟังก์ชันคอนสตรัคเตอร์ Calculation
+}
+Division.prototype = Object.create(Calculation.prototype, { // prototype chain
+ constructor: {
+ value: Division,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+});
+Division.prototype.divide = function() {
+ return this.a / this.b;
+}
+let div = new Division(20,10);
+console.log(div.multiply()); // 200
+console.log(div.divide()); // 2
+console.log(div.a, div.b); // 20 10
+console.log(div instanceof Division); // true
+console.log(div instanceof Calculation); // true
+```
+
+### คอนสตรัคเตอร์ดีฟอลต์ของคลาสลูก
+
+
+```js
+class Calculation {
+ constructor (a, b) {
+ this.a = a;
+ this.b = b;
+ console.log("Calculation:", a , b);
+ }
+}
+class Division extends Calculation {
+ // ไม่มีคอนสตรัคเตอร์
+ // แต่จาวาสคริปต์ จะสร้างคอนสตรัคเตอร์ที่เป็นดีฟอลต์มาให้
+}
+let div = new Division(100 , 200); // "Calculation: 100 200"
+// จะเสมือนมีคอนสตรัคเตอร์ที่เป็นค่าดีฟอลต์มาให้ดังนี้
+/* class Division extends Calculation {
+ constructor (...args) {
+ super(...args);
+ }
+} */
+```
+
+```js
+class Calculation {
+}
+class Division extends Calculation {
+}
+```
+
+```js
+class Calculation {
+}
+class Division extends Calculation {
+ constructor() {
+ // ปราศจากการเรียกใช้ super()
+ }
+}
+new Division(); // เกิด ReferenceError
+```
+
+## การสืบทอดคลาสหลายระดับชั้น
+
+```js
+class Animal {
+ constructor(name) {
+ this.name = name;
+ console.log("Animal constructor"); // บรรทัด a
+ }
+ showName() {
+ console.log("Animal is", this.name);
+ }
+ static sleep() {
+ console.log("This animal is sleeping");
+ }
+}
+class Quadruped extends Animal {
+ constructor(name) {
+ super(name);
+ console.log("Quadruped constructor"); // บรรทัด b
+ }
+ showColor() {
+ console.log(this.name, "is red");
+ }
+}
+class Dog extends Quadruped {
+ constructor(name) {
+ super(name);
+ console.log("Dog constructor"); // บรรทัด c
+ }
+ run() {
+ console.log(this.name, "is running");
+ }
+}
+let dogObj = new Dog("Pit bull");
+// คอนสตรัคเตอร์จะทำงานก่อนรันเมธอด ด้วยการแสดงผลลัพธ์
+//"Animal constructor"
+//"Quadruped constructor"
+//"Dog constructor"
+console.log(dogObj instanceof Dog); // true
+console.log(dogObj instanceof Quadruped); // true
+console.log(dogObj instanceof Animal); // true
+console.log(dogObj instanceof Object); // true
+dogObj.showName(); // "Animal is Pit bull"
+dogObj.showColor(); // "Pit bull is red"
+dogObj.run(); // "Pit bull is running"
+Dog.sleep(); // "This animal is sleeping"
+console.log(typeof dogObj.sleep); // undefined
+```
+
+## โอเวอร์ไรด์เมธอดของคลาสแม่
+
+```js
+class Calculation {
+ constructor (a, b) {
+ this.a = a;
+ this.b = b;
+ }
+ multiply() {
+ return this.a * this.b;
+ }
+}
+class Multiplying extends Calculation {
+ constructor (a, b) {
+ super(a, b);
+ }
+ multiply() { // โอเวอร์ไรด์เมธอด multiply() ของคลาสแม่
+ return "The result is " + super.multiply();
+ }
+}
+let m = new Multiplying(20,10);
+console.log(m.multiply()); // "The result is 200"
+```
+
+```js
+class Calculation {
+ constructor (a, b) {
+ this.a = a;
+ this.b = b;
+ }
+ multiply() {
+ return this.a * this.b;
+ }
+}
+let name = "multiply";
+class Multiplying extends Calculation {
+ constructor (a, b) {
+ super(a, b);
+ }
+ [name]() {
+ return "The result is " + super.multiply();
+ // หรือจะเขียนเป็น return "The result is " + super[name]();
+ }
+}
+let m = new Multiplying(20,10);
+console.log(m[name]()); // "The result is 200"
+console.log(m.multiply()); // "The result is 200"
+```
+
+```js
+class Animal {
+ constructor (name) {
+ this.name = name; // บรรทัด a
+ }
+ set animalName(name) {
+ this.name = name;
+ }
+ get animalName() {
+ return this.name;
+ }
+}
+class Dog extends Animal {
+ constructor (name) {
+ super(name); // บรรทัด b
+ }
+ showName() {
+ console.log(this.name); // "A dog"
+ console.log(super.name); // undefined
+ // เข้าถึงพร็อพเพอร์ตี้แอคเซสเซอร์ของคลาสแม่ ผ่านทาง super
+ super.animalName="Pit bull dog";
+ console.log(super.animalName); // "Pitbull dog"
+ }
+}
+let dogObj = new Dog("A dog");
+dogObj.showName();
+/* แสดงผลลัพธ์เป็น
+"A dog"
+undefined
+"Pit bull dog" */
+```
+
+## สืบทอดคลาสแบบนิพจน์
+
+```js
+function getClass() {
+ let c = class Calculation {
+ constructor (a, b) {
+ this.a = a;
+ this.b = b;
+ }
+ multiply() {
+ return this.a * this.b;
+ } // สิ้นสุดการประกาศเมธอด multiply
+ } // สิ้นสุดการประกาศคลาส Calculation
+ return c; // รีเทิร์นคลาสออกไป
+}
+class Multiplying extends getClass() { // สืบทอดคลาสแบบนิพจน์
+ constructor (a, b) {
+ super(a, b);
+ }
+}
+let m = new Multiplying(20, 10);
+console.log(m.multiply()); // 200
+```
+
+```js
+function Calculation (a,b) {
+ this.a = a;
+ this.b = b;
+}
+Calculation.prototype.multiply = function() {
+ return this.a * this.b;
+};
+class Multiplying extends Calculation {
+ constructor (a, b) {
+ super(a, b);
+ }
+}
+let m = new Multiplying(20, 10);
+console.log(m.multiply()); // 200
+```
+
+## การสืบทอดคลาสมากกว่า 1 ตัว
+
+```js
+let MultiplyingObj = {
+ multiply() {
+ return this.a * this.b;
+ }
+};
+let DivisionObj = {
+ divide() {
+ return this.a / this.b;
+ }
+};
+function getClass (...args) {
+ let merged = function() {}; // ฟังก์ชันคอนสตรัคเตอร์
+ // เมธอดของ MultiplyingObj กับ DivisionObj จะมารวมอยู่ที่ merged.prototype
+ Object.assign(merged.prototype, ...args); // บรรทัด a
+ return merged; // รีเทิร์น merged ซึ่งทำหน้าที่เป็นฟังก์ชันคอนสตรัคเตอร์
+}
+class MyCalc extends getClass(MultiplyingObj, DivisionObj) {
+ // สืบทอดมาจาก MultiplyingObj กับ DivisionObj
+ constructor (a, b) {
+ super();
+ // ไม่สามารถเรียก super(a,b);
+ this.a = a;
+ this.b = b;
+ }
+}
+let calc = new MyCalc(20,10);
+console.log(calc.multiply()); // 200
+console.log(calc.divide()); // 2
+```
+
+## สืบทอดคลาสจากที่มีอยู่แล้วในจาวาสคริปต์
+
+```js
+class ArrayExt extends Array {
+ get(index) {
+ return this[index];
+ }
+}
+let array = new ArrayExt();
+array[0] = 1;
+array[1] = 2;
+console.log(array.get(0)); // 1
+console.log(array.get(1)); // 2
+```
+
+```js
+class ArrayExt extends Array {
+ constructor(length){
+ super(length);
+ }
+}
+let a1 = ArrayExt.of("one", "two", "three");
+console.log(a1 instanceof ArrayExt ); // true
+console.log(a1 instanceof Array ); // true
+console.log(a1.length); // 3
+let a2 = ArrayExt.from(["one", "two", "three"]);
+console.log(a2 instanceof ArrayExt ); // true
+console.log(a2 instanceof Array ); // true
+console.log(a2.length); // 3
+```
+
+## คอมโพสิชั่น
+
+```js
+class Calculation {
+ constructor (a, b) {
+ this.a = a;
+ this.b = b;
+ }
+ execute() {
+ return this.a * this.b;
+ }
+}
+class Multiplying {
+ constructor (calcObj) {
+ if(calcObj instanceof Calculation) {
+ this.calcObj = calcObj; //บรรทัด a -- อ้างถึงอ็อบเจ็กต์ที่เป็นอินสแตนซ์ของ Calculation
+ }
+ }
+ multiply() {
+ return "This value is " + this.calcObj.execute(); // บรรทัด b
+ }
+}
+let c1 = new Calculation(10, 10);
+let m1 = new Multiplying(c1);
+console.log(m1.multiply()); // "This value is 100"
+let c2 = new Calculation(20, 20);
+let m2 = new Multiplying(c2);
+console.log(m2.multiply()); // "This value is 400"
+```
+
+## new.target
+
+```js
+class Calculation {
+ constructor () {
+ console.log(new.target === Calculation); // true
+ // new.target คือคลาส Calculation
+ console.log(new.target); // "class Calculation"
+ console.log(Calculation); // "class Calculation"
+ }
+}
+new Calculation();
+// แสดงผลลัพธ์
+// true
+// "class Calculation" (แต่ละจาวาสคริปต์รันไทม์แสดงผลไม่เหมือนกัน)
+// "class Calculation" (แต่ละจาวาสคริปต์รันไทม์แสดงผลไม่เหมือนกัน)
+```
+
+```js
+class Calculation {
+ constructor () {
+ // ถ้าคลาสลูกเรียกคอนสตรัคเตอร์ของแม่ ค่าของ new.target จะมีค่าเท่ากับ undefined
+ console.log("new.target in Calculaton:", new.target === Calculation);
+ }
+}
+class Multiplying extends Calculation {
+ constructor () {
+ super();
+ console.log("new.target in Multiplying:", new.target === Multiplying);
+ }
+}
+new Multiplying();
+// แสดงผลลัพธ์
+// "new.target in Calculaton: false"
+// "new.target in Multiplying: true"
+```
+
+## สมาชิกแบบ private
+
+```js
+class Car {
+ speed = 100;
+}
+let carObj = new Car();
+carObj.speed = 200 // บรรทัด a -- ไม่ควรเข้าถึง speed โดยตรง
+carObj.speed = -10 // บรรทัด b -- ไม่ควรเข้าถึง speed โดยตรง
+```
+
+### ฟิวด์ที่เป็น private
+
+```js
+class Car {
+ #speed = 100; // เมื่ออินสแตนซ์ถูกสร้างขึึ้นมา ฟิวด์ #speed จะมีค่าเป็น 100
+ /*static {
+ console.log(#speed in new Car()); // true
+ }*/
+}
+let carObj = new Car();
+console.log(carObj.speed); // undefined
+console.log(carObj.#speed); // เกิด SyntaxError
+```
+
+```js
+class Car {
+ #speed; // ไม่จำเป็นต้องกำหนดค่าเริ่มต้นก็ได้
+ constuctor() {
+ this.#speed = 100; // กำหนดค่าให้ทีหลัง
+ }
+}
+let carObj = new Car(); // เมื่ออินสแตนซ์ถูกสร้างขึึ้นมา ฟิวด์ #myField จะมีค่าเป็น 100
+```
+
+```js
+class Car {
+ constuctor() {
+ this.speed = 100; // บรรทัด a -- ทำงานได้ปกติ
+ this.#value = 1; // บรรทัด b -- เกิด SyntaxError
+ }
+}
+```
+
+### เมธอดที่เป็น private
+
+```js
+class Car {
+ #drive() { // บรรทัด a
+ console.log("Driving this car");
+ }
+ /*static {
+ console.log( #drive in new Car()); // true
+ }*/
+}
+let carObj = new Car();
+carObj.#drive(); // เกิด SyntaxError
+```
+
+### ฟิวด์สแตติกที่เป็น private
+
+```js
+class Car {
+ static #speed = 100;
+ /*static {
+ console.log( #speed in Car ); // true
+ }*/
+}
+console.log(Car.speed); // undefined
+console.log(Car.#speed ); // SyntaxError
+```
+
+### เมธอดสแตติกที่เป็น private
+
+```js
+class Car {
+ static #drive() {
+ console.log("Driving this car");
+ }
+ /*static {
+ console.log( #drive in Car ); // true
+ }*/
+}
+Car.#drive(); // เกิด SyntaxError
+```
+
+```js
+class Car {
+ #speedValue; // ไม่จำเป็นต้องประกาศค่าเริ่มต้นก็ได้
+ get #speed() {
+ return this.#speedValue;
+ }
+ set #speed(value) {
+ this.#speedValue = value;
+ }
+}
+```
+
+```js
+class MyClass {
+ #syncMethod() { }
+ get #accessor() { }
+ set #accessor(value) { }
+ * #syncGenerator() { }
+ async #asyncMethod() { }
+ async * #asyncGenerator() { }
+}
+```
+
+```js
+class MyClass {
+ static #syncMethod() { }
+ static get #accessor() { }
+ static set #accessor(value) { }
+ static * #syncGenerator() { }
+ static async #asyncMethod() { }
+ static async * #asyncGenerator() { }
+}
+```
+
+### ตัวอย่างการเข้าถึงสมาชิกที่เป็น private
+
+* ตัวอย่าง การเข้าถึงฟิวด์ที่เป็น private ภายในอินสแตนซ์
+
+```js
+class Car {
+ #speed = 100;
+ drive() {
+ console.log("Driving speed:", this.#speed); // บรรทัด a
+ }
+}
+let objCar = new Car();
+objCar.drive(); // "Driving speed: 100"
+```
+
+* ตัวอย่าง การเข้าถึงเมธอดที่เป็น private ภายในอินสแตนซ์
+
+```js
+class Car {
+ #getSpeed() {
+ return 100;
+ }
+ drive() {
+ console.log("Driving speed:", this.#getSpeed()); // บรรทัด a
+ }
+}
+let objCar = new Car();
+objCar.drive(); // "Driving speed: 100"
+```
+
+* ตัวอย่าง การเข้าถึงฟิวด์ที่เป็น private จากคอนสตรัคเตอร์ และ getter กับ setter ภายในอินสแตนซ์
+
+```js
+class Car {
+ #speed ; // บรรทัด a
+ constructor(speed) {
+ this.#speed = speed; // บรรทัด b
+ }
+ get speed() {
+ return this.#speed; // บรรทัด c
+ }
+ set speed(speed) {
+ this.#speed = speed; // บรรทัด d
+ }
+}
+let objCar = new Car(100);
+objCar.speed = 5;
+console.log(objCar.speed); // 5
+```
+
+* ตัวอย่าง การเข้าถึงฟิวด์สแตติกที่เป็น private จากภายในบอดี้ของคลาส
+
+```js
+class Car {
+ static #speed = 100;
+ drive() {
+ console.log("Driving speed:", Car.#speed); // บรรทัด a
+ }
+}
+let objCar = new Car();
+objCar.drive(); // Driving speed: 100
+```
+
+* ตัวอย่าง การเข้าถึงเมธอดแตติกที่เป็น private จากภายในบอดี้ของคลาส
+
+```js
+class Car {
+ static #getSpeed() {
+ return 100;
+ }
+ drive() {
+ console.log("Driving speed:", Car.#getSpeed()); // บรรทัด a
+ }
+}
+let objCar = new Car();
+objCar.drive(); // "Driving speed: 100"
+```
+
+* สรุป สมาชิกใดๆ ที่จะเข้าถึงสมาชิกที่เป็น private ก็ขอให้ประกาศอยู่ภายใต้บอดี้ของคลาสเดียวกันก็สามารถเข้าถึงได้หมดเลย ดังตัวอย่าง
+
+```js
+class Car {
+ #speed = 10;
+ speedValue = this.#speed * 10; // บรรทัด a
+}
+let objCar = new Car();
+console.log(objCar.speedValue); // 100
+```
+
+```js
+class MyClass {
+ #myField;
+ constructor(value) {
+ this.#myField = value;
+ }
+ showValue(inst) {
+ console.log("Show value:", inst.#myField );
+ }
+}
+let inst1 = new MyClass(1);
+let inst2 = new MyClass(100);
+inst1.showValue(inst2); // "Show value: 100"
+```
+
+### การสืบทอดสมาชิกที่เป็น private
+
+```js
+class SuperClass {
+ #superField = 1;
+}
+class MyClass extends SuperClass {
+ showMsg() {
+ console.log("Result:", this.#superField); // บรรทัด a -- เกิด SyntaxError
+ }
+}
+```
+
+```js
+class SuperClass {
+ #superField = 1;
+ get superField() {
+ return this.#superField;
+ }
+}
+class MyClass extends SuperClass {
+ showMsg() {
+ console.log("Result:", super.superField); // บรรทัด a
+ }
+}
+let inst = new MyClass();
+inst.showMsg(); // "Result: 1"
+```
+
+### ข้อควรรู้ชื่อ private ในอินสแตนซ์
+
+```js
+class Car {
+ #speed = 100;
+ color = "red";
+ showSpeed() {
+ console.log( this.#speed );
+ }
+ showColor() {
+ console.log( this.color );
+ }
+}
+/*let carObj = new Car()
+carObj.showSpeed(); // 100
+carObj.showColor(); // "red"*/
+```
+
+```js
+let Car;
+{ // ขอบเขตของคลาส
+ const speed = Symbol();
+ Car = class {
+ __PrivateElements__ = new Map([
+ [speed, 100],
+ ]);
+ color = "red"
+ showSpeed() {
+ console.log( this.__PrivateElements__.get(speed) );
+ }
+ showColor() {
+ console.log( this.color );
+ }
+ }
+}
+```
+
+### ชื่อฟิวด์ที่เป็น private เมื่อยู่คนละคลาส จะไม่ชนกัน
+
+```js
+class ClassA {
+ #myField = 1;
+}
+class ClassB {
+ #myField = 100;
+}
+```
+
+```js
+class SuperClass {
+ #myField = 1; // บรรทัด a
+ get myField() {
+ return this.#myField;
+ }
+}
+class MyClass extends SuperClass {
+ #myField = 2; // บรรทัด b
+ showMsg() {
+ console.log("Result:", super.myField + this.#myField); // บรรทัด c
+ }
+}
+let inst = new MyClass();
+inst.showMsg(); // "Result: 3"
+```
+
+### ชื่อที่เป็น private กับ public จะไม่ชนกัน
+
+```js
+class MyClass {
+ myField;
+ #myField;
+ myMethod(){ }
+ #myMethod(){ }
+}
+```
+
+### ลำดับการสร้างฟิวด์ เมื่อมีการสืบทอด
+
+```js
+class MyClass {
+ constructor() {
+ console.log("MyClass constructor"); // บรรทัด a
+ }
+ pubField = console.log("pubField"); // บรรทัด b
+ #privateField = console.log("privateField"); // บรรทัด c
+}
+new MyClass();
+// แสดงผลลัพธ์
+// "pubField"
+// "privateField"
+// "MyClass constructor"
+```
+
+```js
+class SuperClass {
+ superField = console.log("superField"); // บรรทัด a
+ constructor() {
+ console.log("SuperClass constructor"); // บรรทัด b
+ }
+ }
+class MyClass extends SuperClass {
+ myField = console.log("myField"); // บรรทัด c
+ constructor() {
+ super();
+ console.log("MyClass constructor"); // บรรทัด d
+ }
+ }
+new MyClass();
+// แสดงผลลัพธ์
+// "superField"
+// "SuperClass constructor"
+// "myField"
+// "MyClass constructor"
+```
+
+```js
+class SuperClass {
+ #superField = console.log("#superField"); // บรรทัด a
+ constructor() {
+ console.log("SuperClass constructor"); // บรรทัด b
+ }
+ }
+class MyClass extends SuperClass {
+ #myField = console.log("#myField"); // บรรทัด c
+ constructor() {
+ super();
+ console.log("MyClass constructor"); // บรรทัด d
+ }
+ }
+new MyClass();
+// แสดงผลลัพธ์
+// "#superField"
+// "SuperClass constructor"
+// "#myField"
+// "MyClass constructor"
+```
+
+## บล็อกสแตติก
+
+```js
+class Car {
+ static { // บรรทัด a
+ console.log("Driving this car"); // บรรทัด b
+ }
+}
+// แสดงผลลัพธ์
+// "Driving this car"
+```
+
+* ตัวอย่าง การใช้สแตติกบล็อกเข้าถึงฟิวด์ของอินสแตนซ์ที่เป็น private
+
+```js
+class Car {
+ #speed;
+ static {
+ let objCar = new Car();
+ objCar.#speed = 100;
+ }
+}
+```
+
+* ตัวอย่าง การใช้สแตติกบล็อกเข้าถึงฟิวด์ของอินสแตนซ์ที่เป็น public
+
+```js
+class Car {
+ speed=1;
+ static {
+ let objCar = new Car();
+ objCar.speed = 100;
+ }
+}
+```
+
+* ตัวอย่าง การใช้สแตติกบล็อกเข้าถึงฟิวด์สแตติกของคลาสที่เป็น private
+
+```js
+class Car {
+ static #speed;
+ static {
+ Car.#speed = 100;
+ }
+}
+```
+
+* ตัวอย่าง การใช้สแตติกบล็อกเข้าถึงฟิวด์สแตติกของคลาสที่เป็น public
+
+```js
+class Car {
+ static speed;
+ static {
+ Car.speed = 100;
+ }
+}
+```
+
+```js
+class Car {
+ static speed = 100;
+ static drive() {
+ console.log("Driving this car");
+ }
+ static {
+ console.log(this.speed); // บรรทัด a
+ this.drive(); // บรรทัด b
+ }
+}
+// แสดงผลลัพธ์
+// 100
+// "Driving this car"
+```
+
+```js
+class Car {
+ static #speed = 100;
+ static #drive() {
+ console.log("Driving this car");
+ }
+ static {
+ console.log(this.#speed); // บรรทัด a
+ this.#drive() ; // บรรทัด b
+ }
+}
+// แสดงผลลัพธ์
+// 100
+// "Driving this car"
+```
+
+```js
+class Car {
+ static speed = 100;
+ static {
+ console.log(this.speed); // บรรทัด a
+ console.log(this === Car); // บรรทัด b -- true
+ }
+}
+// แสดงผลลัพธ์
+// 100
+// true
+```
+
+```js
+class Car {
+ static {
+ console.log(Car.speed); // บรรทัด a -- มองไม่เห็น จะได้เป็น undefined
+ }
+ static speed = 100; // บรรทัด b
+}
+// แสดงผลลัพธ์
+// undefined
+```
+
+```js
+class Car {
+ static {
+ console.log("static"); // บรรทัด a
+ }
+ static speed = console.log("speed"); // บรรทัด b
+ static color = console.log("color"); // บรรทัด c
+}
+// แสดงผลลัพธ์
+// "static"
+// "speed"
+// "color"
+```
+
+```js
+class MyClass {
+ static {
+ console.log("Line a"); // บรรทัด a
+ }
+ static {
+ console.log("Line b"); // บรรทัด b
+ }
+}
+// แสดงผลลัพธ์
+// "Line a"
+// "Line b"
+```
+
+```js
+class MyClass {
+ static myFiled1 = console.log("myFiled1"); // บรรทัด a
+ static {
+ console.log("Static line b"); // บรรทัด b
+ }
+ static myFiled2 = console.log("myFiled2"); // บรรทัด c
+ static {
+ console.log("Static line d"); // บรรทัด d
+ }
+}
+// แสดงผลลัพธ์
+// "myFiled1"
+// "Static line b"
+// "myFiled2"
+// "Static line d"
+```
+
+```js
+class SuberClass {
+ static superFiled = console.log("superFiled"); // บรรทัด a
+ static {
+ console.log("Static line b"); // บรรทัด b
+ }
+}
+class MyClass extends SuberClass {
+ static myFiled = console.log("myFiled"); // บรรทัด c
+ static {
+ console.log("Static line d"); // บรรทัด d
+ }
+}
+// แสดงผลลัพธ์
+// "superFiled"
+// "Static line b"
+// "myFiled"
+// "Static line d"
+```
+
+```js
+class SuperClass {
+ static #myFiled = 1;
+ static showMsg() {
+ console.log( this.#myFiled); // บรรทัด a
+ }
+}
+class MyClass extends SuperClass {
+ // สืบทอด showMsg() มาด้วย
+}
+MyClass.showMsg(); // TypeError
+```
+
+```js
+class SuperClass {
+ static #myFiled = 1;
+ static showMsg() {
+ console.log( SuperClass.#myFiled); // บรรทัด a
+ }
+}
+class MyClass extends SuperClass {
+ // สืบทอด showMsg() มาด้วย
+}
+MyClass.showMsg(); // 1
+```
+
+## เบื้องหลังสมาชิกของอินสแตนซ์
+
+```js
+class MyClass {
+ #privateField = 1
+ #privateMethod() { }
+ get #privateFieldValue() { }
+ set #privateFieldValue(field) { }
+ pubField = 2;
+ publicMethod() { }
+ get pubFieldValue() { }
+ set pubFieldValue(field) { }
+}
+let inst = new MyClass();
+console.log(Object.keys(inst)) // [ 'pubField' ]
+```
+
+```js
+class MyClass {
+ static #privateField = 2
+ static #privateMethod() { }
+ static get #privateFieldValue() { }
+ static set #privateFieldValue(field) { }
+ static pubField = 1; // มองเห็นเป็นชื่อคีย์ pubField
+ static publicMethod() { }
+ static get pubFieldValue() { }
+ static set pubFieldValue(field) { }
+}
+console.log(Object.keys(MyClass)) // [ 'pubField' ]
+```
+
+### การแชร์เมธอดระหว่างอินสแตนซ์
+
+```js
+class Car {
+ #drive() { }
+ stop() { }
+ static {
+ let car1 = new Car();
+ let car2= new Car();
+ console.log( car1.#drive === car2.#drive ); // true -- บรรทัด a
+ console.log( car1.stop === car2.stop ); // true -- บรรทัด b
+ }
+}
+// แสดงผลลัพธ์
+// true
+// true
+```
+
+```js
+class Car {
+ get #speed() { return 100; }
+ set #speed(value) { }
+ get color() { return "red"; }
+ set color(value) { }
+ static {
+ let car1 = new Car();
+ let car2= new Car();
+ console.log( car1.#speed === car2.#speed ); // true -- บรรทัด a
+ console.log( car1.color === car2.color ); // true -- บรรทัด b
+ }
+}
+// แสดงผลลัพธ์
+// true
+// true
+```
+
+```js
+class Car {
+ #drive() { }
+ static {
+ let carObj = new Car();
+ console.log( #drive in carObj ); // true -- บรรทัด a
+ console.log( #drive in Car.prototype ); // false -- บรรทัด b
+ console.log( #drive in Car ); // false
+ }
+}
+// แสดงผลลัพธ์
+// true
+// false
+// false
+```
+
+```js
+class Car {
+ get #speed() { return 100; }
+ set #speed(value) { }
+ static {
+ let carObj = new Car();
+ console.log( #speed in carObj ); // true -- บรรทัด a
+ console.log( #speed in Car.prototype ); // false -- บรรทัด b
+ console.log( #speed in Car ); // false
+ }
+}
+// แสดงผลลัพธ์
+// true
+// false
+// false
+```
+
+```js
+class Car {
+ drive() { }
+ get speed() { return 100; }
+ set speed(value) { }
+}
+let objCar = new Car();
+console.log(objCar.drive == Car.prototype.drive); // true -- บรรทัด a
+console.log(objCar.speed == Car.prototype.speed); // true -- บรรทัด b
+```
+
+## ตรวจสอบสมาชิกที่เป็น private
+
+* ตัวอย่าง ตรวจสอบฟิวด์ที่เป็น private ด้วยโอเปอเรเตอร์ in
+
+```js
+class Car {
+ #speed = 100;
+ static check(target) {
+ console.log( #speed in target ); // บรรทัด a
+ }
+}
+let objCar = new Car();
+Car.check(objCar); // true
+Car.check(Car); // false
+```
+
+* ตัวอย่าง ตรวจสอบเมธอดที่เป็น private ด้วยโอเปอเรเตอร์ in
+
+```js
+class Car {
+ #drive() {
+ console.log("Driving this car");
+ }
+ static check(target) {
+ console.log( #drive in target ); // บรรทัด a
+ }
+}
+let objCar = new Car();
+Car.check(objCar); // true
+Car.check(Car); // false
+```
+
+*ตัวอย่าง ตรวจสอบฟิวด์สแตติกที่เป็น private ด้วยโอเปอเรเตอร์ in
+
+```js
+class Car {
+ static #speed = 100;
+ static check(target) {
+ console.log( #speed in target ); // บรรทัด a
+ }
+}
+let objCar = new Car();
+Car.check(objCar); // false
+Car.check(Car); // true
+```
+
+* ตัวอย่าง ตรวจสอบเมธอดสแตติกที่เป็น private ด้วยโอเปอเรเตอร์ in
+
+```js
+class Car {
+ static #drive() {
+ console.log("Driving this car");
+ }
+ static check(target) {
+ console.log( #drive in target ); // บรรทัด a
+ }
+}
+let objCar = new Car();
+Car.check(objCar); // false
+Car.check(Car); // true
+```
+
+## แอ็บสแตรคท์คลาส
+
+```js
+class Calculation {
+ constructor() {
+ if(new.target === Calculation) {
+ throw new Error("Abstract class cannot be instantiated.")
+ }
+ }
+ execute() {
+ // ไม่มีซอร์สโค้ด ต้องให้คลาสอื่นมา extends เพื่อไปใช้งานต่อ
+ }
+}
+new Calculation(); // จะโยน error ออกมา
+
+class Multiplying extends Calculation {
+ constructor (a, b) {
+ super();
+ this.a = a;
+ this.b = b
+ }
+ execute() {
+ return this.a * this.b;
+ }
+}
+let m = new Multiplying(2, 2);
+console.log(m.execute()); // 4
+```
+
+## Polymorphism
+
+```js
+class Calculation {
+ constructor (a, b) {
+ if (new.target === Calculation) {
+ throw new Error("Abstract class cannot be instantiated.")
+ }
+ this.a = a;
+ this.b = b
+ }
+ execute() { } // เมธอดเปล่าๆ ยังไม่มีการทำงานอะไร
+}
+class Multiplying extends Calculation {
+ constructor (a, b) {
+ super(a, b);
+ }
+ execute() {
+ return this.a * this.b ;
+ }
+}
+class Division extends Calculation {
+ constructor (a, b) {
+ super(a, b);
+ }
+ execute() {
+ return this.a / this.b ;
+ }
+}
+class Subtraction extends Calculation {
+ constructor (a, b) {
+ super(a, b);
+ }
+ execute() {
+ return this.a - this.b ;
+ }
+}
+function calc(calcObj) {
+ if(calcObj instanceof Calculation) {
+ // ผลการทำงานจะขึ้นอยู่กับอ็อบเจ็กต์ที่ส่งเข้ามา ว่ามันเป็นอะไร
+ console.log(calcObj.execute());
+ }
+}
+calc(new Multiplying(20, 10) ); // 200
+calc(new Division(20, 10) ); // 2
+calc(new Subtraction(20, 10) ); // 10
+```
\ No newline at end of file
diff --git a/examples_book/Chapter15.md b/examples_book/Chapter15.md
new file mode 100644
index 0000000..b240272
--- /dev/null
+++ b/examples_book/Chapter15.md
@@ -0,0 +1,785 @@
+# โค้ดบทที่ 15 คอลเลคชั่น
+
+## อาเรย์
+
+### Array.of()
+
+```js
+let array = Array.of( 1, 2, 3 );
+console.log(array.length); // 3
+console.log(array); // [ 1, 2, 3 ]
+console.log(array[0], array[1], array[2]); // 1 2 3
+// จะเสมือนสร้างอาร์เรย์โดยใช้วงเล็บเหลี่ยม
+// let array = [1, 2, 3];
+```
+
+### Array.from()
+
+```js
+let a = [1, 2, 3];
+let array1 = Array.from(a);
+console.log(array1); // [ 1, 2, 3 ]
+let str = "456";
+let array2 = Array.from(str);
+console.log(array2); // [ '4', '5', '6' ]
+let set = new Set([7, 8, 9]);
+let array3 = Array.from(set);
+console.log(array3); // [ 7, 8, 9 ]
+```
+
+```js
+let obj = {
+ length: 4,
+ 1: "foo",
+ 2: "bar"
+};
+let array = Array.from(obj);
+console.log(obj.length); // 4
+console.log(array); // [ undefined, 'foo', 'bar', undefined ]
+```
+
+```js
+let a = Array.from( { length: 4 } ); // มีสมาชิกทั้งหมด 4 ตัว ที่มีค่าเป็น undefined
+console.log(a); // [ undefined, undefined, undefined, undefined ]
+```
+
+```js
+let b = Array( 4 );
+console.log(b); // [ <4 empty items> ]
+let c = Array.apply( null, { length: 4 } );
+console.log(c); // [ undefined, undefined, undefined, undefined ]
+```
+
+```js
+let obj = {
+ length: 4,
+ 1: "foo",
+ 2: "bar"
+};
+let toUpper = function (value,index) { // ฟังก์ชันคอลแบ็ค
+ if (typeof value == "string") {
+ return value.toUpperCase(); // รีเทิร์นสตริงตัวพิมพ์ใหญ่
+ } else {
+ return "index_" + index; // รีเทิร์นข้อความที่ขึ้นต้นด้วยคำว่า "index_" แล้วตามด้วยอินเด็กซ์
+ }
+};
+let array = Array.from( obj, toUpper );
+console.log(array);
+// จะแปลงจาก [ undefined, 'foo', 'bar', undefined ]
+// ให้กลายมาเป็น [ 'index_0', 'FOO', 'BAR', 'index_3' ]
+```
+
+```js
+let obj = {
+ length: 4,
+ 1: "foo",
+ 2: "bar"
+};
+let array = Array.from( obj, function (value,index) {
+ // console.log(this === obj); // true
+ return this[index];
+},obj); // อากิวเมนต์ตัวที่สาม
+console.log(array); // [ undefined, 'foo', 'bar', undefined ]
+```
+
+### copyWithin()
+
+```js
+let a1 = [0, 1, 2, 3, 4, 5];
+a1.copyWithin( 3, 0 );
+console.log(a1); // [ 0, 1, 2, 0, 1, 2 ]
+let a2 = [0, 1, 2, 3, 4, 5];
+a2.copyWithin( 3, 0, 2 );
+console.log(a2); // [ 0, 1, 2, 0, 1, 5 ]
+```
+
+```js
+let a3 = [0, 1, 2, 3, 4, 5];
+a3.copyWithin( 0, -2 );
+console.log(a3) // [ 4, 5, 2, 3, 4, 5 ]
+let a4 = [0, 1, 2, 3, 4, 5];
+a4.copyWithin( 0, -3, -1);
+console.log(a4); // [ 3, 4, 2, 3, 4, 5 ]
+```
+
+### fill()
+
+```js
+let array = Array.of("a", "b", "c", "d");
+console.log(array); // [ 'a', 'b', 'c', 'd' ]
+array.fill( 1 );
+console.log(array); // [ 1, 1, 1, 1 ]
+```
+
+```js
+let array = [ null, null, null, null ,null].fill( 10, 1 );
+console.log(array); // [ null, 10, 10, 10, 10 ]
+```
+
+```js
+let array = [ null, null, null, null ,null].fill( 10, 1, 4 );
+console.log(array); // [ null, 10, 10, 10, null ]
+```
+
+### find()
+
+```js
+let a = ["red", "green", "blue", "yellow"];
+function search(value, index, array) { // ฟังก์ชันคอลแบ็ค
+ //console.log(array); // [ 'red', 'green', 'blue', 'yellow' ]
+ return value == "blue";
+}
+let result = a.find( search );
+console.log(result); // 'blue'
+```
+
+```js
+let a = ["red", "green", "blue", "yellow"];
+let result = a.find( function (value, index, array) {
+ //console.log(array); // [ 'red', 'green', 'blue', 'yellow' ]
+ //console.log(this === a); // true
+ return this[index] == "blue";
+}, a); // อากิวเมนต์ตัวที่สอง
+console.log(result); // 'blue'
+```
+
+### findIndex()
+
+```js
+let a = ["red", "green", "blue", "yellow"];
+function search (value ,index, array) { // ฟังก์ชันคอลแบ็ค
+ // console.log(array); // [ 'red', 'green', 'blue', 'yellow' ]
+ return value == "blue";
+};
+let result = a.findIndex( search );
+console.log(result); // 2
+```
+
+```js
+let a = ["red", "green", "blue", "yellow"];
+let result = a.findIndex( function (value, index, array){
+ // console.log(array); // [ 'red', 'green', 'blue', 'yellow' ]
+ // console.log(this === a); // true
+ return this[index] == "blue";
+}, a); // อากิวเมนต์ตัวที่สอง
+console.log(result); // 2
+```
+
+### includes()
+
+```js
+let array = ["A", "B", "C"]; // ประกาศอาร์เรย์
+console.log(array.includes("A")); // true
+console.log(array.includes("Z")); // false
+```
+
+```js
+let array = ["A", "B", "C"]; // ประกาศอาร์เรย์
+// เริ่มค้นหา "B" จากอินเด็กซ์คือ 2 ซึ่งจะพบว่าหาไม่เจอ
+console.log(array.includes("B", 2)); // false
+// แต่ถ้าเปลี่ยนมาเริ่มค้นหาจากอินเด็กซ์เป็น 1 ก็จะหา "B" เจอ
+console.log(array.includes("B", 1)); // true
+```
+
+```js
+let array = [0, NaN, 1];
+console.log(array.indexOf(NaN)); // -1 เพราะไม่เจอสมาชิกที่ต้องการ
+console.log(array.includes(NaN)); // true
+```
+
+หมายเหตุ -0 จะเว้นวรรคแล้วตามด้วยเครื่องหมาย , (เหตุผลเพราะต้องการ fixbug ในหน้าเพจนี้ ไม่เกี่ยวกับหนังสือ)
+```js
+let array = [-0 , NaN, 1];
+console.log(array.indexOf(+0)); // 0 เพราะเจอค่า -0 อยู่ในอาร์เรย์ที่ตำแหน่งอินเด็กซ์ 0
+console.log(array.includes(+0)); // true
+```
+
+### flat()
+
+หมายเหตุ โค้ดต่อไปนี้จะเป็นการประกาศตัวแปร arr1 ขึ้นมา จึงต้องก็อปปี้ไปรันในโค้ดถัดๆ ไป ภายในในหัวข้อ flat()ด้วย มิฉะนั้นจะหาตัวแปร arr1 ไม่เจอ
+```js
+let arr1 = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]];
+```
+
+```js
+let arr2 = arr1.flat(); // arr2 มีสมาชิกซ้อนกัน 3 ระดับ
+console.log(arr2); // [ 1, 2, 3, 4, 5, 6, [ 7, 8, 9, [ 10, 11, 12 ] ] ]
+let arr3 = arr2.flat(); // arr2 มีสมาชิกซ้อนกัน 2 ระดับ
+console.log(arr3); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, [ 10, 11, 12 ] ]
+```
+
+```js
+let arr4 = arr1.flat().flat().flat(); // จับยืดออก 3 ครั้ง
+console.log(arr4);
+/* แสดงผลลัพธ์
+[
+ 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10,
+ 11, 12
+] */
+```
+
+```js
+let arr5 = arr1.flat(3); // จับยืดออก 3 ครั้ง
+console.log(arr5);
+/* แสดงผลลัพธ์
+[
+ 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10,
+ 11, 12
+] */
+```
+
+```js
+let arr6 = arr1.flat(Infinity); // คลี่ออกมาหมด
+console.log(arr6);
+/* แสดงผลลัพธ์
+[
+ 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10,
+ 11, 12
+] */
+```
+
+### flatMap()
+
+```js
+let arr = [1, 2, 3, 4, 5];
+let newArr1 = arr.map( function(x) {
+ return [x, x * 2];
+});
+console.log(newArr1); // [ [ 1, 2 ], [ 2, 4 ], [ 3, 6 ], [ 4, 8 ], [ 5, 10 ] ]
+```
+
+```js
+let arr = [1, 2, 3, 4, 5];
+let newArr2 = arr.flatMap( function(x) {
+ return [x, x * 2];
+});
+console.log(newArr2);
+/* แสดงผลลัพธ์
+[
+ 1, 2, 2, 4, 3,
+ 6, 4, 8, 5, 10
+] */
+```
+
+### เสริมเพิ่มเติม
+
+```js
+let array = [1, 2, 3, 4];
+array.forEach( (value, index, arrayObj) => console.log(`a[${index}] = ${value}`) );
+/*แสดงผลลัพธ์
+"a[0] = 1"
+"a[1] = 2"
+"a[2] = 3"
+"a[3] = 4" */
+```
+
+```js
+let array = [1, 2, 3, 4];
+array.forEach( value => console.log(value)); // ส่ง value เป็นค่าอากิวเมนต์ตัวแรก
+/*แสดงผลลัพธ์
+1
+2
+3
+4 */
+```
+
+```js
+let array = [1, 2, 3, 4, 5];
+let result = array.every( value => value > 0 ); // สมาชิกของอาร์เรย์ต้องมากกว่า 0
+console.log(result) // true
+```
+
+```js
+let array = [1, 2, 3, 4, 5];
+let result = array.some( (value) => value == 3 ); // รีเทิร์น boolean
+console.log(result) // true
+result = array.find( (value) => value == 3 ); // รีเทิร์นสมาชิก
+console.log(result) // 3
+result = array.findIndex( (value) => value == 3 ); // รีเทิร์นอินเด็กซ์
+console.log(result) // 2
+```
+
+```js
+let array = [1, 2, 3, 4, 5];
+let result = array.filter( value => value > 2 ); // เลือกเฉพาะสมาชิกที่มีค่ามากกว่า 2
+console.log(result) // [ 3, 4, 5 ]
+```
+
+```js
+let array = [1, 2, 3, 4, 5];
+let result = array.reduce( (acc, value) => acc + value ); // บวกรวมสมาชิกทุกตัว
+console.log(result) // 15
+```
+
+```js
+let arr = [1, 2, 3, 4, 5];
+let newArr1 = arr.map( value => 2 * value ); // แปลงสมาขิกทุกตัวด้วยการคูณสอง
+console.log(newArr1); // [ 2, 4, 6, 8, 10 ]
+```
+
+```js
+let arr = [1, 2, 3, 4, 5];
+let result = arr.flatMap(value => [value, value * 2]);
+console.log(result);
+/* แสดงผลลัพธ์
+[
+ 1, 2, 2, 4, 3,
+ 6, 4, 8, 5, 10
+] */
+```
+
+```js
+let arr = [1, 2, 3, 4, 5];
+let result = Array.from( arr, value => 2 * value ); // แปลงสมาขิกทุกตัวด้วยการคูณสอง
+console.log(result); // [ 2, 4, 6, 8, 10 ]
+```
+
+## เซท
+
+```js
+let set = new Set();
+console.log(set.size); // 0
+```
+
+```js
+let set = new Set();
+set.add( 1 );
+set.add("2");
+set.add({id : 1});
+console.log(set); // Set(3) { 1, '2', { id: 1 } }
+```
+
+```js
+let set = new Set();
+set.add( 1 );
+set.add("1");
+set.add( true );
+set.add( true );
+set.add( null );
+set.add( null );
+set.add( undefined );
+set.add( undefined );
+set.add({}); // บรรทัด a
+set.add({}) // บรรทัด b
+console.log(set); // Set(7) { 1, '1', true, null, undefined, {}, {} }
+console.log(set.size); // 7
+```
+
+```js
+let set = new Set();
+set.add(1).add(2).add(3); // เรียกเมธอด add() ต่อเนื่องกันได้
+console.log(set); // Set(3) { 1, 2, 3 }
+```
+
+### คอนสตรัคเตอร์ของเซท
+
+```js
+let set1 = new Set( ["a", "b", "c"] );
+console.log(set1); // Set(3) { 'a', 'b', 'c' }
+let set2 = new Set( "def" );
+console.log(set2); // Set(3) { 'd', 'e', 'f' }
+```
+
+```js
+let set1 = new Set( ["a", "b", "c"] );
+let set2 = new Set( set1); // สร้าง set2 จาก set1 ที่มีอยู่ก่อนแล้ว
+console.log(set2); // Set(3) { 'a', 'b', 'c' }
+```
+
+### วิธีลบสมาชิกของเซท
+
+```js
+let set = new Set(["a", "b", "c"]);
+console.log(set); // Set(3) { 'a', 'b', 'c' }
+console.log(set.delete("a")); // true
+console.log(set); // Set(2) { 'b', 'c' }
+set.clear();
+console.log(set.size); // 0
+```
+
+### เมธอด has()
+
+```js
+let set = new Set();
+let b = {b: 2};
+set.add(b);
+set.add(0);
+console.log(set.has(b)); // true
+console.log(set.has(0)); // true
+console.log(set.has(-0)); // true
+console.log(Object.is(0,-0)); // false
+```
+
+### เมธอด forEach()
+
+```js
+function log(value1, value2, setObj) {
+ // console.log(setObj); // Set { 'a', 'b', 'c' }
+ // console.log(this === set); // true
+ console.log(`[${value1}] = ${value2}`);
+}
+let set = new Set( ["a", "b", "c"] );
+set.forEach( log, set); // ระบุค่าอากิวเมนต์ตัวที่สองเป็น set
+/*แสดงผลลัพธ์เป็น
+"[a] = a"
+"[b] = b"
+"[c] = c" */
+```
+
+```js
+let set = new Set( ["a", "b", "c"] );
+set.forEach( value => console.log(value) ); // ระบุค่าอากิวเมนต์เป็นฟังก์ชันลูกศร
+/*แสดงผลลัพธ์เป็น
+a
+b
+c */
+```
+
+### ข้อควรระวังเมื่อใช้อ็อบเจ็กต์ในเซท
+
+```js
+let set = new Set(["a", true, 1]);
+console.log(set.has("a")); // true
+console.log(set.has(true)); // true
+console.log(set.has(1)); // true
+set.delete("a");
+set.delete(true);
+set.delete(1);
+console.log(set.size); // 0
+```
+
+```js
+let set = new Set();
+set.add({a: 1}); // -- บรรทัด a
+console.log(set.delete({a:1})); // false -- บรรทัด b
+let b = {b: 2};
+set.add(b) // -- บรรทัด c
+console.log(set.delete(b)); // true -- บรรทัด d
+let c = {c:3};
+set.add(c);
+console.log(set.has({c:3})); // false -- บรรทัด e
+console.log(set.has(c)); // true -- บรรทัด f
+let d = [ ];
+set.add(d);
+console.log(set.has([ ])); // false -- บรรทัด g
+console.log(set.has(d)); // true -- บรรทัด h
+```
+
+# WeakSet
+
+```js
+let a = { x: 1}, b = { y: 2};
+a = null; // อ็อบเจ็กต์ {x: 1} จะรอให้ GC มาเรียกคืนหน่วยความจำ
+b = null; // อ็อบเจ็กต์ {y: 2} จะรอให้ GC มาเรียกคืนหน่วยความจำ
+```
+
+```js
+let set = new Set();
+let a = { x: 1 }, b = { y: 2 };
+set.add(a).add(b);
+a = null; // อ็อบเจ็กต์ { x: 1 } ยังไม่ถูก GC มาเรียกคืนหน่วยความจำ
+b = null; // อ็อบเจ็กต์ { y: 2 } ยังไม่ถูก GC มาเรียกคืนหน่วยความจำ
+console.log(set); // Set(2) { { x: 1 }, { y: 2 } }
+```
+
+```js
+let wset = new WeakSet();
+let a = { x: 1 }, b = { y: 2 };
+wset.add( a );
+wset.add( b );
+console.log(wset.has(a)); // true
+console.log(wset.has(b)); // true
+a = null; // อ็อบเจ็กต์ { x: 1 } จะรอให้ GC มาเรียกคืนหน่วยความจำ
+b = null; // อ็อบเจ็กต์ { y: 2 } จะรอให้ GC มาเรียกคืนหน่วยความจำ
+console.log(wset.has(a)); // false
+console.log(wset.has(b)); // false
+```
+
+## แม็พ
+
+```js
+let map = new Map();
+console.log(map.size) // 0
+```
+
+```js
+let map = new Map();
+map.set("1", "Hello");
+map.set("1", "Hi" ); // เลือกใช้สมาชิกตัวนี้
+map.set( {id:2}, "World"); // บรรทัด a
+map.set( {id:2}, "World"); // บรรทัด b
+map.set( null, "You");
+map.set( null, "We"); // เลือกใช้สมาชิกตัวนี้
+map.set( undefined, "Good");
+map.set( undefined, "Bye"); // เลือกใช้สมาชิกตัวนี้
+console.log(map);
+/*แสดงผลลัพธ์เป็น
+Map(5) { '1' => 'Hi', { id: 2 } => 'World', { id: 2 } => 'World', null => 'We', undefined => 'Bye' }
+*/
+```
+
+```js
+let map = new Map();
+map.set(1, "a").set(2, "b").set(3, "c");
+console.log(map); // Map(3) { 1 => 'a', 2 => 'b', 3 => 'c' }
+```
+
+### คอนสตรัคเตอร์ของแม็พ
+
+```js
+let map = new Map( [ [1, "a"] , [2, "b"] ]);
+console.log(map); // Map(2) { 1 => 'a', 2 => 'b' }
+```
+
+```js
+let map1 = new Map();
+map1.set( 1, "a");
+map1.set( 2, "b");
+let map2 = new Map(map1);
+console.log(map2); // Map(2) { 1 => 'a', 2 => 'b' }
+```
+
+### วิธีลบสมาชิกของแม็พ
+
+```js
+let map = new Map();
+map.set( 1, "a");
+map.set( 2, "b");
+map.set( 3, "c");
+console.log(map); // Map(3) { 1 => 'a', 2 => 'b', 3 => 'c' }
+console.log(map.delete(1)); // true
+console.log(map); // Map(2) { 2 => 'b', 3 => 'c' }
+map.clear();
+console.log(map.size); // 0
+```
+
+### เมธอด get() และ has()
+
+```js
+let map = new Map();
+map.set( 1, "a");
+map.set( 2, "b");
+console.log(map.get( 1 )); // "a"
+console.log(map.get( 2 )); // "b"
+```
+
+```js
+let map = new Map();
+map.set( 0, "a" );
+map.set( 1, "b" );
+console.log(map.has(0)); // true
+console.log(map.has(-0)); // true
+console.log(map.has(1)); // true
+```
+
+### เมธอด forEach()
+
+```js
+function log(value, key, mapObj) {
+ // console.log(mapObj); // Map(2) { 1 => 'a', 2 => 'b' }
+ // console.log(this === map); // true
+ console.log(`[${key}] = ${value}`);
+}
+let map = new Map( [ [1, "a"] , [2, "b"] ]);
+map.forEach( log, map); //ระบุค่าอากิวเมนต์ตัวที่สองเป็น map
+/*แสดงผลลัพธ์เป็น
+"[1] = a"
+"[2] = b" */
+```
+
+```js
+let map = new Map( [ [1, "a"] , [2, "b"] ]);
+map.forEach( value => console.log(value) ); // ระบุค่าอากิวเมนต์เป็นฟังก์ชันลูกศร
+/*แสดงผลลัพธ์เป็น
+a
+b */
+```
+
+### ข้อควรระวังเมื่อใช้อ็อบเจ็กต์ในแม็พ
+
+```js
+let map = new Map();
+let obj = { a:1 }; // --บรรทัด a
+map.set( obj, "HI");
+console.log(map.delete({a:1})); // false --บรรทัด b
+console.log(map.has({a:1})); // false --บรรทัด c
+map.set([ ],"Bye"); // --บรรทัด d
+console.log(map.has([ ])); // false --บรรทัด f
+```
+
+### การสร้างแม็พด้วยปีกกา
+
+```js
+let map = { }; // จำลองการสร้างแม็พ
+let a = { x: 1 }, b = { y: 2 };
+map[a] = "foo"; // กำหนดให้ a เป็นค่าคีย์
+map[b] = "bar"; // กำหนดให้ b เป็นค่าคีย์
+console.log(map[a]); // "bar"
+console.log(map[b]); // "bar"
+```
+
+## WeakMap
+
+```js
+let wmap = new WeakMap();
+let a = { x: 1 }, b = { y: 2};
+wmap.set( a, "foo" );
+wmap.set( b, "bar" );
+console.log(wmap.get(a)); // "foo"
+console.log(wmap.get(b)); // "bar"
+a = null; // { x: 1 } จะรอให้ GC มาเรียกคืนหน่วยความจำ
+b = null; // { y: 1 } จะรอให้ GC มาเรียกคืนหน่วยความจำ
+console.log(wmap.get(a)); // undefined
+console.log(wmap.get(b)); // undefined
+```
+
+```js
+let wmap = new WeakMap();
+let a = { x: 1 }, b = { y: 2};
+wmap.set(a,b);
+b=null
+console.log(wmap.get(a)); // { y: 2 }
+```
+
+## อาร์เรย์ระดับบิต
+
+```js
+let buffer = new ArrayBuffer(32); // ระบุความยาว 32 ไบต์ (256 บิต)
+console.log(buffer.byteLength); // 32
+```
+
+```js
+let buffer = new ArrayBuffer( 32 ); // ระบุความยาว 32 ไบต์ (256 บิต)
+console.log(buffer.byteLength); // 32
+let uint16 = new Uint16Array( buffer );
+console.log(uint16.length); // สมาชิก 16 ตัว
+```
+
+```js
+let buffer = new ArrayBuffer( 2 ); // 2 ไบต์ (16 บิต)
+let uint16 = new Uint16Array( buffer );
+console.log(uint16.length); // 1
+uint16[0] = 0b0001110000001111; // 7183 (เลขฐานสิบ)
+console.log(uint16[0] == 7183); // true
+```
+
+```js
+let buffer = new ArrayBuffer( 2 ); // 2 ไบต์ (16 บิต)
+let uint16 = new Uint16Array(buffer); // มีสมาชิกตัวเดียวขนาด 16 บิต
+let uint8 = new Uint8Array(buffer); // มีสมาชิกสองตัว ตัวละ 8 บิต
+uint16[0] = 0x105b; // 4187 (เลขฐานสิบ)
+console.log(uint8[0] == 0x5b); // true
+console.log(uint8[1] == 0x10); // true
+[uint8[1], uint8[0] ] = [uint8[0], uint8[1]] // สลับข้อมูล (ดีสตรัคเตอร์ริ่ง)
+console.log(uint8[0] == 0x10); // true
+console.log(uint8[1] == 0x5b); // true
+console.log(uint16[0]); // 23312
+```
+
+### อาร์เรย์ระดับบิตอื่น ๆ
+
+```js
+let buffer = new ArrayBuffer(2); // 2 ไบต์ (16 บิต)
+let a = new Int16Array(buffer); // มองเห็น 16 บิตของบัฟเฟอร์
+let b = new Int8Array(buffer, 0, 1); // มองเห็น 8 บิตล่างของบัฟเฟอร์
+let c = new Int8Array(buffer, 1, 1); // มองเห็น 8 บิตบนของบัฟเฟอร์
+let d = new Int8Array(buffer,1); // เข้าถึงบัฟเฟอร์ตั้งแต่ offset มีค่าเป็น 1 เป็นต้นไป
+a[0] = 0x105b; // 4187 (เลขฐานสิบ)
+console.log(b[0] == 0x5b); // true
+console.log(c[0] == 0x10); // true
+console.log(d[0] == 0x10); // true
+```
+
+```js
+let a = new Float32Array(2);
+console.log(a.length); // 2
+console.log(a[0], a[1]); // 0 0
+let b = new Float64Array(a);
+console.log(b.length); // 2
+console.log(b[0], b[1]); // 0 0
+let c = new Int32Array([100, 200]);
+console.log(c[0], c[1]); // 100 200
+let likeArray = {
+ length: 2,
+ 0: 300,
+ 1: 400
+}
+let d = new Uint32Array(likeArray);
+console.log(d[0], d[1]); // 300 400
+```
+
+### เมธอดของอาร์เรย์ระดับบิต
+
+```js
+let int32 = new Int32Array( 3 );
+int32 [0] = 1;
+int32 [1] = 2;
+int32 [2] = 3;
+let result = int32.map( function(i) {
+ return i*i;
+} );
+console.log(result); // Int32Array(3) [ 1, 4, 9 ]
+let join = int32.join( "," );
+console.log(join); // "1,2,3"
+```
+
+```js
+var array = [ 10, 1, 5 ];
+array.sort();
+console.log(array); // [ 1, 10, 5 ]
+let uint8 = new Uint8Array([1,10, 5]);
+uint8.sort();
+console.log(uint8); // Uint8Array(3) [ 1, 5, 10 ]
+```
+
+```js
+let uint8 = new Uint8Array( 2 );
+uint8[0] = 20;
+uint8[1] = 40;
+let result = uint8.map( function(i) {
+ return i * i;
+} );
+console.log(result[0]); // 144 (จริง ๆ ควรได้ค่า 400)
+console.log(result[1]); // 64 (จริง ๆ ควรได้ค่า 1600)
+```
+
+```js
+let uint8 = new Uint8Array( 2 );
+uint8[0] = 20;
+uint8[1] = 40;
+let result1 = Uint8Array.from(uint8, function(i) {
+ return i * i;
+} );
+console.log(result1); // Uint8Array(2) [ 144, 64 ]
+let result2 = Array.from(uint8, function(i) {
+ return i * i;
+} );
+console.log(result2); // [ 400, 1600 ]
+```
+
+### includes()
+
+```js
+let uint8 = new Uint8Array([1, 2, 3, 4, 5]);
+console.log(uint8.includes(1)); // true
+console.log(uint8.includes(5)); // true
+console.log(uint8.includes(10)); // false
+```
+
+## เมธอด at()
+
+```js
+let array = ["a", "b", "c", "d", "e"];
+console.log(array.at(3)); // "d"
+console.log(array.at(-3)); // "c"
+```
+
+```js
+let str = "abcde";
+console.log(str.at(3)); // "d"
+console.log(str.at(-3)); // "c"
+```
+
diff --git a/examples_book/Chapter16.md b/examples_book/Chapter16.md
new file mode 100644
index 0000000..dba7b88
--- /dev/null
+++ b/examples_book/Chapter16.md
@@ -0,0 +1,832 @@
+# โค้ดบทที่ 16 อิเทอเรเตอร์ และเจนเนอเรเตอร์
+
+## อินเทอเรเตอร์
+
+### ตัวอย่างการสร้างอิเทอเรเตอร์
+
+```js
+function createIterator(array) {
+ let iterator = {
+ i : 0 // ทุกครั้งที่เรียกใช้ next() ค่าของ i จะบวกเพิ่มเป็นหนึ่งทุกครั้ง
+ ,next : function() {
+ // เมื่อเข้าถึงสมาชิกในอาร์เรย์ครบทุกตัว done จะมีค่าเป็น true
+ let done = (this.i >= array.length);
+ // เข้าถึงสมาชิกในอาร์เรย์
+ let value = !done ? array[this.i++] : undefined;
+ return { value, done };
+ } // สิ้นสุดการประกาศฟังก์ขั่น
+ };
+ return iterator;
+}
+let iterator = createIterator([1, 5, 10]);
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 5, done: false }
+console.log(iterator.next()); // { value: 10, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+## อิเทอเรเตอร์ที่มีอยู่แล้วในภาษา
+
+```js
+let array = [1, 5];
+let iterator = array[Symbol.iterator]();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 5, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+```js
+let say = "hi";
+let iterator = say[Symbol.iterator]();
+console.log(iterator.next()); // { value: 'h', done: false }
+console.log(iterator.next()); // { value: 'i', done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+```js
+console.log( typeof String.prototype[Symbol.iterator] ); // "function"
+console.log( typeof Array.prototype[Symbol.iterator] ); // "function"
+console.log( typeof Set.prototype[Symbol.iterator] ); // "function"
+console.log( typeof Map.prototype[Symbol.iterator] ); // "function"
+console.log( typeof Uint8Array.prototype[Symbol.iterator] ); // "function"
+console.log( typeof WeakSet.prototype[Symbol.iterator] ); // "undefined"
+console.log( typeof WeakMap.prototype[Symbol.iterator] ); // "undefined"
+```
+
+### อ็อบเจ็กต์ที่วนซ้ำได้
+
+```js
+for(let i of [1, 5, 10]) {
+ console.log(i)
+}
+/* แสดงผลลัพธ์
+1
+5
+10 */
+/* อาจเหมือนเขียนประโยคนี้
+let iterator = [1, 5, 10][Symbol.iterator]();
+let result;
+while( (result=iterator.next()) && result.done == false) {
+ let i = result.value;
+ console.log(i);
+}*/
+```
+
+### สตริงในประโยค for
+
+```js
+let str = "ab𠮷";
+console.log(str.length); // 4
+for (let i=0; i < str.length; i++) {
+ console.log(str[i]);
+}
+/* แสดงผลลัพธ์ของประโยค for
+"a"
+"b"
+(blank)
+(blank) */
+```
+
+```js
+let str = "ab𠮷";
+for (let i of str) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+"a"
+"b"
+"𠮷" */
+```
+
+### เมธอด values(), keys และ entries()
+
+```js
+let array = [5, 10];
+let set= new Set(["red", "green"]);
+let map = new Map();
+map.set("firstname", "Somchai");
+map.set("lastname", "Jaidee");
+for (let value of array.values()) {
+ console.log(value);
+}
+for (let value of set.values ()) {
+ console.log(value);
+}
+for (let value of map.values ()) {
+ console.log(value);
+}
+/* จะแสดงผลลัพธ์ดังนี้
+เมื่อใช้ array.values() จะแสดงผลลัพธ์เป็น
+5
+10
+เมื่อใช้ set.values() จะแสดงผลลัพธ์เป็น
+"red"
+"green"
+เมื่อใช้ map.values() จะแสดงผลลัพธ์เป็น
+"Somchai"
+"Jaidee" */
+```
+
+```js
+let array = [5, 10];
+let set= new Set(["red", "green"]);
+let map = new Map();
+map.set("firstname", "Somchai");
+map.set("lastname", "Jaidee");
+for (let key of array.keys()) {
+ console.log(key);
+}
+for (let key of set.keys ()) {
+ console.log(key);
+}
+for (let key of map.keys ()) {
+ console.log(key);
+}
+/* จะแสดงผลลัพธ์ดังนี้
+เมื่อใช้ array.keys() จะแสดงผลลัพธ์เป็น
+0
+1
+เมื่อใช้ set.keys() จะแสดงผลลัพธ์เป็น
+"red"
+"green"
+เมื่อใช้ map.keys() จะแสดงผลลัพธ์เป็น
+"firstname"
+"lastname" */
+```
+
+```js
+let array = [5, 10];
+let set= new Set(["red", "green"]);
+let map = new Map();
+map.set("firstname", "Somchai");
+map.set("lastname", "Jaidee");
+for (let entry of array.entries()) {
+ console.log(entry);
+}
+for (let entry of set.entries()) {
+ console.log(entry);
+}
+for (let entry of map.entries()) {
+ console.log(entry);
+}
+/* จะแสดงผลลัพธ์ดังนี้
+เมื่อใช้ array.entries() จะแสดงผลลัพธ์เป็น
+[ 0, 5 ]
+[ 1, 10 ]
+เมื่อใช้ set.entries() จะแสดงผลลัพธ์เป็น
+[ 'red', 'red' ]
+[ 'green', 'green' ]
+เมื่อใช้ map.entries() จะแสดงผลลัพธ์เป็น
+[ 'firstname', 'Somchai' ]
+[ 'lastname', 'Jaidee' ] */
+```
+
+```js
+let array = [5, 10];
+let set= new Set(["red", "green"]);
+let map = new Map();
+map.set("firstname", "Somchai");
+map.set("lastname", "Jaidee");
+for (let value of array) { // จะเหมือนกับการใช้ array.values()
+ console.log(value);
+}
+for (let value of set) { // จะเหมือนกับการใช้ set.values()
+ console.log(value);
+}
+for (let entry of map) { // จะเหมือนกับการใช้ map.entries()
+ console.log(entry);
+}
+/* จะแสดงผลลัพธ์ดังนี้
+5
+10
+"red"
+"green"
+[ 'firstname', 'Somchai' ]
+[ 'lastname', 'Jaidee' ] */
+```
+
+### โอเปอเรเตอร์สเปรด
+
+* ตัวอย่างที่ 1 จะแสดงการใช้งานโอเปอเรเตอร์สเปรดกับสตริง เพื่อนำไปกำหนดค่าให้เป็นสมาชิกของอาร์เรย์
+
+```js
+let array = [..."abc"]; // จะเหมือนเขียนเป็น let array = ["a", "b", "c"];
+console.log(array[0], array[1], array[2]); // "a b c"
+```
+
+* ตัวอย่างที่ 2 เมื่อใช้โอเปอเรเตอร์สเปรดกับเซท มันจะไปเรียกเมธอด @@iterator ของเซท ให้สร้างอิเทอเรเตอร์ขึ้นมา เพื่อใช้เข้าถึงและแตกสมาชิกของเซทออกมา
+
+```js
+let set = new Set(["a", "b", "c"]) ;
+let array = [...set];
+console.log(array[0], array[1], array[2]); // "a b c"
+```
+
+```js
+let set = new Set(["a", "b", "b", "c", "c",]); // Set(3) { 'a', 'b', 'c' }
+let keys = [ ...set.keys() ],
+ values = [ ...set.values() ],
+ entries = [ ...set.entries() ];
+console.log(keys); // [ 'a', 'b', 'c' ]
+console.log(values); // [ 'a', 'b', 'c' ]
+console.log(entries[0][0]); // "a"
+console.log(entries[0][1]); // "a"
+console.log(entries[1][0]); // "b"
+console.log(entries[1][1]); // "b"
+console.log(entries[2][0]); // "c"
+console.log(entries[2][1]); // "c"
+```
+
+* ตัวอย่างที่ 3 จะแสดงการใช้งานโอเปอเรเตอร์สเปรดกับแม็พ เพื่อนำไปกำหนดค่าให้เป็นสมาชิกของอาร์เรย์
+
+```js
+let map = new Map([ [1,"a"] , [2, "b"] ]);
+let keys = [ ...map.keys() ],
+ values = [ ...map.values() ],
+ entries = [ ...map.entries() ];
+console.log(keys); // [1, 2]
+console.log(values); // [ 'a', 'b' ]
+console.log(entries[0][0]); // 1
+console.log(entries[0][1]); // "a"
+console.log(entries[1][0]); // 2
+console.log(entries[1][1]); // "b"
+console.log( [...map]); // [ [ 1, 'a' ], [ 2, 'b' ] ]
+```
+
+* ตัวอย่างที่ 4 จะแสดงการใช้โอเปอเรเตอร์สเปรด กับอาร์เรย์
+
+```js
+let array = [ ];
+array.length = 3;
+array[1] = "a";
+console.log(...array.keys()); // 0 1 2
+console.log(...array.values()); // undefined a undefined
+console.log(...array.entries()); // [ 0, undefined ] [ 1, 'a' ] [ 2, undefined ]
+console.log(...array); // undefined a undefined
+```
+
+* ตัวอย่างที่ 5 จะแสดงการใช้โอเปอเรเตอร์สเปรด กับอาร์เรย์ระดับบิต
+```js
+let uint8 = new Uint8Array( 2 );
+uint8[0] = 10 ;
+uint8[1] = 20 ;
+console.log(...uint8.keys()); // 0 1
+console.log(...uint8.values()); // 10 20
+console.log(...uint8.entries()); // [ 0, 10 ] [ 1, 20 ]
+console.log(...uint8); // 10 20
+```
+
+* ตัวอย่างที่ 6 จะแสดงการใช้งานโอเปอรเตอร์สเปรดกับคอลเลคชั่น เพื่อแตกค่าออกมาก่อน แล้วจึงส่งมันให้เป็นค่าอากิวเมนต์แก่ฟังก์ชัน
+```js
+let set = new Set([1, 2, 3]);
+let array = [10, 20, 30];
+function plus(a, b, c) {
+ console.log(a + b + c);
+}
+plus(...set); // 6
+plus(...array); // 60
+```
+
+### ยูเนียน อินเตอร์เซคชัน ผลต่างของเซต
+
+* ยูเนียน
+```js
+let a = new Set([1, 2, 3, 4, 5]); // Set(5) { 1, 2, 3, 4, 5 }
+let b = new Set([3, 4, 5, 6, 7]); // Set(5) { 3, 4, 5, 6, 7 }
+let union = new Set([...a, ...b]);
+console.log(...union); // 1 2 3 4 5 6 7
+```
+
+* อินเตอร์เซคชั่น
+```js
+let a = new Set([1, 2, 3, 4, 5]); // Set(5) { 1, 2, 3, 4, 5 }
+let b = new Set([3, 4, 5, 6, 7]); // Set(5) { 3, 4, 5, 6, 7 }
+let temp = [...a]; // แตกสมาชิกของเซทออกมา ให้กลายมาเป็นอาร์เรย์ชั่วคราว
+let intersect = new Set(temp.filter( item => b.has(item) ) );
+// หรือจะเขียนสั้น ๆ ได้เป็น
+// let intersect = new Set([...a].filter(item => b.has(item) ) );
+console.log(...intersect); // 3 4 5
+```
+
+* ผลต่างของเซต
+```js
+let a = new Set([1, 2, 3, 4, 5]); // Set(5) { 1, 2, 3, 4, 5 }
+let b = new Set([3, 4, 5, 6, 7]); // Set(5) { 3, 4, 5, 6, 7 }
+let temp = [...a]; // แตกสมาชิกของเซทออกมา ให้กลายมาเป็นอาร์เรย์ชั่วคราว
+let diff = new Set(temp.filter(item => !b.has(item) ) );
+// หรือจะเขียนสั้น ๆ ได้เป็น
+// let diff = new Set([...a].filter(item => !b.has(item) ) );
+console.log(...diff); // 1 2
+```
+
+### ดีสตรัคเตอร์ริ่ง
+
+* ตัวอย่างที่ 1 ลองพิจารณาการใช้งานเซท กับวิธีดีสตรัคเตอร์ริ่ง
+
+```js
+let [a, b, c] = new Set(["a", "b", "c"]);
+console.log(a, b, c) // "a b c"
+```
+
+* ตัวอย่างที่ 2 ลองพิจารณาการใช้งานแม็พ กับวิธีดีสตรัคเตอร์ริ่ง
+
+```js
+let map = new Map();
+map.set("firstname", "Somchai");
+map.set("lastname", "Jaidee");
+//let map = new Map( [ ["firstname","Somchai"] , ["lastname", "Jaidee"] ] );
+let [a, b] = map;
+console.log(a); // [ 'firstname', 'Somchai' ]
+console.log(b); // [ 'lastname', 'Jaidee' ]
+let [ [key1, value1] , [key2, value2]] = map;
+console.log(key1,key2); // "firstname lastname"
+console.log(value1,value2); // "Somchai Jaidee"
+```
+
+* ตัวอย่างที่ 3 ลองพิจารณาการใช้งานอาร์เรย์ระดับบิต ด้วยการใช้โอเปอเรเตอร์สเปรด ร่วมกับวิธีดีสตรัคเตอร์ริ่ง
+
+```js
+let uint8 = new Uint8Array( 2 );
+[...uint8] = [10, 20];
+console.log(uint8[0], uint8[1]); // 10 20
+```
+
+* ตัวอย่างที่ 4 ลองพิจารณาการนำข้อมูลจากคอลเลคชั่นมากำหนดค่าให้กับอาร์เรย์ ด้วยการใช้โอเปอเรเตอร์สเปรด ร่วมกับวิธีดีสตรัคเตอร์ริ่ง
+```js
+let a1 = [], a2 = [];
+let set = new Set([10, 20]);
+[...a1] = [...set];
+console.log(a1[0], a1[1]); // 10 20
+let map = new Map( [ ["firstname","Somchai"] , ["lastname", "Jaidee"] ] );
+[...a2] = [...map];
+console.log(a2[0]); // [ 'firstname', 'Somchai' ]
+console.log(a2[1]); // [ 'lastname', 'Jaidee' ]
+console.log(a2[0][0], a2[0][1]); // "firstname Somchai"
+console.log(a2[1][0], a2[1][1]); // "lastname Jaidee"
+```
+
+* ตัวอย่างที่ 5 ลองพิจารณาการใช้งานเมธอด entries() ของคอลเลคชั่น ในประโยค for …of
+
+```js
+let array = [5, 10];
+let set= new Set(["red", "green"]);
+let map = new Map( [["firstname","Somchai"] , ["lastname", "Jaidee"] ]);
+let uint8 = new Uint8Array( 2 );
+[...uint8] = [10, 20];
+for(let [key,value] of array.entries()) {
+ console.log(key, value);
+}
+for(let [key,value] of set.entries()) {
+ console.log(key, value);
+}
+for(let [key,value] of map.entries()) {
+ console.log(key, value);
+}
+for(let [key,value] of uint8.entries()) {
+ console.log(key, value);
+}
+
+/*
+เมื่อใช้ array.entries() จะแสดงผลลัพธ์เป็น
+0 5
+1 10
+เมื่อใช้ set.entries() จะแสดงผลลัพธ์เป็น
+"red red"
+"green green"
+เมื่อใช้ map.entries() จะแสดงผลลัพธ์เป็น
+"firstname Somchai"
+"lastname Jaidee"
+เมื่อใช้ uint8.entries() จะแสดงผลลัพธ์เป็น
+0 10
+1 20
+*/
+```
+
+* ตัวอย่างที่ 6 ลองพิจารณาการใช้วิธีดีสตรัคเตอร์ริ่ง มารับค่าจากการรีเทิร์นของฟังก์ชัน
+```js
+function myFunction() {
+ return new Set(["red", "green"]);
+}
+let [a, b] = myFunction();
+console.log(a, b); // "red green"
+```
+
+### พารามิเตอร์แบบดีสตรัคเตอร์
+
+```js
+function createGrade(firstName, lastName,[gender="Male",
+ age=18 ,subject="Math", gpa=0]) {
+ console.log(firstName, lastName, gender, age, subject, gpa);
+}
+let set = new Set(["Female", "21", "Science", "3.44"]);
+let map = new Map([["k1","Male"], ["k2","19"], ["k3","Math"], ["k4","3.20"]]);
+createGrade("Somchai", "Jaidee", set); // "Somchai Jaidee Female 21 Science 3.44"
+createGrade("Mana", "Dekdee", map.values());// "Mana Dekdee Male 19 Math 3.20"
+```
+
+### อ็อบเจ็กต์ที่วนซ้ำได้แบบอื่นๆ
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### วิธีสร้างอ็อบเจ็กต์ที่วนซ้ำได้
+
+
+```js
+let obj = { array: [1, 5, 10] };
+obj[Symbol.iterator] = function () { // บรรทัดที่ 2
+ return this.array[Symbol.iterator](); // บรรทัดที่ 3
+ // return this.array.values(); // หรือจะเขียนแบบนี้ก็สามารถทำได้
+};
+for(let i of obj) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+1
+5
+10 */
+```
+
+```js
+let obj = {
+ array: [1, 5, 10],
+ [Symbol.iterator] () {
+ return this.array[Symbol.iterator]();
+ // return this.array.values();
+ }
+};
+```
+
+```js
+class Iterable {
+ constructor(array) {
+ this.array = array;
+ }
+ [Symbol.iterator] () {
+ return this.array[Symbol.iterator]();
+ // return this.array.values();
+ }
+}
+let obj = new Iterable([1, 5, 10]);
+for (let i of obj) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์เป็น
+1
+5
+10 */
+```
+
+```js
+String.prototype[Symbol.iterator] = function() {
+ let item = this;
+ let iterator = {
+ i : 0 // ทุกครั้งที่เรียกใช้ next() ค่าของ i จะบวกเพิ่มเป็นหนึ่งทุกครั้ง
+ ,next() {
+ // เมื่อเข้าถึงสมาชิกในอาร์เรย์ครบทุกตัว done จะมีค่าเป็น true
+ let done = (this.i >= item.length);
+ // เปลี่ยนเป็นตัวอักษรตัวใหญ่
+ let value = !done ? item[this.i++].toUpperCase() : undefined;
+ return { value, done };
+ } // สิ้นสุดการประกาศเมธอด next()
+ };
+ return iterator;
+}
+for(let i of "abc") {
+ console.log(i);
+}
+/* แสดงผลลัพธ์เป็น
+"A"
+"B"
+"C" */
+```
+
+## เจนเนอเรเตอร์
+
+```js
+function * genIterator() {
+ // ซอร์สโค้ด
+ yield 1;
+ // ซอร์สโค้ด
+ yield 5;
+ // ซอร์สโค้ด
+ yield 10;
+ // ซอร์สโค้ด
+}
+let iterator = genIterator();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 5, done: false }
+console.log(iterator.next()); // { value: 10, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+```js
+function * genIterator(array) {
+ for (let i=0; i < array.length; i++) {
+ // ซอร์สโค้ดก่อนหน้า
+ yield array[i]; // เมื่อประโยคนี้ทำงานเสร็จ ก็จะหยุดรอการเรียก iterator.next() ครั้งต่อไป
+ // ซอร์สโค้ดตามหลัง
+ }
+}
+let iterator = genIterator ([1, 5, 10]);
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 5, done: false }
+console.log(iterator.next()); // { value: 10, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+```js
+function * genIterator(item) {
+ for (let i=0; i < item.length; i++) {
+ yield item[i];
+ }
+}
+let iterator = genIterator([1, 5, 10]);
+for (let i of iterator) { // อิเทอเรเตอร์ของเจนเนอเรเตอร์สามารถอยู่ในประโยค for …of ได้
+ console.log(i);
+}
+/* แสดงผลลัพธ์เป็น
+1
+5
+10 */
+```
+
+
+### ประโยค return ในเจนเนอเรเตอร์
+
+```js
+function * genIterator () {
+ yield 1;
+ yield 5;
+ return 45; // จบการทำงานแค่บรรทัดนี้
+ yield 10; // เส้นทางการทำงานจะไม่มาถึงบรรทัดนี้
+}
+let iterator = genIterator ();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 5, done: false }
+console.log(iterator.next()); // { value: 45, done: true }
+console.log(iterator.next()); // { value: undefined, done: true }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+```js
+function * genIterator () {
+ yield 1;
+ yield 5;
+ return; // จบการทำงานแค่บรรทัดนี้
+ yield 10;
+}
+let iterator = genIterator ();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 5, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+### ประโยคคำสั่ง yield *นิพจน์
+
+```js
+function * g() {
+ yield 2;
+ yield 3;
+}
+function * genIterator() {
+ yield 1; // บรรทัด a
+ yield* g(); // บรรทัด b
+ yield* "45"; // บรรทัด c
+ yield* Array.from(arguments); // บรรทัด d
+ let item = new Set([8, 9]);
+ yield* item.values(); // บรรทัด e
+}
+let iterator = genIterator(6, 7); // บรรทัด f
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 2, done: false }
+console.log(iterator.next()); // { value: 3, done: false }
+console.log(iterator.next()); // { value: '4', done: false }
+console.log(iterator.next()); // { value: '5', done: false }
+console.log(iterator.next()); // { value: 6, done: false }
+console.log(iterator.next()); // { value: 7, done: false }
+console.log(iterator.next()); // { value: 8, done: false }
+console.log(iterator.next()); // { value: 9, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+```js
+function * f() {
+ yield 1; // บรรทัด a
+ return 2; // บรรทัด b
+}
+function * g(count) {
+ for(let i=0; i<2 ; i++) {
+ yield count + i; // บรรทัด c
+ }
+}
+function * genIterator() {
+ let result = yield *f(); // บรรทัด d
+ yield result + 10; // บรรทัด e
+ yield *g(result); // บรรทัด f
+}
+let iterator = genIterator();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next()); // { value: 12, done: false }
+console.log(iterator.next()); // { value: 2, done: false }
+console.log(iterator.next()); // { value: 3, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+### ส่งค่าอากิวเมนต์ไปให้เมธอด next()
+
+```js
+function * genIterator() {
+ let a = yield 1;
+ let b = yield a + 3;
+ yield b + 7;
+}
+let iterator = genIterator();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next(2)); // { value: 5, done: false }
+console.log(iterator.next(3)); // { value: 10, done: false }
+console.log(iterator.next(4)); // { value: undefined, done: true }
+```
+
+### เมธอด throw()
+
+```js
+function * genIterator() {
+ let a = yield 1;
+ let b = yield a + 3;
+ yield b + 7;
+}
+let iterator = genIterator ();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next(2)); // { value: 5, done: false }
+console.log(iterator.throw(new Error(''))); // error
+```
+
+```js
+function * genIterator() {
+ let a = yield 1;
+ let b;
+ try {
+ b = yield a + 3;
+ } catch(ex) {
+ b = 3;
+ }
+ yield b + 7;
+}
+let iterator = genIterator();
+console.log(iterator.next()); // { value: 1, done: false }
+console.log(iterator.next(2)); // { value: 5, done: false }
+console.log(iterator.throw(new Error(''))); // { value: 10, done: false }
+console.log(iterator.next()); // { value: undefined, done: true }
+```
+
+### นิพจน์เจนเนอเรเตอร์
+
+```js
+let genIterator = function *(item) { // นิพจน์เจนเนอเรเตอร์
+ for (let i=0; i < item.length; i++) {
+ yield item[i];
+ }
+}
+for (let i of genIterator([1, 5, 10]) ) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์เป็น
+1
+5
+10 */
+```
+### ประกาศเจนเนอเรเตอร์ในอ็อบเจ็กต์
+
+```js
+let obj = { };
+obj.genIterator = function *(item) { // ประกาศเจนเนอเรเตอร์
+ for (let i=0; i < item.length; i++) {
+ yield item[i];
+ }
+};
+for(let i of obj.genIterator( [1, 5, 10] ) ) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+1
+5
+10 */
+```
+
+```js
+let obj = {
+ genIterator: function *(item) { // ประกาศเจนเนอเรเตอร์
+ for (let i=0; i < item.length; i++) {
+ yield item[i];
+ }
+ }
+};
+```
+
+```js
+let obj = {
+ *genIterator (item) { // ประกาศเจนเนอเรเตอร์แบบย่อ
+ for (let i=0; i < item.length; i++) {
+ yield item[i];
+ }
+ }
+};
+```
+
+### ประกาศเจนเนอเรเตอร์ในคลาส
+
+```js
+class IteratorClass {
+ *genIterator (item) { // ประกาศเจนเนอเรเตอร์
+ for (let i=0; i < item.length; i++) {
+ yield item[i];
+ }
+ }
+}
+let myClass = new IteratorClass();
+for(let i of myClass.genIterator([1, 5, 10]) ) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+1
+5
+10 */
+```
+
+### สร้างอ็อบเจ็กต์ที่วนซ้ำได้ด้วยเจนเนอเรเตอร์
+
+```js
+let obj = { item: [1, 5, 10] };
+obj[Symbol.iterator] = function *() { // ประกาศเจนเนอเรเตอร์
+ yield *this.item;
+};
+for(let i of obj) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์เป็น
+1
+5
+10 */
+```
+
+```js
+let obj = {
+ item: [1, 5, 10],
+ [Symbol.iterator] : function *() { // ประกาศเจนเนอเรเตอร์
+ yield *this.item;
+ }
+ };
+```
+
+```js
+let obj = {
+ item: [1, 5, 10],
+ *[Symbol.iterator]() { // ประกาศเจนเนอเรเตอร์แบบย่อ
+ yield *this.item;
+ }
+ };
+```
+
+```js
+class GenIterable {
+ constructor(item) {
+ this.item = item;
+ }
+ *[Symbol.iterator]() { // ประกาศเจนเนอเรเตอร์
+ yield *this.item;
+ }
+}
+let obj = new GenIterable([1, 5, 10]);
+for(let i of obj) {
+ console.log(i);
+}
+/* แสดงผลลัพธ์
+1
+5
+10 */
+```
diff --git a/examples_book/Chapter17.md b/examples_book/Chapter17.md
new file mode 100644
index 0000000..1587972
--- /dev/null
+++ b/examples_book/Chapter17.md
@@ -0,0 +1,365 @@
+# โค้ดบทที่ 17 เมต้าโปรแกรมมิ่ง
+
+## เมต้าโปรแกรมมิ่ง
+
+### ฟังก์ชัน eval()
+
+```js
+var function1 = "function myFunction (a, b) { console.log(a*b); }";
+var function2 = "function myFunction (a, b) { console.log(a/b); }";
+var randomNumber = Math.random() >= 0.5; // true หรือ false
+var code = randomNumber ? function1 : function2;
+eval(code);
+myFunction(10, 5); // 50 หรือ 2 -- บรรทัด a
+/* จะเสมือนเขียน
+function myFunction(a, b) {
+ console.log(a*b);
+}*/
+/* หรืออาจะเขียนเป็น
+function myFunction(a, b) {
+ console.log(a/b);
+}*/
+```
+
+### Function()
+
+```js
+var body1 = "console.log(a*b)";
+var body2 = "console.log(a/b)";
+var randomNumber = Math.random() >= 0.5; // true หรือ false
+var myBody = randomNumber ? body1 : body2;
+var myFunction = Function("a","b", myBody);
+myFunction(10, 5); // 50 หรือ 2
+/* จะเสมือนเขียน
+function myFunction(a, b) {
+ console.log(a*b);
+}*/
+/* หรืออาจะเขียนเป็น
+function myFunction(a, b) {
+ console.log(a/b);
+}*/
+```
+
+## Reflect
+
+```js
+let obj = { };
+obj.a = 100;
+console.log(obj.a); // 100
+```
+
+```js
+let obj = { };
+Reflect.set(obj, "a", 100); // เหมือนเขียนประโยค obj.a = 100;
+console.log( Reflect.get(obj, "a") ); // 100 -- เหมือนเขียนประโยค console.log(obj.a);
+```
+
+## พร็อกซี่
+
+```js
+let obj = { a: 100 };
+let handler = { }; // บรรทัด 2
+let proxyObj = new Proxy( obj, handler); // บรรทัด 3
+console.log(proxyObj.a); // 100 (บรรทัด 4)
+console.log(obj.a); // 100 (บรรทัด 5)
+```
+
+```js
+// ห่ออาร์เรย์
+let proxyArray = new Proxy( [1, 2, 3], {}); // บรรทัด a
+console.log(proxyArray[1]); // 2
+console.log(...proxyArray); // 1 2 3
+// ห่อฟังก์ชันลูกศร
+let proxyFunc = new Proxy( ()=> console.log("myFunction") , {} ); // บรรทัด b
+proxyFunc(); // "myFunction"
+// ห่อพร็อกซี่
+let proxyObj1 = new Proxy(proxyArray, {}); // บรรทัด c
+console.log(...proxyObj1); // 1 2 3
+// ห่อพร็อกซี่
+let proxyObj2 = new Proxy(proxyFunc, {}); // บรรทัด d
+proxyObj2(); // "myFunction"
+```
+
+### Trap
+
+```js
+let obj = { a: 100 };
+let trapLogic = {
+ get(targetObj,key, proxy) {
+ console.log(`key: ${key}`);
+ // targetObj ในตัวอย่างนี้คือ obj
+ // proxy ในตัวอย่างนี้คือ proxyObj
+ return Reflect.get(targetObj, key);
+ // เนื่องจาก Reflect บางเว็บบราวเซอร์อาจไม่ทำงาน จึงอาจเขียนแบบนี้แทนก็ได้
+ // return targetObj[key];
+ }
+ };
+let proxyObj = new Proxy( obj, trapLogic);
+console.log(proxyObj.a); // บรรทัด a
+// แสดงผลลัพธ์เป็น
+// "key: a"
+// 100
+console.log(obj.a); // 100
+```
+
+### ตัวอย่างการใช้งานพร็อกซี่
+
+* ตัวอย่างที่ 1 จะแสดงการดัดแปลงพฤติกรรมของอ็อบเจ็กต์ ด้วยการใช้พร็อกซี่
+
+```js
+let obj = { foo: 1 };
+let trapLogic = {
+ set(targetObj, key, value, proxy) { // กำหนดค่าให้กับพร็อพเพอร์ตี้
+ if(Reflect.has( targetObj, key )) {
+ return Reflect.set( targetObj, key, value );
+ } else {
+ throw `Can't write property: ${key}`;
+ }
+ }
+ ,get(targetObj, key, proxy) { // อ่านค่าพร็อพเพอร์ตี้
+ if(Reflect.has( targetObj, key )) {
+ return Reflect.get(targetObj, key);
+ } else {
+ throw `Can't read property: ${key}`;
+ }
+ }
+ ,deleteProperty(targetObj, key){ // ลบพร็อพเพอร์ตี้
+ if(Reflect.has( targetObj, key )) {
+ return Reflect.deleteProperty(targetObj, key);
+ } else {
+ throw `Can't delete property: ${key}`;
+ }
+ }
+}
+let proxyObj = new Proxy(obj, trapLogic);
+proxyObj.foo = 100;
+console.log(proxyObj.foo); // 100
+// console.log(delete proxyObj.foo); // true
+proxyObj.a = 1; // error: Can't write property: a
+console.log(proxyObj.b); // error: Can't read property: b
+delete proxyObj.c ; // error: Can't delete property: c
+```
+
+* ตัวอย่างที่ 2 จะแสดงการตรวจสอบค่าอากิวเมนต์ที่ส่งไปให้พารามิเตอร์ของฟังก์ชัน รวมทั้งค่ารีเทิร์นจากฟังก์ชันด้วย
+
+```js
+let validation = { // handler
+ apply(targetObj, thisObj, argumentList) { // ดักจับตอนฟังก์ชันเป้าหมายถูกเรียกใช้งาน
+ if( argumentList.length == 0 ) { // ไม่มีค่าอากิวเมนต์ส่งมาให้ฟังก์ชัน
+ throw new Error("Must send arguments to the function");
+ }
+ argumentList.forEach( function(value, index, thisObj) {
+ if(typeof value != "number") {
+ // ตรวจสอบค่าอากิวเมนต์ที่ส่งให้ฟังก์ชัน มันเป็นตัวเลขหรือไม่ ?
+ throw new Error("All arguments must be numbers");
+ } // สิ้นสุด if
+ }); // สิ้นสุด argumentList.forEach()
+ // เรียกใช้งานฟังก์ชันเป้าหมาย
+ let result = Reflect.apply(targetObj, thisObj, argumentList);
+ // ตรวจสอบค่าที่รีเทิร์นจากฟังก์ชัน มันอยู่ในช่วง safe integer หรือไม่ ?
+ if( Number.isSafeInteger(result) == false) {
+ throw new Error("The result is not safe integer");
+ };
+ return result;
+ } // สิ้นสุด apply
+} // สิ้นสุดการประกาศอ็อบเจ็กต์ validation
+
+function sum(param1, param2) { // หาผลบวก
+ return param1 + param2;
+}
+function multiply(param1, param2) { // หาผลคูณ
+ return param1 * param2;
+}
+
+let proxySum = new Proxy(sum, validation);
+let proxyMultiply = new Proxy(multiply, validation);
+// เรียกฟังก์ชัน โดยส่งค่าอากิวเมนต์ไปให้ ที่เป็นตัวเลข
+// แล้วรีเทิร์นค่าไม่เกิน "safe integer" ก็จะทำงานได้ตามปกติ
+console.log(proxySum(2, 3 )); // 5 = 2 + 3
+console.log(proxyMultiply(2, 3)); // 6 = 2 * 3
+
+// ไม่มีค่าอากิวเมนต์ส่งไปให้ฟังก์ชัน ก็จะเกิด error
+proxySum(); // Error: Must send arguments to the function
+proxyMultiply(); // Error: Must send arguments to the function
+
+// เมื่อส่งค่าอากิวเมนต์ที่ไม่ใช่ตัวเลข ก็จะเกิด error
+proxySum(2, "3"); // Error: All arguments must be numbers
+proxyMultiply(2, "3"); // Error: All arguments must be numbers
+
+// ค่าที่รีเทิร์นออกจากฟังก์ชัน ถ้าเกินช่วง safe integer ก็จะเกิด error
+let maxNum = Number.MAX_SAFE_INTEGER + 1;
+proxySum(maxNum, maxNum); // Error: The result is not safe integer
+proxyMultiply(maxNum, maxNum); // Error: The result is not safe integer
+```
+
+* ตัวอย่างที่ 3 จะแสดงกลไกการป้องกันเวลากำหนดโปรโตไทป์ให้กับอ็อบเจ็กต์
+
+```js
+let people = { };
+
+let preventObj = { // handler
+ // ดักจับตอนกำหนดโปรโตไทป์ให้กับอ็อบเจ็กต์เป้าหมาย
+ setPrototypeOf(targetObj, prototype) {
+ if(prototype !== people) { // ตรวจสอบว่าได้กำหนดโปรโตไทป์เป็น people หรือไม่
+ throw new Error("Prototype must be people object only");
+ }
+ console.log("Set the people prototype");
+ return Reflect.setPrototypeOf(targetObj, prototype);
+ } // สิ้นสุด setPrototypeOf
+}// สิ้นสุดประกาศอ็อบเจ้กต์
+
+let man = { age: 17 };
+let woman = { age: 20 };
+let proxyMan = new Proxy(man, preventObj);
+let proxyWoman = new Proxy(woman, preventObj);
+
+// กำหนดโปรโตไทป์เป็น people ก็จะทำงานได้ตามปกติ
+proxyMan.__proto__ = people; // "Set the people prototype"
+proxyWoman.__proto__ = people; // "Set the people prototype"
+console.log( man.__proto__ === people ); // true
+console.log( woman.__proto__ === people ); // true
+
+// เมื่อกำหนดโปรโตไทป์ที่ไม่ใช่ people ก็จะเกิด error
+let car = { speed: 100 }; // กำหนดให้เป็นโปรโตไทป์ของ man กับ woman
+proxyMan.__proto__ = car; // Error: Prototype must be people object only
+proxyWoman.__proto__ = car; // Error: Prototype must be people object only
+```
+
+* ตัวอย่างที่ 4 จะแสดงกลไกป้องกันการกำหนดสมาชิกคนละชนิดในอาร์เรย์
+```js
+let checkType = {
+ set(targetObj, key, value, proxy) {
+ if( targetObj.length == 0) { // ถ้าเป็นอาร์เรย์ว่าง
+ return Reflect.set( targetObj, key, value );
+ }
+ let val0 = Reflect.get(targetObj, 0); // เข้าถึงสมาชิกตัวแรกของอาร์เรย์ (อินเด็กซ์ 0)
+ if( typeof val0 == typeof value ) { // ข้อมูลสมาชิกที่กำหนดเข้ามาเป็นชนิดเดียวกัน
+ return Reflect.set( targetObj, key, value );
+ } else { // ถ้าเป็นคนข้อมูลคนละชนิดกัน ก็จะเกิด error
+ throw new Error(`Can't add this type: ${typeof value}`);
+ }
+ } // สิ้นสุดการประกาศ set
+}
+
+let myArray = [ 0, 1, 2, 3, 4];
+let proxyArray = new Proxy(myArray, checkType);
+
+// เพิ่มสมาชิกตัวที่ 5 (มีชนิดข้อมูลเป็นตัวเลข)
+proxyArray[5] = 5;
+console.log(proxyArray); // [ 0, 1, 2, 3, 4, 5 ]
+console.log(myArray); // [ 0, 1, 2, 3, 4, 5 ]
+
+// เพิ่มสมาชิกตัวที่ 6 แต่เป็นสตริง จะเกิด error ขึ้นได้
+proxyArray[6] = "6"; // Error: Can't add this type: string
+```
+
+* ตัวอย่างที่ 5 จะแสดงวิธีที่ทำให้อ็อบเจ๊กที่เคยสร้างแล้วจะถูก cached เก็บไว้ จะได้ไม่ต้องสร้างซ้ำ ๆ กันหลายรอบ
+```js
+class Image{
+ constructor(imageName){
+ this.imageName = imageName;
+ // สมมติว่าไปโหลดไปมาจากฐานข้อมูล
+ // ซึ่งอาจเสียเวลานานด้วย
+ // loadImageFromDB(imageName);
+ }
+}
+
+let createImage = { // handler
+ imageMap: new Map(), // เอาไว้เก็บอ็อบเจ็กต์ (cached)
+ construct(targetObj, thisArugment, newTarget) { // ดักจับเมื่อสร้างอ็อบเจ็กต์เป้าหมาย
+ imageName = thisArugment[0];
+ let map = this.imageMap;
+ if( map.has(imageName)) {
+ console.log("Clone an Object from cached");
+ // โคลนนิ่งอ็อบเจ๊กที่เก็บไว้ใน imageMap มาใส่อ็อบเจ็กต์เปล่า แล้วรีเทิร์นออกไป
+ return Object.assign({},map.get(imageName));
+ }
+ // ถ้าไม่มีเก็บไว้ในแม็พ
+ console.log("Create new Object");
+ let newObj = Reflect.construct(targetObj, thisArugment, newTarget);
+ map.set(imageName, newObj); // เก็บไว้ในแม็พ
+ return newObj
+ } // สิ้นสุด construct
+} // สิ้นสุดประกาศอ็อบเจ็กต์
+
+let proxyImage = new Proxy(Image, createImage);
+
+// เมื่อสร้างอ็อบเจ็กต์ด้วยการเรียกใช้ new
+let catImage1 = new proxyImage("cat"); // Create new Object
+
+// เมื่อระบุค่าอากิวเมนต์ "cat" ซ้ำอีกครั้ง ก็จะเป็นการโคลนิ่งอ็อบเจ็กต์ที่มีอยู่แล้ว
+let catImage2 = new proxyImage("cat"); // Clone an Object from cached
+console.log( catImage1 === catImage2) // false
+```
+
+### ข้อควรระวังเมื่อใช้ trap
+
+```js
+let obj = {a: 100};
+let trapLogic = {
+ getOwnPropertyDescriptor(targetObj, key) {
+ console.log(`getOwnPropertyDescriptor: ${key}`); // บรรทัด a
+ return Reflect.getOwnPropertyDescriptor(targetObj, key);
+ },
+ defineProperty(targetObj, key, descriptor) { // บรรทัด b
+ console.log(`defineProperty: ${key}`);
+ return Reflect.defineProperty(targetObj, key, descriptor);
+ }
+ /* ,set(targetObj, key, value, proxy) { // บรรทัด c
+ console.log(`set property: ${key} = ${value}`);
+ return Reflect.set( targetObj, key, value );
+ }*/
+};
+let proxyObj = new Proxy( obj, trapLogic);
+proxyObj.a = 100;
+/* แสดงผลลัพธ์เป็น
+"getOwnPropertyDescriptor: a"
+"defineProperty: a"
+*/
+/* แต่ถ้าเอาคอมเมนต์ของบรรทัด c ออกไป จะเปลี่ยนไปแสดงผลลัพธ์เป็น
+"set property: a = 100"
+*/
+```
+
+### วิธียกเลิกพร็อกซี่
+
+```js
+let trapLogic = {
+ set(target,key,value, proxy) {
+ console.log(`set property: ${key} = ${value}`);
+ return true;
+ }
+};
+let {proxy: myProxy, revoke: revokeFunc} = Proxy.revocable({}, trapLogic); // บรรทัด a
+myProxy.a = 100; // "set property: a = 100" -- บรรทัด b
+revokeFunc(); // หยุดการทำงานของพร็อกซี่
+console.log(myProxy.a); // TypeError -- บรรทัด c
+```
+
+## ลำดับของพร็อพเพอร์ตี้
+
+```js
+let parent = { parentKey: 1 };
+let obj = {
+ __proto__: parent // กำหนดโปรโตไทป์เป็น parent
+};
+console.log(obj.parentKey); // 1
+obj.z = 100;
+obj.y = 200;
+obj [Symbol("c")] = "symbol c";
+obj [Symbol("a")] = "symbol a";
+obj[3.14] = 400;
+obj[-10] = 300
+obj[null] = 500;
+obj[undefined] = 600;
+obj[true] = 700;
+obj[{}] = 800;
+obj[10] = "foo";
+obj[0] = "bar";
+console.log(Reflect.ownKeys(obj));
+// [ '0', '10', 'z', 'y', '3.14', '-10', 'null', 'undefined', 'true', '[object Object]', Symbol(c), Symbol(a) ]
+console.log(Object.getOwnPropertyNames(obj));
+// [ '0', '10', 'z', 'y', '3.14', '-10', 'null', 'undefined', 'true', '[object Object]' ]
+console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(c), Symbol(a) ]
+```
+
diff --git a/examples_book/Chapter18.md b/examples_book/Chapter18.md
new file mode 100644
index 0000000..32d572c
--- /dev/null
+++ b/examples_book/Chapter18.md
@@ -0,0 +1,890 @@
+# โค้ดบทที่ 18 พรอมิส
+
+## พรอมิสคืออะไร
+
+```js
+let promise = new Promise( function (resolve, reject) {
+ console.log(typeof resolve); // บรรทัด a
+ console.log(typeof reject); // บรรทัด b
+ console.log("Promise"); // บรรทัด c
+ } );
+console.log("Last statement"); // บรรทัด d
+/* แสดงผลลัพธ์เป็น
+"function"
+"function"
+"Promise"
+"Last statement" */
+```
+
+## เมธอด then()
+
+```js
+function asynCode(resolve, reject) {
+ setTimeout( function() { // บรรทัด a
+ /* ซอร์สโค้ดอื่น ๆ */
+ //...
+ resolve("success"); // บรรทัด b -- แจ้งว่าพรอมิสทำงานสำเร็จ
+ }, 1000); // ดีเลย์ 1 วินาที
+};
+let promise = new Promise(asynCode); // บรรทัด c
+promise.then(
+ function (value) { // บรรทัด d -- มอนิเตอร์พรอมิส กรณีที่มันทำงานสำเร็จ
+ console.log("Promise:", value);
+ }
+);
+console.log("Last statement"); // บรรทัด e
+/* แสดงผลลัพธ์เป็น
+"Last statement"
+"Promise: success" */
+```
+
+```js
+let asynCode = function (resolve, reject) {
+ console.log("Start a job");
+ let condition;
+ /* ซอร์สโค้ดอะซิงโครนัส */
+ //...
+ if (condition) {
+ resolve("success"); // บรรทัด a -- แจ้งว่าพรอมิสทำงานสำเร็จ
+ } else {
+ reject("failed"); // บรรทัด b -- แจ้งว่าพรอมิสทำงานไม่สำเร็จ
+ }
+};
+let promise = new Promise(asynCode);
+promise.then(
+ function (value) { // บรรทัด c -- มอนิเตอร์พรอมิส กรณีที่มันทำงานสำเร็จ
+ console.log("Promise:",value);
+ }, function (reason) { // บรรทัด d -- มอนิเตอร์พรอมิส กรณีที่มันทำงานไม่สำเร็จ
+ console.log("Promise:", reason);
+ }
+);
+console.log("Last statement");
+// แสดงผลลัพธ์เป็น
+// "Start a job"
+// "Last statement"
+// "Promise: success" หรือ "Promise: failed"
+```
+
+## เมธอด cath()
+
+```js
+let promise = new Promise( function (resolve, reject) {
+ // เมื่อทำงานไม่สำเร็จ
+ console.log("Start a job");
+ reject("failed"); // บรรทัด a
+});
+promise.catch( function (reason){ // บรรทัด b
+ console.log("Promise:", reason);
+});
+console.log("Last statement");
+/* แสดงผลลัพธ์เป็น
+"Start a job"
+"Last statement"
+"Promise: failed" */
+```
+
+```js
+let promise = new Promise( function(resolve, reject) {
+ console.log("Start a job");
+ throw new Error("Error in promise"); // บรรทัด a
+});
+promise.catch( function(error) { // บรรทัด b
+ console.log(error.message);
+} );
+console.log("Last statement");
+/* แสดงผลลัพธ์เป็น
+"Start a job"
+"Last statement"
+"Error in promise" */
+```
+
+```js
+let promise = new Promise( function(resolve, reject) {
+ try{
+ console.log("Start a job");
+ throw new Error("Error in promise");
+ } catch(error) {
+ reject(error);
+ }
+});
+promise.catch( function(error) {
+ console.log(error.message);
+} );
+console.log("Last statement");
+/* แสดงผลลัพธ์เป็น
+"Start a job"
+"Last statement"
+"Error in promise" */
+```
+
+## ตำแหน่งการวาง then() กับ cath()
+
+```js
+let promise = new Promise( function(resolve, reject ) {
+ // resolve("success");
+ // reject("failed");
+});
+console.log("Line 1"); // บรรทัดที่ 1
+//...
+console.log("Line 2000"); // บรรทัดที่ 2000
+promise.catch( function(reason) { // จะวาง catch() ไว้หลังจากสร้างพรอมิสตำแหน่งใดก็ได้
+ console.log("Promise:", reason);
+} );
+//...
+console.log("Line 5000"); // บรรทัดที่ 5000
+promise.then( function(value) { // จะวาง then() ไว้หลังจากสร้างพรอมิสตำแหน่งใดก็ได้
+ console.log("Promise:", value);
+} );
+```
+
+```js
+let promise = new Promise( function(resolve, reject) {
+ console.log("Start a job");
+ resolve("success");
+});
+promise.then( function(value) {
+ console.log("Outer Promise:", value);
+ promise.then( function (value) {
+ console.log("Inner Promise:", value);
+ });
+} );
+console.log("Last statement");
+/* แสดงผลลัพธ์เป็น
+"Start a job"
+"Last statement"
+"Outer Promise: success"
+"Inner Promise: success" */
+```
+
+```js
+let promise = new Promise( function(resolve, reject) {
+ console.log("Start a job");
+ reject("failed");
+});
+promise.catch( function(reason) {
+ console.log("Outer promise:", reason);
+ promise.catch( function (reason) {
+ console.log("Inner promise:", reason);
+ });
+} );
+console.log("Last statement");
+/* แสดงผลลัพธ์เป็น
+"Start a job"
+"Last statement"
+"Outer promise: failed"
+"Inner promise: failed" */
+```
+
+## เรียก then() แบบต่อเนื่อง
+
+```js
+let p1 = new Promise( function(resolve, reject) {
+ resolve("success"); // บรรทัด a
+});
+let p2 = p1.then( function(value) {
+ console.log("Promise:", value); // บรรทัด b
+});
+p2.then( function() { // บรรทัด c
+ console.log("Finish");
+});
+/* แสดงผลลัพธ์เป็น
+"Promise: success"
+"Finish" */
+```
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ resolve("success");
+});
+promise.then(function(value) { // then() ตัวแรก
+ console.log("Promise:", value);
+}).then(function() { // then() ตัวที่สอง ฟังก์ชันคอลแบ็คจะไม่มีพารามิเตอร์
+ console.log("then1: finish");
+}). then(function() { // then() ตัวที่สาม ฟังก์ชันคอลแบ็คจะไม่มีพารามิเตอร์
+ console.log("then2: finish");
+});
+/* แสดงผลลัพธ์เป็น
+"Promise: success"
+"then1: finish"
+"then2: finish" */
+```
+
+## ดักจับ error แบบต่อเนื่อง
+
+```js
+let promise = new Promise (function(resolve, reject) {
+ throw new Error("error1"); // บรรทัด a
+});
+promise.catch( function(error) { // catch() ตัวแรก
+ console.log("catch1:", error.message);
+ throw new Error("error2");
+}).catch( function(error) { // catch() ตัวที่สอง
+ console.log("catch2:", error.message);
+ throw new Error("error3");
+}).catch( function(error) { // catch() ตัวที่สาม
+ console.log("catch3:", error.message);
+});
+/* แสดงผลลัพธ์
+"catch1: error1
+"catch2: error2"
+"catch3: error3" */
+```
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ throw new Error("Error");
+});
+promise.catch( function(error) { // ฟังก์ชันชั่นคอลแบ็คของ catch() ตัวแรก จะทำงาน
+ console.log(error.message);
+}).catch( function() { // ฟังก์ชันชั่นคอลแบ็คของ catch() ตัวที่สอง ไม่ถูกเรียกให้ทำงาน
+ console.log("Last error");
+});
+// แสดงผลลัพธ์
+// "Error"
+```
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ throw new Error("Error");
+});
+promise.catch( function(error) {
+ console.log(error.message);
+}).then( function(value) {
+ console.log("Last then");
+});
+/* แสดงผลลัพธ์
+"Error"
+"Last then" */
+```
+
+## ประโยค return
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ resolve("success");
+});
+promise.then(function(value) { // then() ตัวแรก
+ console.log("then1:", value);
+ return 2; // ส่ง 2 ไปให้กับฟังก์ชันคอลแบ็คของ then() ตัวถัดไป
+}).then(function(value) { // ประกาศฟังก์ชันคอลแบ็คให้มีพารามิเตอร์
+ console.log("then2:", value);
+ return 3; // ส่ง 3 ไปให้กับฟังก์ชันคอลแบ็คของ then() ตัวถัดไป
+}). then(function(value) { // ประกาศฟังก์ชันคอลแบ็คให้มีพารามิเตอร์
+ console.log("then3:", value);
+});
+/* แสดงผลลัพธ์เป็น
+"then1: success"
+"then2: 2"
+"then3: 3" */
+```
+
+## การใช้ then() ร่วมกับ catch()
+
+
+```js
+let promise = new Promise( function(resolve, reject) { // บรรทัด a
+ reject("Promise:");
+});
+promise.then( function(value) {
+ console.log(value, "success"); // ไม่ถูกเรียกให้ทำงาน
+}).catch( function(reason) {
+ console.log(reason, "failed"); // ถูกเรียกให้ทำงาน
+});
+// แสดงผลลัพธ์
+// "Promise: failed"
+```
+
+```js
+let promise = new Promise( function(resolve, reject) {
+ resolve("Promise:");
+});
+promise.catch( function(value) {
+ console.log(value, "failed"); // ไม่ถูกเรียกให้ทำงาน
+}).then( function(reason) {
+ console.log(reason, "success"); // ถูกเรียกให้ทำงาน
+});
+// แสดงผลลัพธ์
+// "Promise: success"
+```
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ throw new Error("Error");
+});
+promise.catch(function(error) {
+ console.log(error.message);
+ return 1; // สามารถส่ง 1 ไปให้ฟังก์ชันคอลแบ็คของ then() ตัวถัดไปได้
+}).then(function(value) {
+ console.log("then:", value);
+ return 2; // ไม่สามารถส่ง 2 ไปให้ฟังก์ชันคอลแบ็คของ catch() ตัวถัดไปได้
+}).catch(function(error) {
+ console.log("catch:", error); // ไม่ถูกเรียกให้ทำงาน
+});
+/* แสดงผลลัพธ์
+"Error"
+"then: 1" */
+```
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ throw new Error("Error");
+});
+promise.catch( function(error) {
+ console.log(error.message);
+ return 1;
+}).then( function(value) {
+ console.log("then:", value);
+ throw 2;
+}).catch( function(value) {
+ console.log("catch:", value); // ถูกเรียกให้ทำงานได้
+});
+/* แสดงผลลัพธ์
+"Error"
+"then: 1"
+"catch: 2" */
+```
+
+## รีเทิร์นพรอมิส
+
+```js
+let p1 = new Promise( function(resolve, reject) {
+ resolve("promise1");
+});
+let p2 = new Promise( function(resolve, reject) {
+ resolve("promise2"); // บรรทัด a
+});
+let p3 = p1.then( function(value) {
+ console.log("First then:", value);
+ return p2; // บรรทัด b
+});
+p3.then( function(value) { // บรรทัด c
+ console.log("Second then:", value);
+});
+/* แสดงผลลัพธ์
+"First then: promise1"
+"Second then: promise2" */
+```
+
+```js
+let p1 = new Promise( function(resolve, reject) {
+ resolve("promise1");
+});
+let p2 = new Promise( function(resolve, reject) {
+ resolve("promise2");
+});
+p1.then( function(value) {
+ console.log("First then:", value);
+ return p2;
+}).then( function(value) {
+ console.log("Second then:", value);
+});
+/* แสดงผลลัพธ์
+"First then: promise1"
+"Second then: promise2" */
+```
+
+```js
+let p1 = new Promise( function(resolve, reject) {
+ resolve("success");
+});
+let p2 = new Promise( function(resolve, reject) {
+ reject("failed");
+});
+p1.then( function(value) {
+ console.log("then:",value);
+ return p2;
+}).catch( function(value) { // บรรทัด a
+ console.log("catch:", value);
+});
+/* แสดงผลลัพธ์
+"then: success"
+"catch: failed" */
+```
+
+```js
+let p1 = new Promise( function(resolve, reject) {
+ console.log("Promise1");
+ resolve("Success1");
+});
+p1.then( function(value) {
+ console.log("p1.then:", value);
+ let p2 = new Promise( function(resolve, reject) { // บรรทัด a
+ console.log("Promise2");
+ resolve("Success2");
+ });
+ return p2;
+}).then(function(value) {
+ console.log("p2.then:", value);
+});
+/* แสดงผลลัพธ์
+"Promise1"
+"p1.then: Success1"
+"Promise2"
+"p2.then: Success2" */
+```
+
+## การสร้างพรอมิสที่มีสถานะ settled
+
+```js
+let promise = Promise.resolve("Promise is fulfilled");
+/*ไม่ต้องเสียเวลาเขียนแบบนี้
+let promise = new Promise(function(resolve, reject) {
+ resolve("Promise is fulfilled");
+}); */
+promise.then(function(value) {
+ console.log(value);
+});
+// แสดงผลลัพธ์เป็น
+// "Promise is fulfilled"
+```
+
+```js
+let promise = Promise.reject("Promise is rejected");
+/*ไม่ต้องเสียเวลาเขียนแบบนี้
+let promise = new Promise(function(resolve, reject) {
+ reject("Promise is rejected");
+}); */
+promise.catch(function(reason) {
+ console.log(reason);
+});
+// แสดงผลลัพธ์เป็น
+// "Promise is rejected"
+```
+
+```js
+let thenable = {
+ then(resolve, reject) {
+ resolve("fulfilled");
+ }
+};
+```
+
+```js
+let thenable = {
+ then (resolve, reject) {
+ console.log("thenable");
+ resolve("fulfilled"); // บรรทัด a -- จะส่งค่า "fulfilled" ไปให้ promise.then()
+ }
+};
+let promise = Promise.resolve(thenable);
+promise.then(function(value) {
+ console.log("then:", value); // บรรทัด b
+});
+/* แสดงผลลัพธ์เป็น
+"thenable"
+"then: fulfilled" */
+```
+
+## เมธอด finally()
+
+```js
+Promise.resolve("fulfilled") // บรรทัด a
+.then( result => console.log("then:", result) ) // บรรทัด b
+.catch( result => console.log("catch:", result) )
+.finally( () => console.log("finally") ); // บรรทัด c
+/* แสดงผลลัพธ์
+"then: fulfilled"
+"finally" */
+```
+
+```js
+Promise.reject("rejected") // บรรทัด a
+.then( result => console.log("then:", result) )
+.catch( result => console.log("catch:", result) ) // บรรทัด b
+.finally( () => console.log("finally") ); // บรรทัด c
+/* แสดงผลลัพธ์
+"catch: rejected"
+"finally" */
+```
+
+```js
+Promise.resolve("fulfilled") // บรรทัด a
+.finally( () => console.log("finally") ) // บรรทัด b
+.then( result => console.log("then:", result) ) // บรรทัด c
+.catch( result => console.log("catch:", result) );
+/*
+"finally"
+"then: fulfilled" */
+```
+
+```js
+Promise.reject("rejected") // บรรทัด a
+.finally( () => console.log("finally") ) // บรรทัด b
+.then( result => console.log("then:", result) )
+.catch( result => console.log("catch:", result) ); // บรรทัด c
+/*
+"finally"
+"catch: rejected" */
+```
+
+```js
+Promise.reject("rejected") // บรรทัด a
+.finally( () => {
+ throw "error from finally"; // บรรทัด b
+} )
+.catch( error => console.log(error) ); // บรรทัด c
+// แสดงข้อความ
+// "error from finally"
+```
+
+```js
+Promise.resolve("fulfilled")
+.finally( ( ) => { return 1 } ) // เขียนย่อเป็น .finally( ( ) => 1 ) ก็ได้
+.then( value => console.log(value));
+// แสดงผลลัพธ์
+// "fulfilled"
+```
+
+```js
+Promise.resolve("fulfilled")
+.finally( () => console.log("finally") ) // มีแค่ finally() อย่างเดียว
+// แสดงผลลัพธ์
+// "finally"
+```
+
+## Promise.all()
+
+```js
+let p1 = Promise.resolve("Promise1");
+let p2 = Promise.resolve("Promise2");
+let p3 = Promise.resolve("Promise3");
+let p4 = Promise.all([p1, p2, p3]); // มอนิเตอร์ p1, p2 และ p3 ที่มีสถานะเป็น fulfilled ทุกตัว
+p4.then(function(value) {
+ console.log(value);
+});
+// แสดงผลลัพธ์เป็น
+// [ 'Promise1', 'Promise2', 'Promise3' ]
+```
+
+```js
+let p1 = new Promise(function(resolve, reject) {
+ resolve("Promise1:");
+});
+let p2 = new Promise(function(resolve, reject) {
+ setTimeout( function(){
+ reject("Promise2:");
+ }, 1000); // ดีเลย์ไป 1 วินาที
+});
+let p3 = Promise.reject("Promise3:");
+let p4 = Promise.all([p1, p2, p3]); // มอนิเตอร์เฉพาะ p3 เพราะมีสถานะเป็น rejected ก่อนตัวอื่น
+p4.then(
+ function(value) { console.log(value, "success"); }
+ ,function(value) { console.log(value, "failed"); }
+);
+// แสดงผลลัพธ์เป็น
+// "Promise3: failed"
+```
+
+## Promise.race()
+
+```js
+let p1 = new Promise( function(resolve, reject) {
+ setTimeout( function() {
+ resolve("Promise1:");
+ }, 500); // ดีเลย์ 0.5 วินาที
+});
+let p2 = new Promise( function(resolve, reject) {
+ setTimeout( function() {
+ resolve("Promise2:");
+ }, 1000); // ดีเลย์ 1 วินาที
+});
+let p3 = Promise.reject("Promise3:");
+let p4 = Promise.race([p1, p2, p3]); // มอนิเตอร์เฉพาะพรอมิส p3 เพราะมีสถานะเป็น settled ก่อนตัวอื่น
+p4.then(
+ function(value) { console.log(value, "success"); }
+ ,function(value) { console.log(value, "failed"); }
+);
+// แสดงผลลัพธ์เป็น
+// "Promise3: failed"
+```
+
+## Promise.allSettled()
+
+```js
+let p1 = Promise.resolve(123);
+let p2 = Promise.reject(456);
+Promise.allSettled( [p1, p2] );
+```
+
+```js
+let p1 = Promise.resolve(123);
+let p2 = Promise.reject(456);
+Promise.allSettled( [p1, p2] ) // allSettled() รีเทิร์นพรอมิสที่เป็น fulfilled
+.then( arr => console.log(arr) ); // ค่า fulfillment และ rejection ที่ถูกส่งมาเป็นอาร์เรย์
+
+/* แสดงผลลัพธ์
+[
+ { status: 'fulfilled', value: 123 },
+ { status: 'rejected', reason: 456 }
+] */
+```
+
+```js
+let p1 = Promise.resolve(123);
+let p2 = new Promise( resolve => {
+ throw "Error" // บรรทัด a
+});
+Promise.allSettled( [p1, p2] ) // บรรทัด b
+.then( arr => console.log(arr) ) // บรรทัด c
+.catch( err => console.log(err) ); // บรรทัด d -- ไม่ถูกเรียกให้ทำงาน
+
+/* แสดงผลลัพธ์
+[
+ { status: 'fulfilled', value: 123 },
+ { status: 'rejected', reason: 'Error' }
+] */
+```
+
+## Promise.any() กับ AggregateError
+
+```js
+let p1 = Promise.resolve(123);
+let p2 = Promise.resolve(456);
+let p3 = Promise.reject(789);
+Promise.any([p1, p2, p3]);
+
+Promise.any([p1, p2, p3]) // p1 เป็น fulfilled ก่อน p2
+.then(value=> console.log(value) ); // จะส่งค่า 123 ของ p1 มาให้ then()
+// แสดงผลลัพธ์
+// 123
+```
+
+```js
+let p1 = new Promise( (resolve) => setTimeout(resolve, 3000) ); // หลับไป 3 วินาที
+let p2 = Promise.resolve(456); // ทำงานเสร็จก่อน p1
+let p3 = Promise.reject(789);
+Promise.any([p1, p2, p3]) // p2 เป็น fulfilled ก่อนตัวอื่น
+.then(value=> console.log(value) ); // จะส่งค่า 456 ของ p2 มาให้ then()
+// แสดงผลลัพธ์
+// 456
+```
+
+```js
+let p1 = Promise.reject("Error 1");
+let p2 = Promise.reject("Error 2");
+let p3 = Promise.reject("Error 3");
+Promise.any([p1, p2, p3])
+.catch(aggregateError => console.log(aggregateError));
+/* แสดงผลลัพธ์
+[AggregateError: All promises were rejected] {
+ [errors]: [ 'Error 1', 'Error 2', 'Error 3' ]
+} */
+
+Promise.any([p1, p2, p3])
+.catch(aggregateError => console.log(aggregateError.errors)); // เข้าถึงพร็อพเพอร์ตี้ errors
+// แสดงผลลัพธ์
+// [ 'Error 1', 'Error 2', 'Error 3' ]
+```
+
+## การประยุกต์ใช้งานพรอมิส
+
+* ตัวอย่างที่ 1
+หมายเหตุ ตัวอย่างนี้ต้องรันไฟล์ ajax.mjs ที่เครื่องตัวเองขึ้นมาด้วย เพื่อรองรับ request ที่เข้ามา
+แต่ถ้าไม่สะดวก็ให้เปลี่ยน url จาก http://127.0.01:8001/messagepromise
+ไปเป็น https://patanasongsivilai.com/example/ajax.php
+
+และตัวอย่างข้างล่างจะแสดงผลลัพธ์หน้าคอนโซลของเว็บเบราเซอร์ด้วย
+{"echo": "test promise"}
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+* ตัวอย่างที่ 2
+
+* [ไฟล์ json.php ประกอบเนื้อหา Fetch API](json.php)
+
+```js
+fetch("https://patanasongsivilai.com/example/json.php") // บรรทัด a
+.then( function (res) { // บรรทัด b
+ return res.text(); // บรรทัด c
+ }
+)
+.then( function (txt) { // บรรทัด d
+ console.log(txt); // บรรทัด e
+ }
+);
+// แสดงผลลัพธ์
+// {"name":"Somchai","age":30,"city":"Bangkok"}
+```
+
+หมายเหตุ ตัวอย่าง html ถัดไป ต้องรันไฟล์ ajax.mjs ที่เครื่องตัวเองขึ้นมาด้วย เพื่อรองรับ request ที่เข้ามา
+แต่ถ้าไม่สะดวก็ให้เปลี่ยน url จาก http://127.0.01:8001/message?msg=test promise
+ไปเป็น https://patanasongsivilai.com/example/ajax.php?msg=test promise
+
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+* ตัวอย่างที่ 3 (ต้องรันบน Node.js เท่านั้น)
+
+* [ไฟล์ json.txt](Chapter18/json.txt)
+ตัวอย่างไฟล์ json.txt อยู่ที่ https://raw.githubusercontent.com/adminho/javascript/master/examples_book/Chapter18/json.txt
+
+```js
+function readJSONFile(fileName){
+ function asynCode(resolve,reject) {
+ let fs = require("fs"); // ใช้อ่านไฟล์
+ fs.readFile(fileName, function(err, text) { // บรรทัด a
+ if (err) {
+ reject(err.message); // บรรทัด b
+ } else {
+ let obj = JSON.parse(text);
+ let json = JSON.stringify(obj, null, 2);
+ resolve(json); // บรรทัด c
+ } // สิ้นสุดประโยค if
+ });
+ } // สิ้นสุดการประกาศฟังก์ชัน asynCode
+ return new Promise(asynCode); // บรรทัด d
+} // สิ้นสุดการประกาศฟังก์ชัน readJSONFile
+let reader = readJSONFile("json.txt"); // อ่านไฟล์ json.text
+console.log("Read a file");
+function handle(value) { console.log(value); }
+function errorHandle(errMsg) { console.log("Error message:", errMsg); }
+reader.then(handle, errorHandle) // บรรทัด e
+```
+
+* ตัวอย่างที่ 4
+
+```js
+let iterator = generator();
+iterator.next(); // เริ่มทำงาน
+function *generator() {
+ for(let i=0; i<5; i++) {
+ let result = yield runService(i); // บรรทัด a
+ console.log("Message:" , result);
+ }
+}
+function runService(data) {
+ function aysnCode(resolve, reject) {
+ console.log("to do something:", data); // บรรทัด b
+ // การทำงานแบบอะซิงโครนัสอื่น ๆ
+ // ...
+ setTimeout(function() {
+ resolve(data); // บรรทัด c
+ }
+ ,1000); // ดีเลย์ 1 วินาที
+ }
+ let promise = new Promise(aysnCode);
+ promise.then(function(value) { // บรรทัด d
+ let result = `service ${value} is success`;
+ iterator.next(result);
+ });
+}
+
+/* แสดงผลลัพธ์
+to do something: 0
+Message: service 0 is success
+to do something: 1
+Message: service 1 is success
+to do something: 2
+Message: service 2 is success
+to do something: 3
+Message: service 3 is success
+to do something: 4
+Message: service 4 is success */
+```
+
+## สไตล์การเขียนด้วยฟังก์ชันคอลแบ็ค
+
+```js
+Promise.resolve(123)
+.then( function(value) { // บรรทัด a -- ฟังก์ชันคอลแบ็คแบบไร้ชื่อ ขึ้นต้นด้วย function
+ console.log(value);
+ }
+);
+// แสดงผลลัพธ์
+// 123
+Promise.reject("Error")
+.catch(function (value) {
+ console.log(value); // บรรทัด b -- ฟังก์ชันคอลแบ็คแบบไร้ชื่อ ขึ้นต้นด้วย function
+ }
+);
+// แสดงผลลัพธ์
+// "Error"
+```
+
+```js
+Promise.resolve(123)
+.then( value => console.log(value)); // บรรทัด a -- ฟังก์ชันคอลแบ็คเป็นฟังก์ชันลูกศร
+// แสดงผลลัพธ์
+// 123
+Promise.reject("Error")
+.catch( value => console.log(value)); // บรรทัด b - ฟังก์ชันคอลแบ็คเป็นฟังก์ชันลูกศร
+// แสดงผลลัพธ์
+// "Error"
+```
+
+```js
+let promise = new Promise(function(resolve, reject) {
+ console.log("Line a ...to do something") // บรรทัด a
+});
+console.log("I done already"); // บรรทัดนี้ถูกเรียกให้ทำงาน
+promise.then( value => console.log(value)) // บรรทัด b
+.catch( value => console.log(value)); // บรรทัด c
+/* แสดงผลลัพธ์เป็น
+"Line a ...to do something"
+"I done already" */
+```
\ No newline at end of file
diff --git a/examples_book/Chapter18/json.txt b/examples_book/Chapter18/json.txt
new file mode 100644
index 0000000..00459a6
--- /dev/null
+++ b/examples_book/Chapter18/json.txt
@@ -0,0 +1,4 @@
+{"Font":[
+ {"color":"red", "lang":"thai"},
+ {"color":"blue", "lang":"eng"}
+]}
diff --git a/examples_book/Chapter19.md b/examples_book/Chapter19.md
new file mode 100644
index 0000000..b7dafa3
--- /dev/null
+++ b/examples_book/Chapter19.md
@@ -0,0 +1,627 @@
+# โค้ดบทที่ 19 การใช้งาน async กับ await
+
+## ประกาศฟังก์ชันด้วย async
+
+* กรณีที่ฟังก์ชันแบบ async รีเทิร์นพรอมิสที่เป็น fulfilled
+
+```js
+async function asyncFunc() {
+ return 123; // บรรทัดที่ 2
+}
+```
+
+* เสมือนเขียนดังนี้
+```js
+function asyncFunc() { // เสมือนเขียนฟังก์ชันปกติธรรมดา
+ return new Promise( resolve => { // จะรีเทิร์นพรอมิส
+ resolve(123); // จากประโยค return 123 เสมือนเรียก resolve(123)
+ });
+}
+```
+
+```js
+async function asyncFunc() {
+ return 123; // 123 คือค่าที่ส่งไปให้ฟังก์ชันคอลแบ็คของ then()
+}
+asyncFunc() // บรรทัด a
+.then(x => console.log(x)); // 123
+```
+
+```js
+async function asyncFunc() {
+ console.log("aysnc function");
+ // บรรทัด 3 - จะเสมือนมีประโยค return undefined;
+}
+```
+
+```js
+function asyncFunc() { // เสมือนเขียนฟังก์ชันปกติธรรมดา
+ return new Promise( resolve => { // จะรีเทิร์นพรอมิส
+ console.log("aysnc function"); // โค้ดถูกห่ออยู่ในพรอมิสที่สร้างขึ้นมา
+ resolve(undefined); // จะเสมือนมี resolve(undefined) ต่อท้าย
+ });
+}
+```
+
+```js
+async function asyncFunc() {
+ console.log("aysnc function");
+ // บรรทัด 3 - จะเสมือนมีประโยค return undefined;
+}
+asyncFunc() // บรรทัด a -- เรียกฟังก์ชันให้ทำงาน
+.then(x => console.log(x)); // undefined
+/* แสดงผลลัพธ์
+"aysnc function"
+undefined */
+```
+
+* กรณีที่ฟังก์ชันแบบ async รีเทิร์นพรอมิสที่เป็น rejected
+
+```js
+async function asyncFunc() {
+ throw new Error("Problem!"); // error ที่ส่งไปให้ฟังก์ชันคอลแบ็คของ catch
+}
+```
+
+* เสมือนเขียนดังนี้
+
+```js
+function asyncFunc() {
+ return new Promise( (resolve, reject) => {
+ reject( new Error("Problem!") ) ;
+ });
+}
+```
+
+```js
+async function asyncFunc() {
+ throw new Error("Problem!"); // error ที่ส่งไปให้ฟังก์ชันคอลแบ็คของ catch
+}
+asyncFunc()
+.catch(err => console.log(err)); // Error: Problem!
+```
+
+```js
+async function asyncFunc() {
+ console.log("aysnc function()"); // บรรทัด a -- ซิงโครนัส
+ return 123; // บรรทัด b
+}
+console.log("Start"); // บรรทัด c -- ซิงโครนัส
+asyncFunc(). // บรรทัด d
+then(x => console.log(`Resolved: ${x}`)); // บรรทัด e - อะซิงโครนัส
+console.log("End"); // บรรทัด f - ซิงโครนัส
+/* แสดงผลลัพธ์
+"Start"
+"aysnc function()"
+"End"
+"Resolved: 123" */
+```
+
+* เมื่อฟังก์ชันแบบ async รีเทิร์นพรอมิสออกมาโดยตรง
+
+```js
+async function asyncFunc() {
+ return Promise.resolve(123); // บรรทัด a -- ส่งพรอมิสที่เป็น fulfilled ออกมา
+}
+asyncFunc() // บรรทัด b
+.then(x => console.log(x)) // 123
+```
+
+```js
+async function asyncFunc() {
+ return Promise.reject(new Error('Problem!')); // บรรทัด a ส่งพรอมิสที่เป็น rejected ออกมา
+}
+asyncFunc() // บรรทัด b
+.catch(err => console.error(err)); // Error: Problem!
+```
+
+* สรุป การรีเทิร์นของฟังก์ชันแบบ asyn ก็ใช้หลักเกณฑ์เดียวกันกับการ return ของพรอมิส
+
+```js
+async function asyncFunc() {
+ return otherAsyncFunc();
+}
+```
+
+```js
+async function asyncFunc() {
+ return await otherAsyncFunc();
+}
+```
+
+## การใช้งาน await
+
+```js
+async function asyncFunc() {
+ let result = await new Promise(resolve => resolve(123)); // บรรทัด a
+ console.log(result); // บรรทัด b
+}
+asyncFunc(); // 123
+```
+
+```js
+async function asyncFunc() {
+ return new Promise( resolve => resolve(123) )
+ .then( result => console.log(result) );
+}
+asyncFunc(); // 123
+```
+
+```js
+async function asyncFunc() {
+ return await new Promise(resolve => resolve(123)); // return นำหน้า await
+}
+```
+
+```js
+async function asyncFunc() {
+ // เสมือนเขียน
+ let result = await new Promise(resolve => resolve(123)); // result = 123
+ return result; // รีเทิร์นพรอมิส พร้อมส่งค่า result = 123 ออกไป
+}
+
+asyncFunc()
+.then( value => console.log(value))
+// แสดงผลลัพธ์
+// 123
+```
+
+```js
+async function asyncFunc() {
+ try {
+ let result = await new Promise((resolve, reject) => reject("Error!")); // บรรทัด a
+ } catch (err) {
+ console.log(err); // บรรทัด b
+ }
+}
+asyncFunc(); // "Error!"
+```
+
+```js
+async function asyncFunc() {
+ return new Promise((resolve, reject) => reject("Error!"))
+ .catch(err => console.log(err));
+}
+asyncFunc(); // "Error!"
+```
+
+### ขอฝากเตือน
+
+```js
+async function asyncFunc() {
+ try {
+ let result = await new Promise((resolve, reject) => { }); // บรรทัด a
+ console.log(result); // บรรทัด b
+ } catch (err) {
+ console.log(err); // บรรทัด c
+ }
+}
+asyncFunc();
+```
+
+### ข้อควรระวังในการใช้ await
+
+```js
+function myFunc() { // ไม่มี async นำหน้า
+ let result = await Promise.resolve("Success!"); // SyntaxError
+}
+```
+
+```run.module
+let result = await Promise.resolve("Success!");
+console.log(result); // "Success!"
+```
+
+```run.module
+try {
+ await Promise.reject("Error!");
+} catch (error) {
+ console.log(error); // "Error!"
+}
+```
+
+```run.module
+let result = await 123;
+console.log(result) // 123
+```
+
+```js
+(async () => {
+let result = await 123;
+console.log(result) // 123
+})();
+```
+
+```js
+async function asyncFunc() {
+ function innerFunc() {
+ return await Promise.resolve("Success!"); // await อยู่ใต้ innerFunc() ไม่ได้
+ }
+ innerFunc()
+ .then(value => console.log(value))
+}
+asyncFunc();
+```
+
+```js
+async function asyncFunc() {
+ async function innerFunc() {
+ return await Promise.resolve("Success!"); // await สามารถอยู่ใต้ innerFunc() ได้
+ }
+ innerFunc()
+ .then(value => console.log(value))
+}
+asyncFunc(); // "Success!"
+```
+
+```js
+async function foo() {
+}
+async function foo() { // ประกาศชื่อ foo ซ้ำกันไม่ได้
+}
+```
+
+หมายเหตุ otherAsyncFunc(ms) ถูกนำไปใช้ในหลายๆ ตัวอย่าง
+
+```js
+async function otherAsyncFunc(ms) {
+ return new Promise (resolve =>
+ setTimeout( () => {
+ console.log("call otherAsyncFunc"); // บรรทัด a
+ resolve("Time out"); // บรรทัด b
+ }
+ , 1000) // กำหนดระยะเวลาในการ timeout ไป 1000 ms หรือ 1 วินาที
+ );
+}
+```
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+
+```js
+async function asyncFunc() {
+ console.log("Start"); // บรรทัด a
+ otherAsyncFunc(); // บรรทัด b
+ console.log("End"); // บรรทัด c
+}
+asyncFunc();
+/* แสดงผลลัพธ์
+"Start"
+"End"
+"call otherAsyncFunc" */
+```
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+
+```js
+async function asyncFunc() {
+ console.log("Start"); // บรรทัด a
+ await otherAsyncFunc(); // บรรทัด b
+ console.log("End"); // บรรทัด c
+}
+asyncFunc();
+/* แสดงผลลัพธ์
+"Start"
+"call otherAsyncFunc"
+"End" */
+```
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+
+```js
+async function asyncFunc() {
+ console.log("Start"); // บรรทัด a
+ let result = await otherAsyncFunc(); // บรรทัด a
+ console.log(result); // บรรทัด b
+}
+asyncFunc();
+/* แสดงผลลัพธ์
+"Start"
+"call otherAsyncFunc"
+"Time out" */
+```
+
+* การใช้ awiat แบบเรียงต่อเนื่องกัน
+
+
+หมายเหตุ otherAsyncFunc(ms) ถูกนำไปใช้ในหลายๆ ตัวอย่าง
+
+```js
+async function otherAsyncFunc(ms) { // ส่งค่าอากิวเมนต์เข้ามา
+ return new Promise (
+ resolve => setTimeout(
+ () => resolve(`Time out: ${ms} ms`, ms )
+ ,ms ) // กำหนด timeout หน่วยเป็นมิลลิวินาที (millisecond)
+ );
+}
+```
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+
+```js
+async function asyncFunc() {
+ let result1 = await otherAsyncFunc(1000); // บรรทัด a -- รอพรอมมิสทำงานก่อน
+ console.log(result1);
+ let result2 = await otherAsyncFunc(2000); // บรรทัด b -- รอพรอมมิสทำงานก่อน
+ console.log(result2);
+}
+asyncFunc(); // บรรทัด c
+/* แสดงผลลัพธ์
+Time out: 1000 ms
+Time out: 2000 ms */
+```
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+
+```js
+function asyncFunc() {
+ return otherAsyncFunc(1000) // ทำงานก่อน
+ .then(result1 => {
+ console.log(result1);
+ return otherAsyncFunc(2000); // ทำงานทีหลัง
+ })
+ .then(result2 => {
+ console.log(result2);
+ });
+}
+asyncFunc(); // เรียกให้ทำงาน
+/* แสดงผลลัพธ์
+Time out: 1000 ms
+Time out: 2000 ms */
+```
+
+* ประยุกต์ใช้งาน await ร่วมกับ Promise.all() เพื่อให้ฟังก์ชันทำงานคู่ขนาน
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+```js
+async function asyncFunc() {
+ let [result1, result2] = await Promise.all([
+ otherAsyncFunc(1000), // บรรทัด a -- ทำงานคู่ขนานกัน
+ otherAsyncFunc(2000), // บรรทัด b -- ทำงานคู่ขนานกัน
+ ]);
+ console.log(`${result1}, ${result2}`); // บรรทัด c
+}
+asyncFunc(); // เรียกให้ทำงาน
+// Time out: 1000 ms, Time out: 2000 ms
+```
+
+หมายเหตุ ถ้าจะรันโค้ดนี้ให้ก็อปปี้การประกาศ otherAsyncFunc() มาด้วย
+
+```js
+function asyncFunc() {
+ return Promise.all([
+ otherAsyncFunc(1000),
+ otherAsyncFunc(2000),
+ ])
+ .then( ([result1, result2]) => {
+ console.log(`${result1}, ${result2}`);
+ });
+}
+asyncFunc(); // เรียกให้ทำงาน
+// Time out: 1000 ms, Time out: 2000 ms
+```
+
+* ตัวอย่างเปลี่ยนจากการเรียกเมธอด then() ต่อเนื่อง มาเป็น await จะสะดวกกว่า
+* [ไฟล์ json.php](json.php)
+
+```js
+fetch("https://patanasongsivilai.com/example/json.php") // บรรทัด a
+.then( res => res.text()) // บรรทัด b
+.then( txt => console.log(txt) ); // บรรทัด c
+console.log("Hello"); // บรรทัด d
+// แสดงผลลัพธ์
+// "Hello"
+// {"name":"Somchai","age":30,"city":"Bangkok"}
+```
+
+```run.module
+let res = await fetch("https://patanasongsivilai.com/example/json.php") // บรรทัด a
+let txt = await res.text() // บรรทัด b
+console.log(txt) // บรรทัด c
+console.log("Hello"); // บรรทัด d
+// แสดงผลลัพธ์
+// {"name":"Somchai","age":30,"city":"Bangkok"}
+// "Hello"
+```
+
+```run.module
+async function otherAsyncFunc(ms) { // ส่งค่าอากิวเมนต์เข้ามา
+ return new Promise (
+ resolve => setTimeout(
+ () => resolve(`Time out: ${ms} ms`, ms )
+ ,ms ) // กำหนด timeout หน่วยเป็นมิลลิวินาที (millisecond)
+ );
+}
+async function func1() {
+ let time = await otherAsyncFunc(1000);
+ let t = await "func1-> " + time;
+ console.log(t);
+}
+async function func2() {
+ let time = await otherAsyncFunc(100);
+ let t = await "func2-> " + time;
+ console.log(t);
+}
+func1(); // บรรทัด a
+func2(); // บรรทัด b
+/* แสดงผลลัพธ์
+"func2-> Time out: 100 ms"
+"func1-> Time out: 1000 ms" */
+```
+
+นำตัวอย่างก่อนหน้ามาใช้ด้วยการ เติม await นำหน้า (อย่าลืมก็อปปี้โค้ด func1() กับ func2() มาใช้งานด้วย)
+```run.module
+await func1();
+await func2();
+/* แสดงผลลัพธ์
+"func1-> Time out: 1000 ms"
+"func2-> Time out: 100 ms" */
+```
+
+## Asynchronous iteration
+
+```js
+let asyncIterable = [1, 5, 10];
+
+asyncIterable[Symbol.asyncIterator]=createAsyncIterator;
+
+function createAsyncIterator() {
+ let array = this; // ในตัวอย่างนี้ this ชี้ไปยังอาร์เรย์ [1, 5, 10]
+ let i = 0; // เอาไว้นับจำนวนรอบเข้าถึงสมาชิกในอาร์เรย์
+ return {
+ // ทุกครั้งที่เรียกใช้ next() ค่าของ i จะบวกเพิ่มเป็นหนึ่งทุกครั้ง
+ next : function() {
+ return new Promise( (resolve, reject) => {
+ // เมื่อเข้าถึงสมาชิกในอาร์เรย์ครบทุกตัว done จะมีค่าเป็น true
+ let done = (i >= array.length);
+ // เข้าถึงสมาชิกในอาร์เรย์
+ let value = !done ? array[i++] : undefined;
+ // อ็อบเจ็กต์จะมีพร็อพเพอร์ตี้ value กับ done
+ let iteratorResult = { value, done };
+ resolve(iteratorResult); // บรรทัด a
+ }); // สิ้นสุดการประกาศพรอมิส
+ } // สิ้นสุดการประกาศฟังก์ชัน next()
+ };
+}
+
+let asyncIterator = asyncIterable[Symbol.asyncIterator]();
+
+asyncIterator.next() // เรียก nex() ครั้งที่ 1
+.then(function(iteratorResult ) {
+ console.log(iteratorResult); // { value: 1, done: false }
+ return asyncIterator.next(); // เรียก nex() ครั้งที่ 2
+})
+.then(function(iteratorResult ) {
+ console.log(iteratorResult); // { value: 5, done: false }
+ return asyncIterator.next(); // เรียก nex() ครั้งที่ 3
+})
+.then(function(iteratorResult ) {
+ console.log(iteratorResult); // { value: 10, done: false }
+ return asyncIterator.next(); // เรียก nex() ครั้งที่ 4 ไม่มีสมาชิกให้เข้าถึง
+})
+.then(function(iteratorResult ) {
+ console.log(iteratorResult);
+})
+/* แสดงผลลัพธ์
+{ value: 1, done: false }
+{ value: 5, done: false }
+{ value: 10, done: false }
+{ value: undefined, done: true }
+*/
+```
+
+ตัวอย่างนี้ต้องก็อปปี้การประกาศ asyncIterable จากตัวอย่างก่อนมาใช้งาน
+```run.module
+let asyncIterator2 = asyncIterable[Symbol.asyncIterator]();
+let obj1 = await asyncIterator2.next();
+let obj2 = await asyncIterator2.next();
+let obj3 = await asyncIterator2.next();
+let obj4 = await asyncIterator2.next();
+console.log(obj1); // { value: 1, done: false }
+console.log(obj2); // { value: 5, done: false }
+console.log(obj3); // { value: 10, done: false }
+console.log(obj4); // { value: undefined, done: true }
+```
+
+## ประโยคคำสั่ง for ...await ...of
+
+ตัวอย่างนี้ต้องก็อปปี้การประกาศ asyncIterable จากตัวอย่างก่อนมาใช้งาน
+```run.module
+for await (const x of asyncIterable) {
+ console.log(x);
+}
+/* แสดงผลลัพธ์
+1
+5
+10 */
+```
+
+```run.module
+for await (const x of [1, 2, 3]) {
+ console.log(x);
+}
+```
+
+```run.module
+let arr = [Promise.resolve("foo"), Promise.resolve("bar")];
+for await (const item of arr) {
+ console.log(item);
+}
+/* แสดงผลลัพธ์
+"foo"
+"bar" */
+```
+
+## Asynchronous generators
+
+รูปแบบโครงสร้างของเจนเนอเรเตอร์แบบอะซิงโครนัส จะเป็นดังนี้
+
+```notrun
+async function* asynGenerator() {
+ // ส่วนอินพุต
+ let x = await myPromise;
+ for await (const y of asyncIterable) {
+ // ···
+ }
+ // ส่วนเอาท์พุต
+ yield someValue;
+ yield* otherAsyncGen();
+}
+```
+
+ตัวอย่างโค้ด
+```run.module
+async function* asynGenerator () {
+ yield 1; // บรรทัด a
+ yield 2; // บรรทัด b
+ yield 3; // บรรทัด c
+ }
+let asyncIterable = asynGenerator(); // บรรทัด d
+let asyncIterator = asyncIterable[Symbol.asyncIterator](); // บรรทัด e
+console.log(await asyncIterator.next()); // { value: 1, done: false }
+console.log(await asyncIterator.next()); // { value: 2, done: false }
+console.log(await asyncIterator.next()); // { value: 3, done: false }
+console.log(await asyncIterator.next()); // { value: undefined, done: true }
+
+for await(const i of asynGenerator()) {
+ console.log(i) // บรรทัด a
+}
+/* แสดงผลลัพธ์
+1
+2
+3 */
+```
+
+```run.module
+async function* asynGenerator () {
+ yield Promise.resolve(1); // บรรทัด a
+ yield Promise.resolve(2); // บรรทัด b
+ yield Promise.resolve(3); // บรรทัด c
+}
+for await(const i of asynGenerator()) { // บรรทัด d
+ console.log(i) // บรรทัด e
+ }
+/* แสดงผลลัพธ์
+1
+2
+3 */
+```
+
+```run.module
+async function* otherAsynGenerator() { // บรรทัด a
+ yield Promise.resolve(2);
+ yield Promise.resolve(3);
+}
+async function* asynGenerator() {
+ yield Promise.resolve(1);
+ yield *otherAsynGenerator(); // บรรทัด b
+ yield Promise.resolve(4); // บรรทัด c
+}
+for await(const i of asynGenerator()) { // บรรทัด d
+ console.log(i)
+ }
+/* แสดงผลลัพธ์
+1
+2
+3
+4 */
+```
diff --git a/examples_book/Chapter2.md b/examples_book/Chapter2.md
deleted file mode 100644
index aca2fca..0000000
--- a/examples_book/Chapter2.md
+++ /dev/null
@@ -1,758 +0,0 @@
-# บทที่ 2 ทบทวนเบื้องต้น
-
-## คอมเมนต์
-```js
-var x = 10; //This is an example.
-```
-
-```js
-/* This is an example
-ECMAScript 6 is very easy*/
-var x = 10;
-```
-
-## console.log()
-```html
-
-
-
-
-Hello, world!
-
-
-
-```
-
-```js
-console.log("Hello world", 122, 333.333); // "Hello world 122 333.333"
-```
-
-## debugger
-```js
-console.log("line 1");
-debugger; // บรรทัดนี้จะเป็นตำแหน่งของ breakpoint เพื่อหยุดการทำงานชั่วขณะ ตอนดีบั๊กโปรแกรม
-console.log("line 2");
-```
-
-## การตั้งชื่อ
-```js
-var _ = 100; // ตั้งชื่อแบบนี้ได้
-var $ = 100; // ตั้งชื่อแบบนี้ได้
-var _a =100; // ตั้งชื่อแบบนี้ได้
-var $a =100; // ตั้งชื่อแบบนี้ได้
-var Abc = 100; // ตั้งชื่อแบบนี้ได้
-var abc = 100; // ตั้งชื่อแบบนี้ได้ แต่ทว่าตัวแปร Abc กับ abc จะถือว่าคนละชื่อกัน
-var a0123 = 100; // ตั้งชื่อแบบนี้ได้
-var 9b = 100; // ทำไม่ได้ มันจะเกิด SyntaxError เพราะมีเลข 9 นำหน้าชื่อตัวแปร
-```
-
-## การประกาศตัวแปร
-```js
-var x = 100;
-```
-
-```js
-var x = 1, y = 2, z = 3; // ประกาศตัวแปร x, y และ z ให้อยู่ในบรรทัดเดียวกัน
-```
-
-```js
-var x= 1, y = x;
-/* จะเสมือนเขียนซอร์สโค้ดแบบนี้
-var x = 1;
-var y = x;
-*/
-```
-
-```js
-var x;
-console.log(x); // undefined
-```
-
-## การประกาศตัวแปรโดยไม่มี var
-```js
-x = 1;
-```
-
-```js
-console.log(x); // ReferenceError
-```
-
-## ไดนามิกไทป์
-```js
-var foo = 42; // เริ่มต้นตัวแปร foo จะมีชนิดข้อมูลเป็นตัวเลข
-foo = "bar"; // foo เปลี่ยนมาเก็บข้อมูลเป็นสตริง
-foo = true; // foo เปลี่ยนมาเก็บข้อมูลเป็นบูลีน
-```
-
-
-### null กับ undefined
-```js
-console.log(null === undefined) // false
-console.log(null == undefined) // true
-console.log(typeof null) // "object"
-console.log(typeof undefined) // "undefined"
-```
-
-## ตัวเลข
-```js
-console.log(100, 0, -0, -300, 3.14, -78.222); // 100 0 -0 -300 3.14 -78.222
-```
-
-```js
-console.log(200e5); // 200 x 105 = 20000000
-console.log(2E-5); // 2 x 10-5 = 0.00002
-```
-
-```js
-console.log(Math.sqrt(-1)); // NaN (ไม่สามารถถอดรากที่สองของ -1)
-console.log(0/0); // NaN ( 0 หาร 0 ไม่มีนิยาม)
-console.log(parseInt("Hi")); // NaN (ไม่สามารถแปลง "Hi" เป็นตัวเลขได้)
-```
-
-```js
-console.log( Infinity * Infinity); // Infinity
-console.log( Infinity / Infinity); // NaN
-console.log(-344 * Infinity); // -Infinity
-console.log(3 / Infinity); // 0
-```
-
-```js
-console.log(Number.MAX_VALUE); // 1.7976931348623157e+308 เป็นค่าโดยประมาณ
-console.log(Number.MAX_VALUE + 100); // 1.7976931348623157e+308 เป็นค่าโดยประมาณ (บรรทัด 2)
-console.log(Number.MAX_VALUE * 10); // Infinity (บรรทัด 3)
-console.log(Number.MAX_VALUE * -10); // -Infinity (บรรทัด 4)
-```
-
-```js
-console.log(Number.MIN_VALUE); //5e-324 (เป็นค่าโดยประมาณ)
-```
-
-## สตริง
-```js
-"Learning JavaScript"
-'Learning JavaScript'
-```
-
-```js
-// ใช้ \" อยู่ภายในสตริง ส่วนเครื่องหมาย ' สามารถเขียนอยู่ในสตริงได้เลย
-console.log("...\"Learning\" 'JavaScript'..."); // ..."Learning" 'JavaScript'...
-// ใช้ \' อยู่ภายในสตริง ส่วนเครื่องหมาย " สามารถเขียนอยู่ในสตริงได้เลย
-console.log('..."Learning" \'JavaScript\'...'); // ..."Learning" 'JavaScript'...
-```
-
-```js
-var str= "line1\
-line2\
-line3";
-console.log(str); // line1line2line3
-```
-
-```js
-console.log("1234567890".length); // 10
-```
-
-## โอเปอเรเตอร์ทางคณิตศาสตร์
-```js
-console.log(true + 0); // ได้ผลลัพธ์เป็น 1 เพราะ true จะถือว่ามีค่าเป็น 1
-console.log(false + false); // ได้ผลลัพธ์เป็น 0 เพราะ false จะถือว่ามีค่าเป็น 0
-console.log(100 - true); // 99
-console.log(true * 30); // 30
-console.log(true / 2); // 0.5
-console.log(true %10); // 1
-console.log(+true); // 1
-console.log(-false); // -0
-var a = false, b=true;
-console.log(++a); // 1
-console.log(--b); // 0
-```
-
-```js
-console.log(NaN + 30); // NaN
-console.log(NaN - 30); // NaN
-console.log(NaN * 30); // NaN
-console.log(NaN / 30); // NaN
-console.log(NaN % 30); // NaN
-console.log(+NaN); // NaN
-console.log(-NaN); // NaN
-var x = NaN;
-console.log(++x); // NaN
-console.log(--x); // NaN
-```
-
-```js
-console.log(Infinity * 0); // NaN
-console.log(Infinity * 1); // Infinity
-console.log(Infinity * Infinity); // Infinity
-console.log(Infinity * -Infinity); // -Infinity
-console.log(Infinity / 0); // Infinity
-```
-
-## โอเปอเรเตอร์ที่ใช้กำหนดค่าให้กับตัวแปร
-```js
-var a = 20;
-a +=true; // true มีค่าเป็น 1
-console.log(a); // 21
-a *=NaN;
-console.log(a); // NaN
-```
-
-## โอเปเรอเตอร์แบบตรรกะ
-```js
-console.log(true || true); // true (เงื่อนไข short circuit)
-console.log(true || false); // true (เงื่อนไข short circuit)
-console.log(false || true); // true
-console.log(false || false); // false
-console.log(true && true); // true
-console.log(true && false); // false
-console.log(false && true); // false (เงื่อนไข short circuit)
-console.log(false && false); // false (เงื่อนไข short circuit)
-console.log(!true); // false
-console.log(!false); // true
-```
-
-## โอเปอเรเตอร์ระหว่างบิต
-```js
-var a = 12; // 1100 (เลขฐานสอง)
-var b = 5; // 0101 (เลขฐานสอง)
-var c = a & b; // 0100 (เลขฐานสอง)
-console.log(c.toString(2)); // 100 (เลขฐานสอง)
-console.log(c); // 4
-console.log(12 & 5); // 4
-```
-
-```js
-var a = 12; // 1100
-var b = 5; // 0101
-var c = a | b; // 1101
-console.log(c.toString(2)); // 1101
-console.log(c); // 13
-console.log(12 | 5); // 13
-```
-
-```js
-var a =12; // 1100
-var b= 5; // 0101
-var c = a ^ b; // 1001
-console.log(c.toString(2)); // 1001
-console.log(c); // 9
-console.log(12 ^ 5); // 9
-```
-
-```js
-var a= 9; // 00000000000000000000000000001001
-var b = ~a; // 11111111111111111111111111110110 (1’s Complement)
-console.log(b); // -10
-console.log(~9); // -10
-```
-
-```js
-var a = 9; // 00000000000000000000000000001001
-var c = a << 2; // เลื่อนบิตจากขวามือไปทางซ้ายมือ 2 ตำแหน่ง
- // 00000000000000000000000000100100
-console.log(c); // 36
-console.log(9 << 2); // 36
-```
-
-```js
-var a = 9; // 00000000000000000000000000001001
-var c = a >> 2; // เลื่อนบิตจากซ้ายมือไปทางขวามือ 2 ตำแหน่ง
- // 00000000000000000000000000000010
-console.log(c); // 2
-console.log(9 >> 2); // 2
-```
-
-```js
--9; // 11111111111111111111111111110111 (เลขฐานสอง)
--9 >> 2; // 11111111111111111111111111111101 (เลขฐานสอง) = -3 (เลขฐานสิบ)
-```
-
-```js
-var a = 9; // 00000000000000000000000000001001
-var c = a >>> 2; // เลื่อนบิตจากซ้ายมือไปทางขวามือ 2 ตำแหน่ง พร้อมเติมเลข 0 ที่บิตด้านหน้าสุด
- // 00000000000000000000000000000010
-console.log(c); // 2
-console.log(9 >>> 2); // 2
-```
-
-## โอเปอเรเตอร์ typeof
-```js
-console.log(typeof true); // "boolean"
-console.log(typeof false); // "boolean"
-console.log(typeof -0.13); // "number"
-console.log(typeof NaN); // "number"
-console.log(typeof Infinity); // "number"
-console.log(typeof undefined); // "undefined"
-console.log(typeof ''); // "string"
-console.log(typeof "Hi"); // "string"
-console.log(typeof (typeof 100) ); // "string"
-console.log(typeof null ); // "object"
-console.log(typeof {x: 1, y: 2}); // "object"
-console.log(typeof [1, 2]); // "object"
-console.log(typeof function(){}); // "function"
-console.log(typeof Math.sqrt); // "function"
-console.log(typeof class C {}); // "function"
-console.log(typeof Symbol()); // "symbol"
-```
-
-## โอเปอเรเตอร์วงเล็บ
-```js
-var a = 1 + 2 * 3 + 5;
-// จะเสมือนเขียนเป็น var a = 1 + (2 * 3) + 5;
-console.log(a); // 12
-```
-
-```js
-var a = (1 + 2) * (3 + 5);
-console.log(a); // 24
-```
-
-## โอเปอเรเตอร์คอมม่า
-```js
-var a = 1, b = 2;
-var x = (1+34, a+=2, b*=10, b+1);
-console.log(x); // 21
-```
-
-## โอเปอเรเตอร์ void
-```js
-var a = void 12;
-console.log(a); // undefined
-console.log(Math.ceil(4.4)); // 5
-console.log(void Math.ceil(4.4)); // undefined
-var b = 1;
-console.log(void (++b)); // undefined
-console.log(b); // แสดงค่าออกมาเป็น 2 เพราะตัวแปร b ถูกบวกเพิ่มไป 1 ค่า
-```
-
-## อาร์เรย์
-```js
-[1, 1, 1, true, "Array"]; // อาร์เรย์
-```
-
-```js
-var a = ["a", "b", "c", "d", "e"];
-console.log(typeof a); // "object"
-console.log(a[0], a[1], a[2], a[3], a [4]); // "a b c d e"
-```
-
-```js
-var array = []; // ประกาศเป็นอาร์เรย์ว่าง
-array[0] = 1;
-array[1] = 2;
-```
-
-```js
-var array = [1, 2, 3, 4, 5];
-console.log(array.length); // 5
-```
-
-```js
-var array = [1, 2, 3, 4, 5];
-console.log(array.length); // 5
-array.length = 7; // เพิ่มขนาดอาร์เรย์จาก 5 เป็น 7
-console.log(array); // [ 1, 2, 3, 4, 5, <2 empty slots> ]
-console.log(array.length); // 7
-array[9] = 100;
-console.log(array); // [ 1, 2, 3, 4, 5, <4 empty slots>, 100 ]
-console.log(array.length); // 10
-```
-
-## การประกาศฟังก์ชั่น
-```js
-function function_Name (พารามิเตอร์1, พารามิเตอร์2, …, พารามิเตอร์N)
-{
-// ซอร์สโค้ดภายในบอดี้ของฟังก์ชั่น
-return [value];
-// จะมีหรือไม่มีประโยค return ก็ได้
-// ส่วนค่า value หลังคำว่า return จะมีหรือไม่มีก็ได้
-}
-```
-
-```js
-function calculate(param1, param2){
-return param1 * param2;
-}
-```
-
-```js
-var result = calculate(10, 2);
-console.log(result); // 20
-```
-
-```js
-function calculate(){
-return 20;
-}
-var result = calculate();
-console.log(result); // 20
-```
-
-## ประโยค return
-```js
-function myFunction (){
- return 1;
- console.log("myFunction");// บรรทัดนี้เส้นทางการทำงานของโปรแกรมจะมาไม่ถึง
-}
-var result = myFunction();
-console.log(result); // 1
-```
-
-```js
-function myFunction (){
- return;
-}
-var result = myFunction();
-console.log(result); // undefined
-```
-
-```js
-function myFunction (){
-console.log("myFunction");
-// จะเสมือนมีประโยค return undefined; วางไว้ตำแหน่งสุดท้าย ก่อนฟังก์ชั่นจบการทำงาน
-}
-var result = myFunction(); // "myFunction"
-console.log(result); // undefined
-```
-
-## ฟังก์ชั่นไร้ชื่อ
-```js
-function (param1,param2){
-return param1 * param2;
-}
-```
-
-## นิพจน์ฟังก์ชั่น
-```js
-var calculate = function (param1,param2){
-return param1 * param2;
-}
-console.log(calculate(10, 2)); // 20
-calculate = 100; // ตัวแปร calculation สามารถแก้ไขให้เป็นค่าอื่นได้
-console.log(calculate); // 100
-```
-
-```js
-var calculate = function calc2(param1,param2){
-return param1 * param2;
-}
-console.log(calculate(10,2)); // 20
-```
-
-## ฟังก์ชั่นคอลแบ็ค
-```js
-function sayHi(){
-console.log("Hi");
-}
-function sayBye(){
-console.log("Bye");
-}
-
-function say(func){
- func(); // เรียกฟังก์ชั่นให้ทำงาน
-}
-say(sayHi); // "Hi"
-say(sayBye); // "Bye"
-```
-
-```js
-function say(func){
- console.log("Say...");
-function sayHi(){
- console.log("Hi");
-}
-return sayHi; // รีเทิร์นฟังก์ชั่น
-}
-var hi = say(); // "Say..."
-hi(); // "Hi"
-```
-
-```js
-function say(func){
- console.log("Say...");
- return function(){ // รีเทิร์นฟังก์ชั่นไร้ชื่อ
- console.log("Hi");
-}
-} // สิ้นสุดการประกาศฟังก์ชั่น
-var hi = say(); // "Say..."
-hi(); // "Hi"
-```
-
-## อ็อบเจ็กต์ arguments
-```js
-function myFunction(param1, param2){
-console.log(param1, param2);
-}
-myFunction(); // undefined undefined
-myFunction(100); // 100 undefined
-myFunction(100,200); // 100 200
-myFunction(100,200,300,400); // 100 200
-```
-
-```js
-function myFunction (param1, param2){
-console.log(arguments);
-}
-myFunction(100,200,300,400); // [100, 200, 300, 400]
-```
-
-```js
-function myFunction(param1,param2){ // ฟังก์ชั่นนี้ไม่เคยถูกเรียกใช้
- console.log("function1 value:", param1, param2);
-}
-myFunction(100, 200); // เรียกใช้ฟังก์ชั่นที่ประกาศอยู่ด้านล่าง
-function myFunction(param){ // จะโอเวอร์ไรด์ทับฟังก์ชั่นที่ประกาศไว้ก่อนหน้านี้
- console.log("function2 value:", param);
-}
-myFunction(100);
-myFunction(100, 200);
-/* แสดงผลลัพธ์เป็น
-"function2 value: 100"
-"function2 value: 100"
-"function2 value: 100" */
-```
-
-## ขอบเขตการมองเห็นของตัวแปร
-```js
-if(true){
-var a = 1; // a มีขอบเขตการมองเห็นแบบโกลบอล
-}
-{
-var b = 2; // b มีขอบเขตการมองเห็นแบบโกลบอล
-}
-console.log(a, b); // 1 2
-```
-
-```html
-
-
-
-
-
-
-
-```
-
-```js
-console.log(NaN, undefined, Infinity); // NaN undefined Infinity
-console.log(window.NaN, window.undefined, window.Infinity); // NaN undefined Infinity
-// ถ้ารันอยู่ใน Node.js
-// console.log(global.NaN, global.undefined, global.Infinity);
-// NaN undefined Infinity
-```
-
-## ฟังก์ชั่นซ้อนฟังก์ชั่น
-```js
-function outerFunc() {
- var value = 0;
- function innerFunc() {
- console.log(++value);
- }
- return innerFunc;
-};
-var func1 = outerFunc(); // บรรทัด a
-func1(); // 1
-func1(); // 2
-
-var func2 = outerFunc(); // บรรทัด b
-func2(); // 1
-func2(); // 2
-```
-
-## Hoist
-```js
-var value = 100;
-```
-
-```js
-function myFunction(num){
- // สามารถมองเห็นตัวแปร value
- console.log(value); // undefined
-
- if(num > 10) {
- var value = num*10; // ประกาศตัวแปร value ที่ตรงนี้ แต่มองเห็นได้ทั่วฟังก์ชั่น
- /* ซอร์สโค้ด */
- } else {
- // ถ้าเงื่อนไขประโยค if เป็นเท็จ ก็จะเข้ามาทำงานที่ else
- // ซึ่งจะเห็นตัวแปร value มีค่าเป็น undefined
- console.log(value); // undefined
- }
-// สามารถมองเห็นตัวแปร value ได้ หลังจากประโยค if …else ทำงานเสร็จสิ้น
- console.log(value);
-}
-```
-
-```js
-function myFunction(num){
- var value; // ประกาศตัวแปร value โดยไม่มีค่าเริ่มต้น จึงทำให้มีค่าเป็น undefined
-console.log(value); // undefined
- if(num > 10) {
- value = num*10; // บรรทัดนี้เป็นเพียงการกำหนดค่าให้กับตัวแปร value
- /* ซอร์สโค้ด */
- } else {
- console.log(value); // undefined
- }
- console.log(value);
-}
-```
-
-```js
-// สามารถมองเห็นตัวแปร value
-console.log(value); // undefined
-if(true) {
-var value = 100; // ประกาศตัวแปรแบบ var
-}
-console.log(value); // 100
-```
-
-```js
-var value; // ประกาศตัวแปร value โดยไม่มีค่าเริ่มต้น จึงทำให้มีค่าเป็น undefined
-console.log(value); // undefined
-if(true) {
- value = 100; // บรรทัดนี้เป็นเพียงการกำหนดค่าให้กับตัวแปร value
-}
-console.log(value); // 100
-```
-
-```js
-// มองเห็นฟังก์ชั่นก่อนการประกาศใช้งาน
-myFunction(); // "Hoisted"
-function myFunction(){
-console.log("Hoisted");
-}
-
-myFunction(); // "Hoisted"
-```
-
-```js
-function outerFunc() {
- innerFunc(); // มองเห็นฟังก์ชั่นก่อนการประกาศใช้งาน
- function innerFunc() {
- console.log("inner function");
- }
-};
-outerFunc(); // "inner function"
-console.log(typeof innerFunc); // undefined
-```
-
-## สตริคท์โหมด
-```js
-"use strict"; // ประกาศโหมดสตริคท์ ด้วยการเขียนไว้ที่ตอนต้นของไฟล์
-var x = 1;
-```
-
-```js
-function myFunction() {
- "use strict"; // เฉพาะฟังก์ชั่นนี้จะอยู่ในโหมดสตริคท์
- var x = 1;
-}
-```
-
-```js
-"use strict";
-x = 1; // เกิด error เพราะไม่ได้ประกาศตัวแปรแบบ var ถ้าอยู่ดี ๆ จะมากำหนดค่าให้ทันทีแบบนี้จะทำไม่ได้
-```
-
-```js
-"use strict";
-function x(a, a) {}; // เกิด error เพราะประกาศพารามิเตอร์ ที่มีชื่อ a ซ้ำกัน
-```
-
-```js
-"use strict";
-var x = 1;
-delete x; // เกิด error ไม่สามารถลบตัวแปรได้
-```
-
-```js
-"use strict";
-delete Object.prototype; //เกิด error เพราะพร็อพเพอร์ตี้ตัวนี้ห้ามลบ
-```
-
-```js
-"use strict";
-var x = 010; // เกิด error ไม่สามารถประกาศแบบนี้ได้
-var y = \010; // เกิด error ไม่สามารถประกาศแบบนี้ได้
-```
-
-```js
-"use strict";
-var obj = {};
-Object.defineProperty(obj, "x", {value:0, writable:false});
-obj.x = 1; // เกิด error เนื่องจากมันเป็นพร็อพเพอร์ตี้ที่อ่านค่าได้อย่างเดียว
-```
-
-```js
-"use strict";
-var obj = {get x() {return 0} };
-obj.x = 1; // เกิด error ไม่สามารถกำหนดค่าให้กับ x ได้
-```
-
-```js
-"use strict";
-var obj = {};
-Object.preventExtensions(obj);
-obj.a= 1; // เกิด error ไม่สามารถเพิ่มพร็อพเพอร์ตี้เข้าไปในอ็อบเจ็กต์ได้
-```
-
-```js
-"use strict";
-function f() { return this; }
-console.log(f()); // undefined
-```
-
-```js
-"use strict";
-var eval = 1; // เกิด error ไม่สามารถใช้ชื่อ eval เป็นตัวแปร
-```
-
-```js
-"use strict";
-var arguments = 1; // เกิด error ไม่สามารถใช้ชื่อ arguments เป็นตัวแปร
-```
-
-```js
-"use strict";
-with (Math){ a = cos(1)}; // เกิด error ไม่สามารถใช้ประโยคคำสั่ง with ได้
-```
-
-```js
-"use strict";
-eval("var x = 1;"); // ประกาศตัวแปร x ด้วย eval()
-x = 2; // เกิด error
-// แบบนี้จะไม่เกิด error
-// eval("var x = 1; x = 2;"); // ไม่เกิด error
-```
-
-```js
-"use strict";
-var implements =1; // เกิด error เพราะ implements คือคำสงวนในโหมดสตริคท์
-```
-
-```js
-"use strict";
-if(true) {
-function myFunction1(){ } // ขอบเขตแบบโลบอล
-}
-
-{
-function myFunction2(){ } // ขอบเขตแบบโลบอล
-
-}
-console.log(typeof myFunction1); // undefined (ถ้าไม่ใช่โหมดสตริคท์จะแสดงค่าเป็น "function")
-console.log(typeof myFunction2); // undefined (ถ้าไม่ใช่โหมดสตริคท์จะแสดงค่าเป็น "function")
-```
-
-
-
-
diff --git a/examples_book/Chapter20.md b/examples_book/Chapter20.md
new file mode 100644
index 0000000..a6a3fe0
--- /dev/null
+++ b/examples_book/Chapter20.md
@@ -0,0 +1,475 @@
+# โค้ดบทที่ 20 มอดูล
+
+## มอดูลคืออะไร
+
+```js
+// -------------- ไฟล์ main.js --------------------
+import "./lib/mylib.js"; // ไม่ได้โหลดอะไรเข้ามา
+```
+
+```module
+// -------------- ไฟล์ lib/mylib.js ---------------
+export var a = 1;
+export var b = 2;
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------------
+import { a, b } from "./lib/mylib.js";
+console.log(a); // 1
+console.log(b); // 2
+```
+
+## เอ็กซ์พอร์ตด้วยการระบุชื่อ
+
+```module
+// -------------- ไฟล์ lib.js --------------------
+export var a = 1;
+export let b = 2;
+export const MY_CONST = 100;
+export function myFunction() {
+ // ซอร์สโค้ด
+}
+export function * myGenerator() {
+ // ซอร์สโค้ด
+}
+export class MyClass {
+ // ซอร์สโค้ด
+}
+```
+
+```module
+// -------------- ไฟล์ example.js --------------------
+const CONST_VALUE = 100; // บรรทัด a -- จะไม่ถูกเอ็กซ์พอร์ตออกไป
+export function square(x) { // บรรทัด b
+ return x * x;
+}
+export function calculate(x, y) { // บรรทัด c
+ return (square(x) + square(y)) * CONST_VALUE;
+}
+function multiply(num1, num2) { // บรรทัด d
+ return num1 * num2;
+}
+export multiply; // บรรทัด e -- เอ็กซ์พอร์ตภายหลัง
+```
+
+```module
+// -------------- ไฟล์ example.js --------------------
+const CONST_VALUE = 100;
+function square(x) {
+ return x * x;
+}
+function calculate(x, y) {
+ return (square(x) + square(y)) * CONST_VALUE;
+}
+function multiply(num1, num2) {
+ return num1 * num2;
+}
+export { square, calculate, multiply }; // เขียนคำว่า export ที่บรรทัดสุดท้ายที่เดียว
+```
+
+```js
+let condition = true;
+if (condition) {
+ export condition; // SyntaxError
+}
+```
+
+## วิธีโหลดมอดูล
+
+```module
+// -------------- ไฟล์ example.js --------------
+const CONST_VALUE = 100;
+function square(x) {
+ return x * x;
+}
+function calculate(x, y) {
+ return (square(x) + square(y)) * CONST_VALUE;
+}
+function multiply(num1, num2) {
+ return num1 * num2;
+}
+export { square, calculate, multiply };
+```
+
+```run.module
+// -------------- ไฟล์ main.js -----------------
+import { square, calculate } from "./example.js";
+console.log(square(2)); // 4
+console.log(calculate(2, 2)); // 800
+square =1; // บรรทัด a -- จะเกิด TypeError
+calculate= 2; // บรรทัด b -- จะเกิด TypeError
+let square = 1; // บรรทัด c -- จะเกิด SyntaxError
+let calculate = 2 ; // บรรทัด d -- จะเกิด SyntaxError
+```
+
+-----
+
+```module
+// -------------- ไฟล์ msg.js -----------------
+export var message = "Hi";
+export function setMessage(msg) {
+ message = msg;
+}
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { message, setMessage } from "./msg.js";
+console.log(message); // "Hi"
+setMessage("Bye"); // บรรทัด a
+console.log(message); // "Bye"
+message = "Good morning"; // บรรทัด b -- จะเกิด TypeError
+```
+
+```run.module
+// ไฟล์ main.js
+import * as lib from "./example.js";
+console.log(lib.square(2)); // 4
+console.log(lib.calculate(2, 2)); // 800
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { square } from "./example.js";
+import { calculate } from "./example.js";
+import { multiply } from "./example.js";
+```
+
+เพื่อให้เข้าใจถึงหลักการทำงานเวลามอดูลถูกโหลดเข้ามา สมมติว่ามีไฟล์มอดูล say.js ดังนี้
+```module
+// -------------- ไฟล์ say.js -----------------
+export const msg = "Hello"; // บรรทัด a
+console.log(msg); // บรรทัด b
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { msg } from "./say.js";
+// แสดงผลลัพธ์
+// "Hello"
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import * as say1 from "./say.js";
+import * as say2 from "./say.js";
+import * as say3 from "./say.js";
+// แสดงผลลัพธ์
+// "Hello"
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { msg } from "./say.js";
+import { msg } from "./say.js"; // เกิด SyntaxError เพราะประกาศชื่อ msg ซ้ำกัน 2 ครั้ง
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { msg as msg1 } from "./say.js";
+import { msg as msg2 } from "./say.js";
+// แสดงผลลัพธ์
+// "Hello"
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+console.log("Hi") // บรรทัด a
+import { msg } from "./say.js"; // บรรทัด b
+// แสดงผลลัพธ์
+// "Hello"
+// "Hi"
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+{
+ import { msg } from "./say.js"; // SyntaxError
+}
+```
+
+## เปลี่ยนชื่อสิ่งที่ต้องการโหลด และเอ็กซ์พอร์ต
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { square, calculate as calc } from "./example.js";
+console.log(square(2)); // 4
+console.log(calc(2, 2)); // 800
+```
+
+```module
+// -------------- ไฟล์ example.js --------------
+const CONST_VALUE = 100;
+export function square(x) {
+ return x * x;
+}
+export function calculate(x, y) {
+ return (square(x) + square(y)) * CONST_VALUE;
+}
+function multiply(num1, num2) {
+ return num1 * num2;
+}
+export { square as sqr, calculate as calc, multiply as mul }; // บรรทัด a
+```
+
+```run.module
+// -------------- ไฟล์ main.js -----------------
+import { sqr, calc, mul } from "./example.js";
+console.log(sqr(2)); // 4
+console.log(calc(2, 2)); // 800
+console.log(mul(2,2)); // 4
+```
+
+## เอ็กซ์พอร์ตแบบดีฟอลต์
+
+```module
+// -------------- ไฟล์ MyFunc.js --------------
+export default function () { /*…*/ }
+```
+
+```module
+// -------------- ไฟล์ MyClass.js --------------
+export default class { /*…*/ }
+```
+
+```module
+// -------------- ไฟล์ MyValue.js --------------
+export default 123;
+```
+
+```module
+// -------------- ไฟล์ MyArrow.js --------------
+export default param => param;
+```
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import func from "./MyFunc.js";
+import _class from "./MyClass.js";
+import value from "./MyValue.js";
+import arrowFunc from "./MyArrow.js";
+```
+
+----
+
+```module
+// -------------- ไฟล์ mydefault.js --------------
+export var value = 100;
+export function square(x) {
+ return x * x;
+}
+export default function(num1, num2) { // ฟังก์ชันไร้ชื่อ
+ return num1 + num2;
+}
+```
+
+```run.module
+// -------------- ไฟล์ main.js -------------------
+import multiply, { value, square } from "./mydefault.js";
+console.log(value); // 100
+console.log(square(2,2)); // 4
+console.log(multiply(2,2)); // 4
+```
+
+## เอ็กซ์พอร์ตซ้ำจากมอดูลอื่น
+
+```module
+// -------------- ไฟล์ mylib.js --------------
+var foo = 1;
+var bar = 2;
+export { foo, bar };
+```
+
+```module
+// -------------- ไฟล์ example.js --------------
+export { foo, bar } from "./mylib.js";
+```
+
+```module
+// -------------- ไฟล์ example.js --------------
+import { foo, bar } from "./mylib.js";
+export { foo, bar };
+```
+
+```module
+// -------------- ไฟล์ example.js --------------
+export { foo as foo1, bar } from "./mylib.js";
+```
+
+```module
+// -------------- ไฟล์ example.js --------------
+export * from "./mylib.js";
+```
+
+หมายเหตุ โค้ดสำหรับเทสในหัวข้อนี้ (ไม่มีในหนังสือ)
+
+```run.module
+// -------------- ไฟล์ main.js --------------
+import { foo, bar } from "./example.js";
+console.log(foo, bar);
+```
+
+## Namespace re-exporting
+
+```js
+export * as ns from "http";
+```
+
+* ลองพิจารณาตัวอย่างไฟล์ 3 อัน ดังต่อไปนี้
+* 1) ไฟล์ name.js จะเป็นมอดูลง่ายๆ เก็บตัวแปร firstname กับ lastname
+
+```module
+// -------------- ไฟล์ name.js ------------------
+const firstname = "Somchai";
+const lastname = "Jaidee";
+export { firstname, lastname }; // ส่งออก firstname กับ lastname
+```
+
+* 2) ไฟล์ student.js เป็นมอดูลอย่างง่าย ข้างในทำการ export ส่งออกตัวแปร age และจะนำเข้ามอดูล name.js พร้อม export ส่องออกมอดูลออกมาเป็นชื่อ person (เปลี่ยนชื่อ namespace)
+
+```module
+// -------------- ไฟล์ student.js ------------------
+const age = 25;
+export {age}; // ส่งออก age
+export * as person from "./name.js" // ส่งออก person
+```
+
+* 3) ไฟล์ myprogram.js เอาไว้รันทดสอบโปรแกรม โดยจะนำเข้ามอดูล student.js ดังตัวอย่าง
+
+```run.module
+// -------------- ไฟล์ myprogram.js ------------------
+import { age, person } from "./student.js"
+console.log(age); // 25
+console.log(person.firstname); // "Somchai"
+console.log(person.lastname); // "Jaidee"
+```
+
+## อ็อบเจ็กต์โกลบอล
+
+```module
+// -------------- ไฟล์ example.js --------------
+Object.prototype.say = function(msg) {
+ console.log(msg);
+};
+```
+
+```run.module
+// -------------- ไฟล์ main.js ------------------
+import "./example.js";
+let a = { };
+a.say("I love JavaScript"); // "I love JavaScript"
+```
+
+## ลองใช้งานมอดูลกันจริงๆ
+
+### วิธีใช้งานมอดูลบนเว็บเบราเซอร์
+
+หมายเหตุ ตัวอย่างหน้า HTML นี้ ต้องมีมอดูล mylib.js ข้างล่างเสียก่อน ไม่เช่นนั้นตัวอย่างหน้าเว็บจะไม่เจอมอดูล
+
+เช่น mylib.js อยู่ในโฟลเดอร์ test_module เราก็อ้างถึงพาธ "./test_modulejs/mylib.js"
+
+```tab.html
+
+
+
+
+
+
+
+```
+
+หมายเหตุ mylib.js สมมติอยู่ในโฟลเดอร์ test_modulejs
+
+```module
+// -------------- ไฟล์ mylib.js ------------------
+export const msg = "I love JavaScript";
+```
+
+```notrun
+
+```
+
+### วิธีใช้งานมอดูลบน Node.js
+
+หมายเหตุ หลายตัวอย่างต่อไปนี้ต้องทดสอบบน Node.js เท่านั้น เพราะบนเว็บเบราเซอร์ยังไม่รองรับ
+
+```js
+// -------------- ไฟล์ mylib.mjs ------------------
+export const msg = "I love JavaScript";
+```
+
+```js
+// -------------- ไฟล์ myapp.mjs ------------------
+import { msg } from "./mylib.mjs";
+console.log(msg);
+```
+
+```module
+// -------------- ไฟล์ mylib.js ------------------
+export const msg = "I love JavaScript";
+```
+
+```run.module
+// -------------- ไฟล์ myapp.js ------------------
+import { msg } from "./mylib.js";
+console.log(msg);
+```
+
+ตัวอย่างไฟล์ package.json
+
+```notrun
+{ "type": "module" }
+```
+
+```notrun
+{
+ "name": "my-awesome-package",
+ "version": "1.0.0"
+ ,"type": "module"
+}
+```
+
+### เสริมเพิ่มเติม
+
+หมายเหตุ โค้ดต่อไปนี้ให้รันบน Node.js
+
+```js
+var http = require("http");
+var fs = require("fs");
+var url = require("url");
+```
+
+```js
+import * as http from "http";
+import * as fs from "fs";
+import * as url from "url";
+```
+
+## โอเปอเรเตอร์ import()
+
+หมายเหตุ โค้ดต่อไปนี้ให้รันบน Node.js
+
+```js
+import("http")
+.then((httpModule) => {
+ console.log(httpModule.maxHeaderSize); // 16384
+});
+```
+
+```js
+const httpModule = await import("http");
+console.log(httpModule.maxHeaderSize); // 16384
+```
+
+## import.meta
+
+```run.module
+console.log(import.meta.url); // "file:///c:/javascript/mymodule.js"
+```
\ No newline at end of file
diff --git a/examples_book/Chapter3.md b/examples_book/Chapter3.md
deleted file mode 100644
index a7f4daf..0000000
--- a/examples_book/Chapter3.md
+++ /dev/null
@@ -1,296 +0,0 @@
-
-# บทที่ 3 ทบทวนประโยคคำสั่งเบื้องต้น
-
-## บล็อก
-```js
-{
- var a = 2; // ประโยคคำสั่ง 1
- a++; // ประโยคคำสั่ง 2
- console.log(a); // ประโยคคำสั่ง 3
-}
-```
-
-```js
-if (true) {
- var a = 2; // ประโยคคำสั่ง 1
- a++; // ประโยคคำสั่ง 2
- console.log(a); // ประโยคคำสั่ง 3
-}
-```
-
-## ประโยคคำสั่ง while
-```js
-var i = 0;
-while (i < 3) {
- console.log(i);
- i++;
-}
-/* แสดงผลลัพธ์
-0
-1
-2 */
-```
-
-## ประโยคคำสั่ง do …while
-```js
-var i = 0;
-do{
- console.log(i);
- i++;
-} while (i < 3);
-/* แสดงผลลัพธ์
-0
-1
-2 */
-```
-
-## ประโยคคำสั่ง for
-```js
-for(var i=0; i<3; i++){
- console.log(i);
-}
-/* แสดงผลลัพธ์
-0
-1
-2 */
-```
-
-## ประโยคคำสั่ง continue
-```js
-for(var i=0; i<3; i++){
- if(i<=1){
- continue; // ข้ามประโยคคำสั่งที่เหลือ ไปทำงานรอบถัดไปแทน
- }
- console.log(i);
-}
-// แสดงผลลัพธ์
-// 2
-```
-
-## ประโยคคำสั่ง break
-```js
-for(var i=0; i<3; i++){
- if(i==2){
- break;
- }
- console.log(i);
-}
-/* แสดงผลลัพธ์
-0
-1 */
-```
-
-## ประโยคคำสั่ง label
-```js
-outer: for(var i=0; i < 2; i++) { // บรรทัด a
- console.log("i: ", i);
- for (var j=0; j < 3; j++ ) {
- if ( j == 1){
- continue outer; // บรรทัด b
- }
- console.log("j: ", j);
- }// สิ้นสุดประโยคคำสั่ง for
-} // สิ้นสุดประโยคคำสตั่ง for ที่ได้ติดฉลาก outer: for
-/* แสดงผลลัพธ์
-"i: 0"
-"j: 0"
-"i: 1"
-"j: 0" */
-```
-
-```js
-outer: while(true){ // บรรทัด a
- for (var i=0; i < 3; i++ ) {
- if ( i == 1){
- break outer; // บรรทัด b
- }
- console.log("i: ", i);
- }// สิ้นสุดประโยคคำสั่ง for
-}// สิ้นสุดประโยคคำสั่ง while
-// แสดงผลลัพธ์
-// "i: 0"
-outer: while(true){ // บรรทัด a
- for (var i=0; i < 3; i++ ) {
- if ( i == 1){
- break outer; // บรรทัด b
- }
- console.log("i: ", i);
- }// สิ้นสุดประโยคคำสั่ง for
-}// สิ้นสุดประโยคคำสั่ง while
-// แสดงผลลัพธ์
-// "i: 0"
-```
-
-## ประโยคคำสั่ง if
-```js
-// var i = 1;
-// var i = 2;
-// var i = 3;
-
-if(i == 1)
-console.log("if statement");
-else if(i == 2)
- console.log("else if statement");
-else
- console.log("else statement");
-```
-
-## ประโยคคำสั่ง switch
-```js
-// var i = 1;
-// var i = 2;
-// var i = 3;
-switch (i) {
- case 1:
- console.log("case1"); // ถ้า i มีค่าเป็น 1 ก็จะมาทำประโยคนี้
- break; // ออกจากประโยค switch
- case 2:
- console.log("case2"); // ถ้า i มีค่าเป็น 2 ก็จะมาทำประโยคนี้
- break; // ออกจากประโยค switch
- default:
- console.log("case_default"); // ถ้า i ไม่ใช่ 1 กับ 2 ก็จะมาทำประโยคนี้
-
-}
-```
-
-```js
-switch (1) {
- case 1:
- console.log("case1");
- case 2:
- console.log("case2");
- default:
- console.log("case_default");
-}
-/* แสดงผลลัพธ์เป็น
-"case1"
-"case2"
-"case_default" */
-```
-
-```js
-switch (1) {
- case 1:
- case 2:
- default:
- console.log("case_default");
-}
-// แสดงผลลัพธ์เป็น
-// "case_default"
-```
-
-## โอเปอเรเตอร์แบบเงื่อนไข
-```js
-// var condition = true;
-// var condition = false;
-var value = condition ? "foo" : "bar";
-console.log(value); // "foo" หรือ "bar"
-```
-
-```js
-// var condition = true;
-// var condition = false;
-var value;
-if(condition){
-value = "foo";
-} else {
- value = "bar";
-}
-console.log(value); // "foo" หรือ "bar"
-```
-
-## ปการจัดการความผิดพลาด
-```js
-throw "Error"; // โยน exception เป็นชนิดข้อมูลสตริง
-throw 100; // โยน exception เป็นชนิดข้อมูลตัวเลข
-throw true; // โยน exception เป็นชนิดข้อมูลบูลีน
-throw new Object(); // โยน exception เป็นชนิดข้อมูลอ็อบเจ็กต์
-throw new Error("Error") // โยน exception เป็นชนิดข้อมูลอ็อบเจ็กต์
-```
-
-```js
-console.log(x); // ReferenceError
-```
-
-```js
-new Error(["ข้อความ error"])
-```
-
-```js
-throw new SyntaxError ("Syntax error");
-```
-
-## ประโยคคำสั่งจัดการความผิดพลาด
-```js
-try {
- console.log(x); // บรรทัด a
- x++; // บรรทัด b
-} catch (e) {
- console.log(typeof e); // "object"
- console.log(e.message); // "x is not defined"
- console.log(e.name); // "ReferenceError"
-}
-console.log("Last statement"); // บรรทัด c
-/* แสดงผลลัพธ์เป็น
-"object"
-"x is not defined"
-"ReferenceError"
-"Last statement" */
-```
-
-```js
-try {
-throw 42; // โยน exception ออกมาเอง
-console.log(42); // เส้นทางการทำงานของโปรแกรมจะมาไม่ถึง
-} catch (e) {
- console.log(e); // 42
-}
-console.log("Last statment");
-/* แสดงผลลัพธ์
-42
-"Last statment" */
-```
-
-```js
-try {
-console.log(x); // บรรทัด a
-} catch (e){
- console.log(e.message); // "x is not defined"
-} finally {
- console.log("finally");
-}
-console.log("Last statement");
-/* แสดงผลลัพธ์
-"x is not defined"
-"finally";
-"Last statement" */
-```
-
-```js
-try {
-console.log("no error");
-} catch (e){
- console.error(e.message);
-} finally{
- console.log("finally");
-}
-console.log("Last statement ");
-/* แสดงผลลัพธ์
-"no error"
-"finally";
-"Last statement" */
-```
-
-```js
-function foo(){
-try {
- return "foo";
-} finally{
- console.log("finally");
-}
-}
-console.log(foo());
-/* แสดงผลลัพธ์
-"finally";
-"foo"; */
-```
diff --git a/examples_book/Chapter4.md b/examples_book/Chapter4.md
deleted file mode 100644
index ce43c80..0000000
--- a/examples_book/Chapter4.md
+++ /dev/null
@@ -1,838 +0,0 @@
-# บทที่ 4 ทบทวนอ็อบเจ็กต์
-
-## วิธีสร้างอ็อบเจ็กต์อย่างง่าย
-
-```js
-var font = {};
-```
-
-```js
-var font = {
- color: "red" // คีย์ชื่อ color : ข้อมูลจะเป็นสตริง "red"
- ,myFunction: function (param){ // คีย์ชื่อ myFunction : ข้อมูลจะเป็นเมธอด (ฟังก์ชั่น)
- // ซอร์สโค้ดของเมธอด
-}
-,option: { // คีย์ชื่อ option : ข้อมูลจะเป็นอ็อบเจ็กต์
- value: 1
-}
-};
-```
-
-
-## การเข้าถึงพร็อพเพอร์ตี้
-```js
-var obj = {
- a: 1 // กำหนดให้ a มีค่าตั้งต้นเป็น 1
-,myFunction : function() {
- console.log("call myFunction");
-}
-};
-obj.a = 100; // กำหนดให้ obj.a มีค่าเป็น 100
-console.log(obj.a); // 100
-console.log(typeof obj.myFunction); // "function"
-obj.myFunction(); // "call myFunction"
-```
-
-## การใช้วงเล็บเหลี่ยม
-```js
-var student = {
-"First name": "Somchai"
-,"Last name": "Jaidee"
-,"Who are you": function(){
- console.log("I’m a student");
-}
-,nickname: "Tom"
-};
-console.log(student["First name"]); // "Somchai"
-var lastName = "Last name";
-console.log(student[lastName]); // "Jaidee"
-student["Who are you"](); // "I’m a student"
-console.log(student.nickname); // "Tom"
-console.log(student["nickname"]); // "Tom"
-```
-
-```js
-var obj = {
-1: 1
-,true: 2
-,null : 3
-,undefined: 4
-};
-console.log(obj[1 + 0]); // 1
-console.log(obj[true && true]); // 2
-console.log(obj[null]); // 3
-console.log(obj[undefined]); // 4
-```
-
-```js
-var obj = {
-{}: 1 // เกิด error ไม่สามารถใช้อ็อบเจ็กต์เป็นคีย์ได้โดยตรง
-};
-```
-
-## เพิ่มพร็อพเพอร์ตี้เข้าไปทีหลัง
-```js
-var obj = {};
-obj.a = 1; // เพิ่มพร็อพเพอร์ตี้ที่เป็นตัวแปร a
-obj[1]=100; // เพิ่มพร็อพเพอร์ตี้ที่มีคีย์เป็นตัวเลข 1
-obj["property name"]= 200; // เพิ่มพร็อพเพอร์ตี้ที่มีคีย์เป็นสตริง "property name"
-obj.myFunction = function(){ // เพิ่มพร็อพเพอร์ตี้ที่เป็นเมธอด
-console.log("to do something");
-};
-
-console.log(obj.a); // 1
-console.log(obj[1]); // 100
-console.log(obj["property name"]); // 200
-obj.myFunction(); // "to do something"
-```
-
-```js
-var obj = { };
-var key = { };
-obj[key] = 100; // มีคีย์เป็นอ็อบเจ็กต์ว่าง
-console.log(obj[key]); // 100
-```
-
-## การส่งค่าให้ตัวแปร
-```js
-function myFunction(param1, param2){
- param1.a = 3; // pass by reference
- param2 = 200; // pass by value
-}
-var obj = {a:1, b:2}, value = 100;
-myFunction(obj, value);
-console.log(obj.a); // 3
-console.log(value); // 100
-```
-
-```js
-var obj1 = {a:1, b:2};
-var obj2 = obj1; // บรรทัด a -- pass by reference
-obj2.a = 3; // บรรทัด b
-console.log(obj1.a); // 3
-var value1 = 1;
-var value2 = value1; // บรรทัด d -- pass by value
-value2 = 3; // บรรทัด e
-console.log(value1); // 1
-```
-
-## การเปรียบเทียบความเท่ากัน
-```js
-console.log({a:1} == {a:1}); // false
-console.log({a:1} === {a:1}); // false
-```
-
-```js
-var a = 1, b = 1;
-console.log(a == b); // true
-console.log(a === b); // true
-```
-
-## this
-```js
-var obj = {
- a: 1
- ,foo: function(){
- return 2;
- }
- ,bar: function(){
- console.log(this.a);
-}
-,zoo: function(){
- console.log(this.foo());
-}
-};
-obj.bar(); // 1
-obj.zoo(); // 2
-```
-
-```js
-var obj = {
- foo: function (){
- this.a = 1; // เพิ่มตัวแปร a เข้าไปในอ็อบเจ็กต์
- console.log(this.a );
-}
-,bar: function(){
- console.log(this.a);
-}
-};
-
-obj.foo(); // 1
-obj.bar(); // 1
-console.log(obj.a); // 1
-```
-
-## การผูก this ไว้กับอ็อบเจ็กต์
-```js
-var obj1 = {};
-var obj2 ={
-a: 1
-,bar : function(){
- console.log("this.a =", this.a);
- obj1.foo = function(){
- console.log("this.a =", this.a);
- } // สิ้นสุดการประกาศฟังก์ชั่น foo()
- } // สิ้นสุดการประกาศฟังก์ชั่น bar()
-};
-obj2.bar(); // "this.a = 1"
-obj1.foo(); // "this.a = undefined"
-```
-
-## this ในฟังก์ชั่น
-```js
-//"use strict";
-function myFunction() {
- return this;
-}
-var obj = myFunction();
-console.log(typeof obj);
-// แสดงผลลัพธ์เป็น
-// undefined (ถ้าเป็นโหมดสตริคท์)
-// "object" (ถ้าไม่ใช่โหมดสตริคท์)
-```
-
-## เมธอด call() apply() และ bind()
-```js
-var obj1 = {
- value: 20
-};
-var obj2 = {
-myFunction: function(param1, param2){
- var value = this.value; // this จะชี้ไปยัง obj1
- console.log(param1, param2, value);
-}
-}
-obj2.myFunction(1, 10); // 1 10 undefined
-obj2.myFunction.call(obj1, 1, 10); // 1 10 20
-obj2.myFunction.apply(obj1, [1, 10]); // 1 10 20
-var f = obj2.myFunction.bind(obj1, 1, 10);
-f(); // 1 10 20
-```
-
-## พร็อพเพอร์ตี้แอคเซสเซอร์
-```js
-var font = { color: "red" } ;
-font.color = "blue" ;
-```
-
-```js
-var font = {
- set color(param){ // ประกาศเมธอด setter โดยมีพารามิเตอร์ ได้เพียงตัวเดียว
- this.col = param; // กำหนดค่าให้กับข้อมูลภายในอ็อบเจ็กต์
-}
-} ;
-font.color = "blue"; // แก้ไขค่าได้
-console.log(font.color) // undefined
-```
-
-```js
-var font = {
- col: "red"
- ,get color(){ // ประกาศเมธอด getter โดยไม่ต้องมีพารามิเตอร์
- return this.col; // รีเทิร์นข้อมูลภายในอ็อบเจ็กต์ออกไป
-}
-};
-console.log(font.color); // "red"
-font.color = "blue"; // ไม่มีผลอะไรเกิดขึ้น หรือจะเกิด TypeError ในโหมดสตริคท์
-console.log(font.color); // "red"
-```
-
-```js
-var font = {
-col: "red"
- ,set color(param){
- this.col = param;
-}
-,get color(){
- return this.col;
-}
-} ;
-console.log(font.color); // "red"
-font.color = "blue";
-console.log(font.color); // "blue"
-```
-
-## โอเปอเรเตอร์ delete
-```js
-var obj = {x:1 ,y:2} ;
-console.log(delete obj.x); // true
-console.log(delete obj["y"]); // true
-console.log(obj); // {}
-var a = 1;
-console.log(delete a); // false หรือเกิด SyntaxError ในโหมดสตริคท์
-```
-
-```js
-console.log(delete Number.MAX_VALUE); // false หรือเกิด TypeError โหมดสตริคต์
-```
-
-```js
-var a = [1, "Hi"];
-console.log(a.length); // 2
-console.log(delete a[0]); // true
-console.log(delete a[1]); // true
-console.log(a[0]); // undefined
-console.log(a[1]); // undefined
-console.log(a.length); // 2
-```
-
-## Descriptor
-```js
-var obj1 = {};
-Object.defineProperty(obj1, "foo", { // อ็อบเจ็กต์ descriptor
- value: 100
- ,writable: true
-});
-console.log(obj1.foo); // 100
-console.log(Object.getOwnPropertyDescriptor(obj1,"foo")); // รีเทิร์น descriptor
-// { value: 100, writable: true, enumerable: false, configurable: false }
-var obj2 = {};
-Object.defineProperties(obj2, {
- "foo": { // อ็อบเจ็กต์ descriptor
- value: "fooValue",
- writable: true
- }
- ,"bar": { // อ็อบเจ็กต์ descriptor
- value: "barValue",
- writable: false
- }
- // พร็อพเพอร์ตี้อื่น ๆ
-});
-console.log(obj2.foo, obj2.bar); // "fooValue barValue"
-console.log(Object.getOwnPropertyDescriptor(obj2,"foo")); // รีเทิร์น descriptor
-// { value: "fooValue", writable: true, enumerable: false, configurable: false }
-console.log(Object.getOwnPropertyDescriptor(obj2,"bar")); // รีเทิร์น descriptor
-// { value: "barValue", writable: false, enumerable: false, configurable: false }
-```
-
-## ฟังก์ชั่นคอนสตรัคเตอร์
-```js
-function Car(color) {
-this.color = color;
-return true;
-}
-var redCar = new Car("red");
-var blueCar = new Car("blue");
-//… สร้างอ็อบเจ็กต์ใหม่ได้เรื่อยด้วยโอเปอเรเตอร์ new
-console.log(redCar.color); // "red"
-console.log(blueCar.color); // "blue"
-```
-
-```js
-function Car(color) {
-this.color = color; // ถ้าเป็นโหมดสตริคท์จะเกิด error ขึ้นได้
-return true;
-}
-var blueCar = Car("blue"); // เป็นการเรียกฟังก์ชั่นธรรดา
-console.log(blueCar); // true
-```
-
-```js
-function Car(color) {
-console.log("constructor");
-}
-var redCar = new Car(); // "constructor"
-var blueCar = new Car; // "constructor"
-```
-
-## เมธอด Object.create()
-```js
-var car = {
- drive: function(){ console.log("driving a car") ; }
-}
-var redCar = Object.create(car);
-var blueCar = Object.create(car,
-{ // เพิ่มพร็อพเพอร์ตี้เข้าไป ด้วยการระบุ descriptor
- foo: { writable: true, configurable: true, value: "fooValue" } // descriptor
- ,bar:{ writable: true, configurable: true, value: "barValue" } // descriptor
-}
-);
-// สร้างอ็อบเจ็กต์ใหม่ได้เรื่อย ๆ ด้วย Object.create()
-// …
-redCar.drive(); // "driving a car"
-blueCar.drive(); // "driving a car"
-console.log(blueCar.foo); // "fooValue"
-console.log(blueCar.bar); // "barValue"
-```
-
-```js
-var car = { }
-var redCar = Object.create(car);
-var blueCar = Object.create(car);
-car.drive = function() {
- console.log("driving a car");
-}
-redCar.drive(); // "driving a car"
-blueCar.drive(); // "driving a car"
-```
-
-```js
-console.log( Object.getPrototypeOf(redCar) === car ); // true (เพราะโปรโตไทป์คือ car)
-console.log( Object.getPrototypeOf(blueCar) === car ); // true (เพราะโปรโตไทป์คือ car)
-```
-
-```js
-var obj1 = Object.create(null); // ไม่มีโปรโตไทป์
-console.log(obj1); // {}
-console.log(Object.getPrototypeOf(obj1)); // null
-
-var obj2 = Object.create(Object.prototype); // จะเหมือนสร้างอ็อบเจ็กต์ด้วยวิธีนี้ var obj = {}
-console.log(obj2); // {}
-console.log(Object.getPrototypeOf(obj2) === Object.prototype); // true
-```
-
-## prototype
-```js
-function Car(color) {
-this.color = color;
-}
-var redCar = new Car("red");
-console.log( Object.getPrototypeOf(redCar) === Car.prototype); // true
-```
-
-```js
-function Car(color) {
-this.color = color;
-}
-Car.prototype.drive = function() {
-console.log("Drive a", this.color, "car"); // this จะชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
-};
-var redCar = new Car("red");
-redCar.drive(); // " Drive a red car"
-var blueCar = new Car("blue");
-blueCar.drive(); // " Drive a blue car"
-console.log( Object.getPrototypeOf(redCar) === Car.prototype); // true
-console.log( Object.getPrototypeOf(blueCar) === Car.prototype); // true
-```
-
-```js
-function Car(color) {
-this.color = color;
-}
-Car.drive = function() {
-console.log("driving a car");
-};
-Car.drive(); // "driving a car"
-var redCar = new Car("red");
-console.log(typeof redCar.drive); // undefined
-```
-
-## การสืบทอดสมาชิกหลายระดับชั้น
-```js
-var extend = {
-drive: function(){
- console.log("Drive a", this.color, "car");
-}
-}
-function Car(color) {
-this.color = color;
-}
-Car.prototype = extend; // บรรทัด a
-Car.prototype.stop = function(){ // บรรทัด b
-console.log("Stop a", this.color, "car");
-};
-var redCar = new Car("red");
-console.log( Object.getPrototypeOf(redCar) === extend); // true
-redCar.drive(); // "Drive a red car"
-redCar.stop(); // "Stop a red car"
-```
-
-```js
-function Car(color) {}
-Car.prototype.drive = function() {
-console.log("Drive a", this.color, "car"); // this ชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
-};
-function RedCar(color){
- this.color = color;
-}
-RedCar.prototype = Object.create(Car.prototype); // บรรทัด a
-console.log( Object.getPrototypeOf(RedCar.prototype) === Car.prototype); // true
-RedCar.prototype.stop = function(){
-console.log("Stop a", this.color, "car"); // this ชี้ไปยังอ็อบเจ็กต์ที่ถูกสร้างขึ้นมา
-}
-var redCar = new RedCar("red");
-console.log( Object.getPrototypeOf(redCar) === RedCar.prototype); // true
-redCar.drive(); // "Drive a red car"
-redCar.stop(); // "Stop a red car"
-```
-
-## โอเปอรเตอร์ instanceof
-```js
-function Foo() { }
-var obj = new Foo();
-console.log(obj instanceof Foo); // true
-console.log(Object.getPrototypeOf(obj) === Foo.prototype); // true
-```
-
-```js
-function Foo() { }
-var obj = new Foo();
-console.log(obj instanceof Foo); // true
-console.log(Object.getPrototypeOf(obj) === Foo.prototype); // true
-
-console.log(obj instanceof Object); // true
-console.log(Foo.prototype instanceof Object); // true
-console.log(Object.getPrototypeOf(Foo.prototype) === Object.prototype); // true
-console.log(Object.getPrototypeOf(obj) === Object.prototype); // false
-```
-
-## prototype ที่มีอยู่ในภาษา
-```js
-console.log( Object.getPrototypeOf(function(){}) === Function.prototype); // true
-console.log( Object.getPrototypeOf([]) === Array.prototype); // true
-console.log( Object.getPrototypeOf({}) === Object.prototype); // true
-console.log( Object.getPrototypeOf('') === String.prototype); // true
-console.log( Object.getPrototypeOf(true) === Boolean.prototype); // true
-console.log( Object.getPrototypeOf(1) === Number.prototype); // true
-console.log(function(){} instanceof Function); // true
-console.log([] instanceof Array); // true
-console.log({} instanceof Object); // true
-console.log(''instanceof String); // false
-console.log(true instanceof Boolean); // false
-console.log(1 instanceof Number); // false
-```
-
-```js
-// ฟังก์ชั่น
-Function.prototype.sayMsg = function(msg) {
- console.log("Function say:", msg);
-};
-function myFunction(){}
-myFunction.sayMsg("Hello");// " Function say: Hello"
-// อาร์เรย์
-Array.prototype.sayMsg = function(msg) {
- console.log("Array say:", msg);
-};
-[].sayMsg("Hello"); // "Array say: Hello"
-// อ็อบเจ็กต์
-Object.prototype.sayMsg = function(msg) {
- console.log("Object say:", msg);
-};
-var obj = {};
-obj.sayMsg("Hello"); // "Object say: Hello"
-({}).sayMsg("Hello"); // "Object say: Hello"
-// สตริง
-String.prototype.sayMsg = function(msg) {
- console.log("String say:", msg);
-};
-"123".sayMsg("Hello"); // "String say: Hello"
-// บูลีน
-Boolean.prototype.sayMsg = function(msg) {
- console.log("Boolean say:", msg);
-}
-true.sayMsg("Hello"); // "Boolean say: Hello"
-// ตัวเลข
-Number.prototype.sayMsg = function(msg) {
- console.log("Number say:", msg);
-}
-var num = 123;
-num.sayMsg("Hello"); // "Number say: Hello"
-(123).sayMsg("Hello"); // "Number say: Hello"
-```
-
-## โอเปอเรเตอร์ in
-```js
-var obj = {x: 1, y: 2};
-console.log("x" in obj); // true
-console.log("xyz" in obj); // false (อ็อบเจ็กต์ไม่มีพร็อพเพอร์ตี้ xyz)
-var a = ["a", "b", "c"];
-console.log(0 in a); // true (อาร์เรย์นี้มีอินเด็กซ์ 0)
-console.log(5 in a); // false (อาร์เรย์ไม่มีอินเด็กซ์ 5)
-console.log("1" in a); // true (อาร์เรย์นี้มีอินเด็กซ์ 1)
-console.log("length" in a); // true (อาร์เรย์จะมี length เป็นพร็อพเพอร์ตี้)
-```
-
-```js
-var parent = {x:1};
-var obj = Object.create(parent);
-console.log("x" in obj); // true
-```
-
-## ประโยคคำสั่ง for …in
-```js
-function Font() {
- this.color = "red";
- this.size = 200;
-}
-var coordinate = {x: 1, y: 1, z: 1}
-Font.prototype = Object.create(coordinate);
-Font.prototype.myFunction = function(){};
-var font = new Font();
-font[1] = "fontValue";
-for(var prop in font) {
-console.log(prop);
-}
-/* แสดงผลลัพธ์เป็น
-"1"
-"color "
-"size "
-"myFunction"
-"x "
-"y "
-"z " */
-```
-
-```js
-function Font() {
- this.color = "red";
- this.size = 200;
-}
-var coordinate = {x: 1, y: 1, z: 1}
-Font.prototype = Object.create(coordinate);
-Font.prototype.myFunction = function(){};
-var font = new Font();
-font[1] = "fontValue";
-for(var prop in font) {
- if(font.hasOwnProperty( prop ) ) { // เข้าถึงคีย์ที่อยู่ในอ็อบเจ็กต์เท่านั้น
- console.log("font." + prop, "=", font[prop]);
-}
-}
-/* แสดงผลลัพธ์เป็น
-"font.1 = fontValue"
-"font.color = red"
-"font.size = 200" */
-```
-
-## Object.preventExtensions() กับ Object.isExtensions()
-```js
-var obj1 = {};
-var obj2 = Object.preventExtensions(obj1);
-console.log(obj1 === obj2); // true
-
-obj1.a = 1; // จะเพิกเฉย แต่ถ้าอยู่ในโหมดสตริคท์จะเกิด TypeError
-
-var obj3 = Object.create(obj1);
-console.log(obj3); // {}
-obj3.a = 1; // เพิ่มพร็อพเพอร์ตี้เข้าไปได้
-console.log(Object.getPrototypeOf(obj3) === obj1); // true
-```
-
-```js
-var obj = {};
-console.log(Object.isExtensible(obj)); // true
-Object.preventExtensions(obj);
-console.log(Object.isExtensible(obj)); // false
-```
-
-## Object
-```js
-var obj1 = new Object(1234);
-var obj2 = new Object(); // อ็อบเจ็กต์ว่าง
-var obj3 = new Object(undefined); // อ็อบเจ็กต์ว่าง
-var obj4 = new Object(null); // อ็อบเจ็กต์ว่าง
-var obj5 = Object(1); // เรียกแบบฟังก์ชั่น (ค่าอากิวเมนต์เป็นอะไรก็ได้)
-console.log(typeof obj5); // "object"
-```
-
-## Boolean
-```js
-var obj = new Boolean(true);
-console.log(typeof obj); // "object"
-var b = Boolean(true);
-console.log(typeof b); // "boolean"
-console.log(b); // true
-console.log(obj == b); // true
-console.log(obj === b); // false
-```
-
-```js
-var false1 = Boolean(); // false
-var false2 = Boolean(false); // false
-var false3 = Boolean(0); // false
-var false4 = Boolean(-0); // false
-var false5 = Boolean(null); // false
-var false6 = Boolean(''); // false
-var false7 = Boolean(NaN); // false
-var false8 = Boolean(undefined); // false
-var true1 = Boolean(true); // true
-var true2 = Boolean("Hi"); // true
-var true3 = Boolean("true"); // true
-var true4 = Boolean("false"); // true
-var true5 = Boolean([]); // true
-var true6 = Boolean({}); // true
-var true7 = Boolean(true4); // true
-```
-
-## Number
-```js
-var obj = new Number(1);
-console.log(typeof obj); // "object"
-var n1 = Number("1"); // รับค่าเป็นสตริงก็ได้เช่นกัน
-var n2 = Number("a"); // "a" ไม่ใช่ตัวเลข จึงทำให้ตัวแปร n2 มีค่าเป็น NaN
-console.log(typeof n1, typeof n2); // "number number"
-console.log(n1, n2); // 1 NaN
-console.log(obj == n1); // true
-console.log(obj === n1); // false
-```
-
-## String
-```js
-var str1 = new String("MyString");
-console.log(typeof str1); // "object"
-console.log(str1 === "MyString"); // false
-var str2 = String("MyString");
-console.log(typeof str2); // "string"
-console.log(str2 === "MyString"); // true
-console.log(str1 == str2); // true
-```
-
-## Array
-```js
-var array1 = Array( 3 ); // เรียกแบบฟังก์ชั่น
-console.log(array1.length); // 3
-console.log(array1); // [ <3 empty slots> ]
-var array2 = new Array(3);
-console.log(array2.length); // 3
-console.log(array2); // [ <3 empty slots> ]
-```
-
-## เมธอดของสตริง
-```js
-console.log( " Learning JavaScript ".trim() ); // แสดงผลเป็น "Learning JavaScript"
-```
-
-```js
-console.log( "foo_foo_foo_".indexOf("foo") ); // 0
-console.log("foo_foo_foo_".lastIndexOf("foo") ); // 8
-```
-
-```js
-"use strict";
-var str = "MyString";
-console.log(str.length) // 8
-str.length = 0; // TypeError (ถ้าไม่ใช่โหมดสตริคท์จะไม่เกิด error แต่จะเพิกเฉย)
-str.func = function(){}; // TypeError (ถ้าไม่ใช่โหมดสตริคท์จะไม่เกิด error แต่จะเพิกเฉย)
-```
-
-## เมธอดของอาร์เรย์
-```js
-var array = ["a","b","c","d"];
-var str = array.join("->");
-console.log(str); // "a->b->c->d"
-```
-
-```js
-var array = [];
-array.push("a","b","c","d"); // เพิ่มสมาชิกกี่ตัวก็ได้
-console.log(array); // ["a", "b", "c", "d"]
-console.log(array.pop()); // "d"
-console.log(array); // ["a", "b", "c"]
-```
-
-```js
-var array = ["a","b","c","d"];
-console.log(array.indexOf("c" )); // 2
-console.log(array.indexOf("e" )); // -1
-```
-
-```js
-var array = ["a","b","c","d"];
-var result = array.some( function matcher(value, index, arrayObj){
- // value คือค่าสมาชิกของอาร์เรย์
- // index คืออินเด็กซ์ของอาร์เรย์
- // arrayObj คือ ["a", "b", "c", "d"]
- return value == "c";
-} );
-console.log(result) // true
-```
-
-```js
-var array = ["a","b","c","d"];
-array.forEach(function (value, index, arrayObj) {
- // value คือค่าสมาชิกของอาร์เรย์
- // index คืออินเด็กซ์ของอาร์เรย์
- // arrayObj คือ ["a", "b", "c", "d"]
- console.log("a[", index, "] = ", value);
-});
-/* แสดงผลลัพธ์
-"a[ 0 ] = a"
-"a[ 1 ] = b"
-"a[ 2 ] = c"
-"a[ 3 ] = d" */
-```
-
-## Regular Expression
-```js
-var myRegex = new RegExp("Hello+");
-console.log(myRegex.toString()); // /Hello+/
-```
-
-```js
-var myRegex = /Hello+/;
-// ข้อความ regex ก็คืออ็อบเจ็กต์ตัวหนึ่ง
-// จึงสามารถแชร์ใช้งานเมธอด RegExp.prototype.toString()
-console.log(/Hello+/.toString()); // /Hello+/
-```
-
-## เมธอด test() กับ exec()
-```js
-console.log( /Hello+/.test("Hellooooo") ); // true
-console.log( (new RegExp("Hello+")).test("Hellooooo") ); // true
-```
-
-```js
-var result = /(foo).(bar)/.exec("0123foo_bar");
-console.log(result.index); // 4
-console.log(result[0]); // "foo_bar"
-console.log(result[1]); // "foo"
-console.log(result[2]); // "bar"
-console.log(result.input); // "0123foo_bar"
-```
-
-## สตริงกับ regex
-```js
-console.log("012Hellooooo".search(/Hello+/)); // 3
-var result = "Hellooooo Hello".match(/Hello+/g);
-console.log(result); // ["Hellooooo", "Hello"]
-console.log(result.length); // 2
-
-var str = "Hellooooo".replace(/Hello+/,"Bye");
-console.log(str); // "Bye"
-var split = "1,2,3".split(/,/);
-console.log(split); // ["1", "2", "3"]
-```
-
-## ค่าแฟล็ก
-```js
-var regex = /Hello+/gi;
-console.log(regex.lastIndex); // 0
-console.log(regex.source); // "Hello+"
-console.log(regex.global); // true
-console.log(regex.ignoreCase); // true
-console.log(regex.multiline); // false
-```
-
-```js
-var myRegex = /Hello+/g;
-var str = "01Hello Hellooo89";
-var result = myRegex.exec(str); // ค้นหาครั้งแรก
-console.log(result[0]); // "Hello"
-console.log(myRegex.lastIndex); // 7
-myRegex.exec(str); // ค้นหาครั้งที่ 2
-console.log(result[0]); // "Hello"
-console.log(myRegex.lastIndex); // 15
-myRegex.exec(str); // ค้นหาครั้งที่ 3
-console.log(result[0]); // "Hello"
-console.log(myRegex.lastIndex); // 0
-myRegex.exec(str); // ค้นหาครั้งที่ 4
-console.log(result[0]); // "Hello"
-console.log(myRegex.lastIndex); // 7
-```
-
-```js
-console.log( /Hello+/g === /Hello+/g); // false
-/Hello+/g.exec("Hello Hello Hello"); // บรรทัด 2
-console.log(/Hello+/g.lastIndex); // 0 -- บรรทัด 3
-```
-
-## ตัวอย่างการใช้ regex
-```js
-var myRegex = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
-console.log(myRegex.test("xxxxxx.yyyyyy_zzzzz@abc.com")); // true
-```
-
-```js
-var myRegex = /^(\-?|\+?)\d*$/;
-console.log(myRegex.test("-987")); // true
-```
-
diff --git a/examples_book/Chapter5.md b/examples_book/Chapter5.md
deleted file mode 100644
index 239655f..0000000
--- a/examples_book/Chapter5.md
+++ /dev/null
@@ -1,297 +0,0 @@
-# บทที่ 5 ฟีเจอร์ใหม่ของตัวเลข สตริง และ regex
-
-## การแปลงสตริงเป็นตัวเลข
-```js
-console.log(Number.parseInt("15")); // 15
-console.log(Number.parseFloat("123.5")); // 123.5
-console.log(Number.parseInt("abc")); // NaN (แปลงเป็นเลขจำนวนเต็มไม่ได้)
-console.log(Number.parseFloat("abc")); // NaN (แปลงเป็นเลขทศนิยมไม่ได้)
-```
-
-```js
-console.log(parseInt("15")); // 15
-console.log(parseFloat("123.5")); // 123.5
-console.log(typeof window.parseInt); // "function" (บนเว็บบราวเซอร์)
-console.log(typeof window.parseFloat); // "function" (บนเว็บบราวเซอร์)
-//console.log(typeof global.parseInt); // "function" (บน Node.js)
-//console.log(typeof global.parseFloat); // "function" (บน Node.js)
-```
-
-## เลขฐาน 2 ฐาน 8 และฐาน 16
-```js
-console.log(Number("100")); // 100
-console.log(Number("0b111")); // 7
-console.log(Number("0o45")); // 37
-console.log(Number("0x17")); // 23
-// ใช้ Number.parseInt()
-console.log(Number.parseInt("100")); // 100
-console.log(Number.parseInt("0b111")); // 0
-console.log(Number.parseInt("0o45")); // 0
-console.log(Number.parseInt("0x17")); // 23
-```
-
-## เมธอด Number.isFinite() กับ Number.isNaN()
-```js
-console.log(isFinite(2560)); // true
-console.log(isFinite("2560")); // true
-console.log(Number.isFinite(2560)); // true
-console.log(Number.isFinite("2560")); // false
-console.log(isNaN(NaN)); // true
-console.log(isNaN("NaN")); // true
-console.log(Number.isNaN(NaN) ); // true
-console.log(Number.isNaN("NaN")); // false
-console.log(typeof window.isFinite); // "function" (บนเว็บบราวเซอร์)
-console.log(typeof window.isNaN); // "function" (บนเว็บบราวเซอร์)
-//console.log(typeof global.isFinite); // "function" (บน Node.js)
-//console.log(typeof global.isNaN); // "function" (บน Node.js)
-```
-
-## เมธอด Number.isInteger() กับ Number.isSafeInteger()
-```js
-console.log(Number.isInteger(34.6)); // false
-console.log(Number.isInteger(34.0)); // true (เขียนเป็นเลข 34.0 ก็จริง แต่จะถูกจัดเก็บเป็นเลข 34)
-console.log(Number.isInteger(34)); // true
-```
-
-```js
-console.log(Math.pow(2,53)); // 9007199254740992
-console.log(Math.pow(2,53) + 1); // 9007199254740992 -- บรรทัด 2
-console.log(Math.pow(2,53) + 2); // 9007199254740994 -- บรรทัด 3
-console.log(Math.pow(2,53) + 3); // 9007199254740996 -- บรรทัด 4
-console.log(Math.pow(2,53) * 100); // 900719925474099200 -- บรรทัด 5
-```
-
-```js
-var upper = Number.MAX_SAFE_INTEGER;
-console.log(Number.isSafeInteger(upper)); // true
-console.log(Number.isInteger(upper)); // true
-var outside_upper = upper + 1;
-console.log(Number.isSafeInteger(outside_upper)); // false
-console.log(Number.isInteger(outside_upper)); // true
-var lower = Number.MIN_SAFE_INTEGER;
-console.log(Number.isSafeInteger(lower)); // true
-console.log(Number.isInteger(lower)); // true
-var outside_lower = lower - 1;
-console.log(Number.isSafeInteger(outside_lower)); // false
-console.log(Number.isInteger(outside_lower)); // true
-```
-
-## ค่าคงที่ Number.EPSILON
-```js
-console.log(Number.EPSILON); // 2.220446049250313e-16
-```
-
-## เมธอด repeat()
-```js
-console.log( "JavaScript".repeat(3) ); // "JavaScriptJavaScriptJavaScript"
-```
-
-## เมธอด startsWith(), endsWith(), กับ includes()
-```js
-console.log("JavaScript".startsWith("Java")); // true (มีคำว่า "Java" อยู่ตำแหน่งแรก)
-console.log("JavaScript".startsWith("world")); // false (ไม่มีคำว่า "world" อยู่ตำแหน่งแรก)
-console.log("JavaScript".endsWith("Script")); // true (มีคำว่า "Script" อยู่ตำแหน่งสุดท้าย)
-console.log("JavaScript".endsWith("Hello")); // false (ไม่มีคำว่า "Hello" อยู่ตำแหน่งสุดท้าย)
-console.log("JavaScript".includes("va")); // true (มีคำว่า "va" อยู่ในสตริง)
-console.log("JavaScript".includes("same")); // false (ไม่มีคำว่า "same" อยู่ในสตริง)
-```
-
-```js
-console.log("JavaScript".startsWith("ri", 6)); // true
-console.log("JavaScript".endsWith("va", 4)); // true
-console.log("JavaScript".includes("ri", 2)); // true
-```
-
-## ยูนิโคด
-```js
-var a = "ABC";
-console.log(a.length); // 3
-console.log(a.codePointAt(0)); // 65
-console.log(a.codePointAt(1)); // 66
-console.log(a.codePointAt(2)); // 67
-console.log(a.codePointAt(3)); // undefined
-```
-
-```js
-var thai = "กขค";
-console.log(thai.length); // 3
-console.log(thai.codePointAt(0).toString(16)); // e01
-console.log(thai.codePointAt(1).toString(16)); // e02
-console.log(thai.codePointAt(2).toString(16)); // e04
-```
-
-```js
-console.log(String.fromCodePoint(42)); // "*"
-console.log(String.fromCodePoint(65, 66, 67)); // "ABC"
-console.log(String.fromCodePoint(0xe01, 0xe02, 0xe04) ); // "กขค"
-// สามารถส่งค่าอากิวเมนต์เป็นสตริงที่เขียนด้วยตัวเลข ก็สามารถทำได้เช่นกัน
-console.log(String.fromCodePoint("97", "98", "99")); // "abc"
-console.log(String.fromCodePoint("0xe07", "0xe08", "0xe09") ); // "งจฉ"
-//String.fromCodePoint('_'); // RangeError
-//String.fromCodePoint(Infinity); // RangeError
-//String.fromCodePoint(-1); // RangeError
-//String.fromCodePoint(NaN); // RangeError
-```
-
-```js
-console.log("\u{e01}"); // "ก"
-console.log("\u{e01}\u{e02}\u{e04}ABC"); // "กขคABC"
-```
-
-```js
-console.log("\u0e01"); // "ก"
-```
-
-```js
-console.log("\u20BB7"); // " 7"
-console.log("\u{20BB7}"); // "𠮷"
-```
-
-```js
-console.log("a".length); // 1
-console.log("ก".length); // 1
-var char = "𤭢"; // "\u{24b62}" -- เป็นอักษรกลุ่ม CJK
-console.log(char.length); // 2
-```
-
-## การตั้งชื่อด้วยตัวอักษรพิเศษยูนิโคด
-```js
-var \u{e01} = 100; // จะเหมือนเขียน var ก = 100
-console.log(\u{e01}); // 100
-console.log("\u{e01}"); // "ก"
-var ข = "JavaScript";
-console.log(ข); // "JavaScript"
-```
-
-```js
-var \u0e01 = 100; // จะเหมือนเขียน var ก = 100
-console.log(\u0e01); // 100
-```
-
-## เมธอด normalize()
-```js
-function toCodePoint(str){ // ฟังก์ชั่นแสดงค่า code point ของสตริงออกทางหน้าคอนโซล
- var concat = "";
- for(var i = 0; i < str.length; i++ ){
- concat += "0x" + str.codePointAt(i).toString(16) + " ";
- }
- console.log(concat);
-}
-
-// U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE
-// U+0373: GREEK SMALL LETTER ARCHAIC SAMPI
-var str = "\u{1E9B}\u{0373}";
-var s1= str.normalize("NFC");
-toCodePoint(s1); // 0x1e9b 0x373
-
-var s2= str.normalize("NFD");
-toCodePoint(s2); // 0x17f 0x307 0x373
-
-var s3 = str.normalize("NFKC");
-toCodePoint(s3); // 0x1e61 0x373
-
-var s4 = str.normalize("NFKD");
-toCodePoint(s4); // 0x73 0x307 0x373
-```
-
-## แฟล็ก u
-```js
-var str = "𠮷";
-console.log(str.length); // 2
-console.log(/^.$/.test(str)); // false
-```
-
-```js
-var str = "𠮷";
-console.log(/^.$/u.test(str)); // true
-```
-
-```js
-var result1 = "𠮷กขคง𤭢".match(/[\s\S]/gu);
-console.log(result1.length); // 6
-
-// ถ้าไม่ใช้แฟล็ก u จะนับตัวอักษรผิด
-var result2 = "𠮷กขคง𤭢".match(/[\s\S]/g);
-console.log(result2.length); // 8
-```
-
-## แฟล็ก y
-```js
-var str = "foo1_foo2_foo3"; // สตริงที่จะค้นหา
-var regex = /foo\d_?/; // ไม่มีแฟล็ก
-var regexG = /foo\d_?/g; // แฟล็ก g
-var regexY = /foo\d_?/y; // แฟลก y
-var result = regex.exec(str);
-var resultG = regexG.exec(str);
-var resultY = regexY.exec(str);
-console.log(result[0]); // "foo1_"
-console.log(resultG[0]); // "foo1_"
-console.log(resultY[0]); // "foo1_"
-console.log(regex.lastIndex); // 0
-console.log(regexG.lastIndex); // 5
-console.log(regexY.lastIndex); // 5
-```
-
-```js
-result = regex.exec(str);
-resultG = regexG.exec(str),
-resultY = regexY.exec(str);
-console.log(result[0]); // "foo1_"
-console.log(resultG[0]); // "foo2_"
-console.log(resultY[0]); // "foo2_"
-console.log(regex.lastIndex); // 0
-console.log(regexG.lastIndex); // 10
-console.log(regexY.lastIndex); // 10
-```
-
-```js
-var str = "foo1_foo2_foo3";
-var regex = /foo\d_?/;
-var regexG = /foo\d_?/g; // แฟล็ก g
-var regexY = /foo\d_?/y; // แฟลก y
-
-regex.lastIndex = 1;
-regexG.lastIndex = 1;
-regexY.lastIndex = 1;
-var result = regex.exec(str);
-var resultG = regexG.exec(str);
-var resultY = regexY.exec(str);
-
-console.log(result[0]); // "foo1_"
-console.log(resultG[0]); // "foo2_"
-console.log(resultY); // มีค่าเป็น null เพราะค้นหาไม่เจอข้อความ
-```
-
-```js
-var myRegex = /foo+/y;
-console.log(myRegex.sticky); // true
-myRegex.sticky = 1; // TypeError ไม่สามารถแก้ไขค่าได้ มีไว้อ่านอย่างเดียว
-```
-
-## RegExp
-```js
-var myRegex = /foo/g;
-var regex2 = new RegExp(myRegex);
-console.log(regex2.test("foo")); // true
-console.log(myRegex === regex2); // false
-```
-
-```js
-var myRegex = /foo/i;
-var regex2 = new RegExp(myRegex, "g");
-console.log(myRegex.test("FOO")); // true (ไม่สนใจตัวพิมพ์ใหญ่พิมพ์เล็ก)
-console.log(regex2.test("FOO")); // false
-```
-
-```js
-var myRegex = new RegExp("foo", "y"); // จะเสมือนเขียน var myRegex = /foo/y;
-console.log(myRegex.exec("foo_abc")); // ["foo"]
-```
-
-## พร็อพเพอร์ตี้ flags
-```js
-var myRegex = /foo/i;
-console.log(myRegex.source); // "foo"
-console.log(myRegex.flags); // "i"
-```
-
diff --git a/examples_book/Chapter6.md b/examples_book/Chapter6.md
deleted file mode 100644
index 9f8a140..0000000
--- a/examples_book/Chapter6.md
+++ /dev/null
@@ -1,478 +0,0 @@
-
-# บทที่ 6 การประกาศตัวแปร และการกำหนดค่า
-
-## การประกาศตัวแปรแบบ let
-```js
-function calculate(num){
- if (num > 10) {
- let value = num*10; // ประกาศตัวแปรแบบ let
- // ซอร์สโค้ดส่วนที่เหลือ
- console.log(value); // มองเห็นตัวแปร value
- } else {
- // มองไม่เห็นตัวแปร value
- }
- // มองไม่เห็นตัวแปร value
-}
-```
-
-## การใช้ตัวแปรแบบ var เปรียบเทียบกับ let
-```js
-var a = 1;
-console.log(a); // 1
-{
- var a = 2;
- console.log(a); // 2
-}
-console.log(a); // 2
-```
-
-```js
-var a = 1;
-console.log(a); // 1
-{
- let a = 2;
- console.log(a); // 2
-}
-console.log(a); // 1
-```
-
-## var กับ let ในประโยควนลูป
-```js
-for(var i=0; i < 10; i++) { // วนลูป 10 ครั้ง
-// ซอร์สโค้ด
-}
-// สามารถเข้าถึงตัวแปร i ที่ตอนนี้มีค่าเป็น 10 ได้
-console.log(i); // 10
-```
-
-```js
-for(let i=0; i < 10; i++) { // วนลูป 10 ครั้ง
-// ซอร์สโค้ด
-}
-console.log(i); // จะเกิด ReferenceError เพราะมองไม่เห็นตัวแปร i
-```
-
-```js
-var array = [];
-for(var i=0; i < 5; i++){
- // เพิ่มฟังก์ชั่นเข้าไป เพื่อให้เป็นสมาชิกของอาร์เรย์
- array.push( function () { console.log(i) } );
-}
-array.forEach( function(printLog) {
- // เรียกสมาชิกของอาร์เรย์ที่เป็นฟังก์ชั่น ให้ทำงาน
- printLog(); // จะแสดงค่าของตัวแปร i เป็นเลข 5 ทั้งหมดห้ารอบด้วยกัน
-});
-/*แสดงผลลัพธ์เป็น
-5
-5
-5
-5
-5
-*/
-```
-
-```js
-var array = [];
-for(var i=0; i< 5; i++){
- array.push(
- function(item) {
- // รีเทิร์นฟังก์ชั่นออกไป เพื่อให้เป็นสมาชิกของอาร์เรย์
- return function() { console.log(item); } ;
- }( i ) // ใช้เทคนิค IIFE
-);
-}
-array.forEach( function(printLog) {
- printLog(); // รอบแรกแสดงค่าเป็น 0 รอบที่สองเป็น 1 รอบที่สามเป็น 2 …จนถึงรอบที่ห้าจะแสดงค่าเป็น 4
-});
-/*แสดงผลลัพธ์เป็น
-0
-1
-2
-3
-4
-*/
-```
-
-```js
-var array = [];
-for(let i=0; i<5; i++){ // ประกาศตัวแปร i แบบ let
- array.push( function () { console.log(i); } );
-}
-array.forEach(function(printLog){
- printLog(); // รอบแรกแสดงค่าเป็น 0 รอบที่สองเป็น 1 รอบที่สามเป็น 2 …จนถึงรอบที่ห้าจะแสดงค่าเป็น 4
-});
-/*แสดงผลลัพธ์เป็น
-0
-1
-2
-3
-4
-*/
-```
-
-## สรุปขอบเขตการมองเห็นตัวแปรแบบ let
-```js
-console.log(count); // undefined หรือเกิด ReferenceError (ขึ้นอยู่กับจาวาสคริปต์เอ็นจิ้น)
-let count = 89; // จะมองเห็นตัวแปร count ตั้งแต่จุดนี้เป็นต้นไป
-if(true){
-console.log(count); // 89
-}
-```
-
-```js
-var count = 89;
-let count = 12; // เกิด error เพราะประกาศชื่อตัวแปรซ้ำกัน
-```
-
-```js
-var count = 89;
-if(true) {
-let count = 12; // จะไม่เกิด error
-// บรรทัดต่อจากนี้ไป สามารถมองเห็นตัวแปร count ที่ประกาศแบบ let เท่านั้น
-console.log(count); // 12
-}
-// มองเห็นและเข้าถึงตัวแปร count ที่อยู่นอกบล็อกของ if
-console.log(count); // 89
-```
-
-## ตัวแปรค่าคงที่
-```js
-const MAX_COUNT = 100; // ประกาศถูกต้องตามไวยากรณ์
-const MAX_VALUE; // เกิด error เพราะไม่ได้กำหนดค่าตั้งต้นให้แต่แรก
-const MESSAGE = "Hello"; // ประกาศถูกต้องตามไวยากรณ์
-MESSAGE = "Bye"; // เกิด error เพราะไปแก้ไขตัวแปรค่าคงที่ภายหลังประกาศใช้งานแล้ว ซึ่งจะทำไม่ได้
-```
-
-```js
-console.log(count); // undefined หรือเกิด ReferenceError (ขึ้นอยู่กับจาวาสคริปต์เอ็นจิ้น)
-const count = 89; // จะมองเห็นตัวแปร count ตั้งแต่จุดนี้เป็นต้นไป
-if(true){
-console.log(count); // 89
-}
-```
-
-```js
-var message = "foo";
-let count = 100;
-// ประกาศตัวแปรค่าคงที่
-const message = "bar"; // เกิด error เพราะประกาศตัวแปรชื่อซ้ำกัน
-const count = 1; // เกิด error เพราะประกาศตัวแปรชื่อซ้ำกัน
-```
-
-```js
-var message = "foo";
-let count = 100;
-if(true) {
- const message = "bar";
-const count = 1;
-// มองเห็นตัวแปร message และ count ที่ประกาศเป็นค่าคงที่เท่านั้น
-console.log(message); // "bar"
-console.log(count); // 1
-}
-// มองเห็นและเข้าถึง message และ count ที่อยู่นอกบล็อกของ if
-console.log(message); // "foo"
-console.log(count); // 100
-```
-
-## ข้อควรระวังเกี่ยวกับตัวแปรค่าคงที่
-```js
-const obj = {
- value: 100
-};
-obj.value = 1; // สามารถแก้ไขค่าพร็อพเพอร์ตี้ภายในอ็อบเจ็กต์ได้
-console.log(obj.value); // 1
-obj = 10; // จะเกิด error เพราะแก้ไขตัวแปรค่าคงที่ไม่ได้
-```
-
-```js
-for (const i=0; i < 10; i++) { // จะ error เพราะนิพจน์ i++ ได้ไปแก้ไขตัวแปร i ซึ่งเป็นค่าคงที่ มันจะทำไม่ได้
-// ซอร์สโค้ด
-}
-```
-
-```js
-let obj = {
- key1: true,
- key2: true,
-};
-for (const key in obj) {
- console.log(key);
-}
-/*แสดงผลลัพธ์เป็น
-"key1"
-"key2"
-*/
-```
-
-```js
-for (const value of [1, 2]) {
- console.log(value);
-}
-/*แสดงผลลัพธ์เป็น
-1
-2
-*/
-```
-
-## ดีสตรัคเตอร์ริ่ง
-```js
-let f = {
- color: "red"
-,size: "200"
-,icon: "small"
-,style: "normal"
-, lang: "thai"
-} ;
-// การแกะข้อมูลภายในอ็อบเจ็กต์ เพื่อไปกำหนดค่าให้กับตัวแปรทีละตัว จะดูยุ่งยากมาก
-let color = f.color, size = f.size, icon = f.icon, style=f.style, lang= f.lang;
-console.log(color, size, icon, style, lang); // "red 200 small normal thai"
-```
-
-```js
-let f = ["red", "200", "small", "normal", "thai"];
-// การนำข้อมูลจากอาร์เรย์ เพื่อไปกำหนดค่าให้กับตัวแปรทีละตัว จะดูยุ่งยากมาก
-let color = f[0], size = f[1], icon = f[2], style =f[3], lang=f[4];
-console.log(color, size, icon, style, lang); // "red 200 small normal thai"
-```
-
-## ดีสตรัคเตอร์ริ่งจากอ็อบเจ็กต์
-```js
-let font = {
- color: "red"
-,size: 200
-} ;
-let fontColor = font.color, fontSize = font.size;
-```
-
-```js
-let font = {
- color: "red"
-,size: 200
-} ;
-// กำหนดค่าให้กับตัวแปร ด้วยวิธีดีสตรัคเตอร์ริ่ง
-// จะเสมือนประกาศแบบนี้
-// let fontColor = font.color, fontSize = font.size;
-let {color: fontColor, size: fontSize } = font;
-// จะประกาศตัวแปรเป็นแบบ var หรือ const ก็ทำได้เช่นกัน
-// var {color: fontColor, size: fontSize } = font;
-// const {color: fontColor, size: fontSize } = font;
-console.log(fontColor); // "red" จะมีค่าเท่ากับ font.color
-console.log(fontSize); // 200 จะมีค่าเท่ากับ font.size
-```
-
-```js
-let font = {
- color: "red"
-,size: 200
-};
-// จะเสมือนประกาศแบบนี้
-// let color = font.color, size = font.size;
-let {color, size} = font; // กำหนดค่าให้กับตัวแปร ด้วยวิธีดีสตรัคเตอร์ริ่งแบบย่อ
-console.log(color); // "red
-console.log(size); // 200
-```
-
-```js
-let font = {
- color: "red"
-,size: 200
-};
-let { color, size, style } = font;
-console.log(color); // "red"
-console.log(size); // 200
-console.log(style); // undefined
-```
-
-## อ็อบเจ็กต์ซ้อนอ็อบเจ็กต์
-```js
-let font = {
- color: "red"
-,size: 200
-,text : {
- name: "thai"
-}
-} ;
-// จะเสมือนประกาศแบบนี้
-// let color = font.color, size = font.size, name = font.text.name;
-let {color, size, text: {name} } = font;
-console.log(color, size, name); // "red 200 thai"
-```
-
-## ดีสตรัคเตอร์ริ่งจากอาร์เรย์
-```js
-let font = [ "red", "bold", "thai"];
-// กำหนดค่าให้กับตัวแปร ด้วยวิธีดีสตรัคเตอร์ริ่ง
-// จะเสมือนประกาศตัวแปรแบบนี้
-// let color = font[0], style = font[1];
-let [ color, style] = font;
-// จะประกาศตัวแปรเป็นแบบ var หรือ const ก็ทำได้เช่นกัน
-// var [color, style] = font;
-// const [color, style] = font;
-console.log(color); // "red" จะมีค่าเท่ากับ font[0]
-console.log(style); // "bold" จะมีค่าเท่ากับ font[1]
-```
-
-```js
-let font = [ "red", "bold", "thai"];
-let [ , style , ] = font;
-console.log(style); // "bold"
-```
-
-## อาร์เรย์ซ้อนอาร์เรย์
-```js
-let font = [ "red", ["200", "thai"], "bold"];
-let [ color, [size, lang], style, option] = font;
-console.log(color); // "red"
-console.log(color === font[0]); // true
-console.log(size); // "200"
-console.log(size === font[1][0]); // true
-console.log(lang); // "thai"
-console.log(lang === font[1][1]); // true
-console.log(style); // "bold"
-console.log(style === font[2]); // true
-console.log(option); // undefined
-```
-
-```js
-let font = [ "red", ["200", "thai"], "bold"];
-let [ color, option , style] = font;
-console.log(color, style); // "red bold"
-console.log(option[0]); // "200"
-console.log(option[1]); // "thai"
-console.log(option === font[1]); // true (เพราะมันอ้างอิงไปที่อาร์เรย์ตำแหน่งเดียวกัน)
-```
-
-## ข้อควรรู้เพิ่มเติมของวิธีดีสตรัคเตอร์ริ่ง
-```js
-let action = {
- save: true
-,undo: false
-};
-let save, undo;
-{save, undo} = action; // เกิด error
-```
-
-```js
-let action = {
- save: true
-,undo: false
-};
-let save, undo;
-({save, undo} = action); // ใส่วงเล็บครอบทั้งประโยคจะไม่เกิด error
-console.log(save, undo); // true false
-```
-
-```js
-let font = [ "red", "bold"];
-let color, style;
-[color, style] = font; // ไม่เกิด error
-console.log(color, style); // "red bold"
-```
-
-## การระบุค่าดีฟอลต์ให้กับตัวแปร
-```js
-let { color, size = 200 } = {color:"red"}
-console.log(color) // "red"
-console.log(size) // 200
-```
-
-```js
-let [ , ,lang = "thai"] = []
-console.log(lang); // "thai"
-```
-
-## ข้อมูลผสมระหว่างอ็อบเจ็กต์และอาร์เรย์
-```js
-let action = {
- save : "success",
- undo : "none",
- option : ["move", "stop", "slow"]
-};
-// กำหนดค่าให้กับตัวแปรด้วยวิธีดีสตรัคเตอร์ริ่ง
-let {save, undo, option: [ moveOption, stopOption]} = action;
-console.log(save, undo, moveOption, stopOption); // "success none move stop"
-```
-
-```js
-let action = {
- save : "succes",
- undo : "none",
- option : ["move", "stop", "slow"]
-};
-
-let {save, undo, option} = action; // บรรทัด a
-console.log(save, undo); // "success none"
-console.log(option[0]); // "move"
-console.log(option[1]); // "stop"
-console.log(option[2]); // "slow"
-console.log(option === action.option); // true (เพราะมันอ้างอิงไปที่อาร์เรย์ตำแหน่งเดียวกัน)
-```
-
-## การสลับข้อมูล
-```js
-let a = 1, b =2
-let temp = a; // temp เป็นตัวแปรชั่วคราวที่ใช้เก็บค่าของ a เอาไว้ก่อน
-a = b;
-b = temp;
-console.log(a); // 2
-console.log(b); // 1
-```
-
-```js
-let a = 1, b =2;
-[b , a] = [a , b]; // ดีสตรัคเตอร์ริ่งจากอาร์เรย์
-console.log(a); // 2
-console.log(b); // 1
-```
-
-```js
-let a = 1, b = 2, c = 3, d = 4;
-console.log(a, b, c, d); // 1 2 3 4
-[d, c, b ,a] = [a, b, c, d]; // ดีสตรัคเตอร์ริ่งจากอาร์เรย์
-console.log(a, b, c, d); // 4 3 2 1
-```
-
-
-## รับค่าจากฟังก์ชั่น
-```js
-function myFunctin(){
- return {a:1 ,b: 2};
-}
-let {a, b} = myFunctin();
-console.log(a, b); // 1, 2
-```
-
-```js
-function myFunctin(){
- return [1, 2] ;
-}
-let [a, b] = myFunctin();
-console.log(a, b); // 1 2
-```
-
-## ข้อมูล JSON
-```js
-// เป็นข้อมูล JSON ซึ่งเขียนด้วยเทมเพลตสตริง (บทที่ 8)
-let jsonText = `{
- "file": "index.html",
- "menu": [
- {"value": "New", "onclick": "createDoc"},
- {"value": "Open", "onclick": "openDoc"}
- ]
-}`;
-
-let jsonObj = JSON.parse(jsonText); // อ็อบเจ็กต์ที่ใช้เป็นตัวแทนของ JSON
-console.log(jsonObj);
-/* แสดงผลลัพธ์เป็น
-{ file: "index.html",
- menu:
- [ { value: "New", onclick: "createDoc" },
- { value: "Open", onclick: "openDoc" } ] }
-*/
-let {file, menu:[ menu1, menu2] } = jsonObj;
-console.log(file); // "index.html"
-console.log(menu1.value); // "New"
-console.log(menu1.onclick); // "createDoc"
-console.log(menu2.value); // "Open"
-console.log(menu2.onclick); // "openDoc"
-```
diff --git a/examples_book/Chapter7.md b/examples_book/Chapter7.md
deleted file mode 100644
index d5f92ac..0000000
--- a/examples_book/Chapter7.md
+++ /dev/null
@@ -1,890 +0,0 @@
-
-# บทที่ 7 ฟังก์ชั่น
-
-## นิพจน์ฟังก์ชั่น
-```js
-let f1 = function (){
- // ซอร์สโค้ด
-}
-const f2 = function (){
- // ซอร์สโค้ด
-}
-var f3 = function (){
- // ซอร์สโค้ด
-}
-
-f1();
-f2();
-f3();
-```
-
-## พารามิเตอร์แบบดีฟอลต์
-```js
-function sendMessage(ipaddress, message = "Hello" , callback = function() {}) {
-// ถ้าไม่ส่งค่าอากิวเมนต์มาให้พารามิเตอร์ message จะมีค่าเป็น "Hello"
-/* ถ้าไม่ส่งค่าอากิวเมนต์มาให้พารามิเตอร์ callback จะได้เป็นฟังก์ชั่นว่างที่ไม่ได้ทำงานอะไรเลย
- แต่จะรีเทิร์นค่าเป็น undefined */
-console.log(ipaddress, message, callback() );
-}
-```
-
-```js
-// ใช้ค่าดีฟอลต์ของพารามิเตอร์ message กับ callback
-sendMessage("127.0.0.1"); // "127.0.0.1 Hello undefined"
-// ใช้ค่าดีฟอลต์ของพารามิเตอร์ callback
-sendMessage("127.0.0.1", "Good bye!"); // "127.0.0.1 Good bye! undefined"
-// ไม่ได้ใช้ค่าดีฟอลต์อะไรเลย
-sendMessage("127.0.0.1", "Good bye!", function() {
- return "toDoSomething";
-});
-```
-
-```js
-function sendMessage(ipaddress, message = "Hello", callback = function() {}) {
-console.log(ipaddress, message, callback() );
-}
-// จะใช้ค่าดีฟอลต์ของพารามิเตอร์ callback เพียงตัวเดียวเท่านั้น
-sendMessage("127.0.0.1", null, undefined); // "127.0.0.1 null undefined"
-```
-
-## ตำแหน่งการวางพารามิเตอร์แบบดีฟอลต์
-```js
-function sendMessage(ipaddress, message = "Hello" , callback) {
-console.log(ipaddress, message, typeof callback);
-}
-```
-
-```js
-// จะใช้ค่าดีฟอลต์ของพารามิเตอร์ message เพียงตัวเดียวเท่านั้น
-sendMessage("127.0.0.1"); // "127.0.0.1 Hello undefined"
-```js
-
-```js
-sendMessage("127.0.0.1", "Hello", function() {}); // "127.0.0.1 Hello function"
-// พารามิเตอร์ message จะได้ค่าเป็น null
-sendMessage("127.0.0.1",null, function() {}); // "127.0.0.1 null function"
-// พารามิเตอร์ message จะใช้ค่าดีฟอลต์
-sendMessage("127.0.0.1", undefined, function() {}); // "127.0.0.1 Hello function"
-```
-
-```js
-function sendMessage(ipaddress, callback, message = "Hello") {
-console.log(ipaddress, message, typeof callback);
-}
-sendMessage("127.0.0.1", function() {}); // "127.0.0.1 Hello function"
-```
-
-## ประโยชน์ของพารามิเตอร์แบบดีฟอลต์
-```js
-function sendMessage(ipaddress, message , callback) {
-message = message || "Hello";
-callback = callback || function() { return "callback";};
-console.log(ipaddress, message, callback());
-}
-// message กับ callback จะใช้ค่าดีฟลอต์
-sendMessage("127.0.0.1"); // "127.0.0.1 Hello callback"
-sendMessage("127.0.0.1", 0, null); // "127.0.0.1 Hello callback"
-sendMessage("127.0.0.1", NaN, ''); // "127.0.0.1 Hello callback"
-```
-
-```js
-let value = 1;
-function getMessage() {
- return "My_message_" + (value++);
-}
-function createCallback() {
- return function() {
- return "callback";
- };
-}
-function sendMessage(message = getMessage(), callback = createCallback() ) {
-console.log(message, callback());
-}
-sendMessage(); // "My_message_1 callback"
-sendMessage(); // "My_message_2 callback"
-```
-
-```js
-function add(value) {
- return value + 10;
-}
-
-function calculate(a, b = add(a), c = a * b) {
- console.log(a, b, c) ;
-}
-
-calculate(1,1,1); // 1 1 1
-calculate(10); // 10 20 200
-calculate(20); // 20 30 600
-calculate(30); // 30 40 1200
-```
-
-## พารามิเตอร์แบบเรสต์
-```js
-function iterateItem(item){
- console.log(item); // แสดงค่าอากิวเมนต์ตัวแรกออกมาก่อน
- let result = 0;
-let len = arguments.length;
- for(let i=1; i {
-return value;
-};
-// เรียกใช้ฟังก์ชั่นได้เหมือนปกติธรรมดา
-console.log(arrowFunc(122)); // 122
-```
-
-### ตัวอย่าง 2
-```js
-// เหมือนในตัวอย่างที่ 1 แต่การเขียนจะสั้นและกระชับกว่า
-// ไม่ต้องมีเครื่องหมายปีกกาครอบบอดี้ฟังก์ชั่น รวมทั้งไม่ต้องเขียนประโยคคำสั่ง return
-let arrowFunc = value => value;
-console.log(arrowFunc(122)); // 122
-/* จะเสมือนเขียนเป็น
-let arrowFunc = function(value){
- return value;
-};*/
-let arrowFunc2 = value => console.log(value);
-arrowFunc2(122); // 122
-/* จะเสมือนเขียนเป็น
-let arrowFunc2 = function(value){
- return console.log(value);
-};*/
-```
-
-### ตัวอย่าง 3
-```js
-// ฟังก์ชั่นลูกศรที่ไม่มีการประกาศพารามิเตอร์อะไรเลย
-let arrowFunc = () => 122;
-console.log(arrowFunc()); // 122
-/* จะเสมือนเขียนเป็น
-let arrowFunc = function(){
- return 122;
-};*/
-```
-
-### ตัวอย่าง 4
-```js
-// ฟังก์ชั่นลูกศรที่ไม่มีพารามิเตอร์ และตัวบอดี้ของฟังก์ชั่นก็ว่างเปล่า
-let arrowFunc = () => {};
-arrowFunc();
-// จะเสมือนเขียนเป็น
-// var arrowFunc = function(){};
-```
-
-### ตัวอย่าง 5
-```js
-// ใส่เครื่องหมายวงเล็บ เพื่อครอบอ็อบเจ็กต์ที่ถูกรีเทิร์นออกมา
-let getFont = () => ( { color: "red", size: 200 } );
-console.log(getFont()); // {color: "red", size: 200}
-/* จะเสมือนเขียนเป็น
-let getFont = function(){
- return {color: "red", size: 200};
-};*/
-```
-
-### ตัวอย่าง 6
-```js
-// มีวงเล็บครอบพารามิเตอร์เอาไว้
-let sum = (val1, val2, val3) => val1 + val2 + val3;
-console.log(sum(1,2,3)); // 6
-/* จะเสมือนเขียนเป็น
-let sum = function(val1, val2, val3){
- return val1 + val2 +val3;
-};*/
-```
-
-### ตัวอย่าง 7
-```js
-// ฟังก์ชั่นลูกศรที่ใช้พารามิเตอร์แบบดีฟอลต์
-let sum = (val1 = 1, val2 = 2, val3 = 3) => val1 + val2 + val3;
-console.log(sum()); // 6
-/* จะเสมือนเขียนเป็น
-let sum = function(val1 = 1, val2 = 2, val3 = 3){
- return val1 + val2 +val3;
-};*/
-```
-
-
-### ตัวอย่าง 8
-```js
-// ฟังก์ชั่นลูกศรที่ใช้พารามิเตอร์แบบเรสต์
-let max = (...value) => Math.max(...value);
-console.log(max(1, 2, 3, 6)); // 6
-/* จะเสมือนเขียน
-let max = function(...value){ // พารามิเตอร์แบบเรสต์
- return Math.max(...value); // โอเปอเรเตอร์สเปรด
-};*/
-```
-
-
-## ฟังก์ชั่นลูกศรต่างจากฟังก์ชั่นธรรมดาอย่างไร
-```js
-let arrowFunc = value => value;
-console.log(typeof arrowFunc); // "function"
-console.log(arrowFunc instanceof Function); // true
-```
-
-
-
-```js
-let arrowFunc = () => {};
-console.log(arrowFunc.name); // จะแสดงชื่อ "arrowFunc" (ขึ้นอยู่กับจาวาสคริปต์เอ็นจิ้น)
-```
-
-## อ็อบเจ็กต์ arguments ในฟังก์ชั่นลูกศร
-```js
-// เขียนแบบฟังก์ชั่นลูกศร
-var arrowFunc = () => console.log(arguments); // ไม่สามารถใช้อ็อบเจ็กต์ arguments ได้
-arrowFunc(1, 2, 3); // [] (ถ้าใช้ Traceur กับ Babel ตัว arguments จะเป็นอาร์เรย์ว่าง)
-// เขียนแบบฟังก์ชั่นธรรมดา
-var arrowFunc2 = function(){
- return console.log(arguments); // ฟังก์ชั่นธรรมดาสามารถใช้อ็อบเจ็กต์ arguments ได้ตามปกติ
-};
-arrowFunc2(1, 2, 3); // [1, 2, 3]
-```
-
-```js
-function createArrow(value) {
-// ฟังก์ชั่นลูกศรสามารถเรียกใช้ arguments ของฟังก์ชั่น createArrow()
- return () => arguments[0];
-}
-let arrowFunc = createArrow(1);
-console.log(arrowFunc()) // 1
-```
-
-## เทคนิคการเขียน IIFE
-```js
-// เทคนิค IIFE กับฟังก์ชั่นลูกศร
-var printItem = (
-(item) => function() { console.log(item); }
-)("IIFE");
-printItem(); // "IIFE"
-/* จะเสมือนใช้เทคนิค IIFE กับฟังก์ชั่นธรรมดา
-var printItem = function(item) {
- return function() { console.log(item); };
-}("IIFE");
-printItem(); // "IIFE"
-*/
-```
-
-## ฟังก์ชั่นคอลแบ็ค
-```js
-var array = [1, 2, 3, 4];
-array.forEach( (value, index, arr) => arr[index] = value *2 );
-console.log(array); // [2, 4, 6, 8]
-/* จะเสมือนใช้ฟังก์ชั่นคอลแบ็คแบบปกติ
-var array = [1, 2, 3, 4];
-array.forEach(function(value, index, arr) {
- return arr[index] = value * 2;
-});
-console.log(array); // [2, 4, 6, 8]
-*/
-```
-
-## การใช้ this ในฟังก์ชั่นลูกศร
-```js
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-
-```js
-let obj ={
- value : "JavaScript"
- ,printValue: function(){
- console.log("Message:", this.value); // this จะชี้ไปยังอ็อบเจ็กต์ obj
- }
- ,handle : function (){
- console.log("Press a button");
- }
- ,init : function(){
- let element = document.querySelector("#b1"); // ปุ่ม "Try it"
- element.addEventListener("click", function(event){
- this.handle(); // this จะชี้ไปยังอ็อบเจ็กต์ obj
- }.bind(this), false); // บรรทัด a -- this จะชี้ไปยังไปอ็อบเจ็กต์ obj
- //}.bind(obj), false); // จะใช้บรรทัดนี้ก็ได้ มีความหมายเหมือนกัน
- }
-}; // สิ้นสุดการประกาศอ็อบเจ็กต์
-
-obj.printValue(); // "Message: JavaScript"
-obj.init();
-```
-
-
-```js
-let obj ={
- value : "JavaScript"
- ,printValue: function(){
- console.log("Message:", this.value); // this จะชี้ไปยังอ็อบเจ็กต์ obj
- }
- ,handle : function (){
- console.log("Press a button");
- }
- ,init : function(){
- let element = document.querySelector("#b1"); // ปุ่ม "Try it"
- element.addEventListener("click", (event)=> this.handle()); //this จะชี้ไปยัง obj
- }
-}; // สิ้นสุดการประกาศอ็อบเจ็กต์
-obj.printValue(); // "Message: JavaScript"
-obj.init();
-```
-
-
-## เมธอด apply(), call() และ bind()
-```js
-let sum = (val1, val2) => console.log(val1 + val2) ;
-sum.apply(null, [5, 5] ); // 10
-sum.call(null, 5, 5); // 10
-let resultSum = sum.bind(null, 5, 5);
-resultSum(); // 10
-```
-
-```js
-let objA = {value: "access objA"};
-let objB = {
- value: "access objB"
- ,myFunction() {
- console.log("this.value in myFunction:", this.value);
- // this ในฟังก์ชั่นลูกศร จะเห็นเหมือนกับที่ myFunction() มองเห็น
- let arrowFunc = () => console.log("Arrow function:", this.value) ;
-
- let func = function(){ // this ในฟังก์ชั่นปกติ สามารถเปลี่ยนไปชี้อ็อบเจ็กตัวอื่นได้
- console.log("Normal function:", this.value);
- }
- arrowFunc.call(objA); // บรรทัด a –- ไม่สามารถเปลี่ยนค่า this ได้
- func.call(objA); // บรรทัด b -- สามารถเปลี่ยนค่า this ให้ชี้ไปยังอ็อบเจ็กต์ objA ได้
- }
-}
-objB.myFunction(); // บรรทัด c
-/*แสดงผลลัพธ์
-"this.value in myFunction: access objB"
-"Arrow function: access objB"
-"Normal function: access objA"
-*/
-objB.myFunction.call(objA); // บรรทัด d
-/*แสดงผลลัพธ์
-"this.value in myFunction: access objA"
-"Arrow function: access objA"
-"Normal function: access objA"
-*/
-```
-
-## Tail call optimization
-```js
-function foo(a) {
- return a; // บรรทัด a
-}
-function bar(b) {
- let c = b + 100;
- return foo(c); // บรรทัด b
-}
-console.log( bar(30) ); // บรรทัด c แสดงผลลัพธ์เป็น 130
-```
-
-## ตำแหน่ง Tail call
-### กรณีที่ 1
-```js
-function foo() {
- bar(); // เรียกฟังก์ชั่นแบบนี้จะไม่ใช่ตำแหน่งสุดท้าย
- // ถ้าเขียนเป็น return bar(); จะเป็นการเรียกฟังก์ชั่นในตำแหน่งสุดท้าย
-}
-```
-จะเสมือนเขียน
-
-```js
-function foo() {
- bar();
- return undefined;
-}
-```
-
-### กรณีที่ 2
-```js
-function foo() {
- return 1+ bar(); // เรียกฟังก์ชั่นแบบนี้จะไม่ใช่ตำแหน่งสุดท้าย
-}
-```
-
-จะเสมือนเขียน
-
-```js
-function foo() {
- let result = bar();
- return 1 + result;
-}
-
-
-กรณีที่ 3
-
-```js
-function foo(condition) {
- if(condition){
- return bar(); // บรรทัด a -- เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
- } else {
- bar(); // บรรทัด b -- เรียกฟังก์ชั่นแบบนี้จะไม่ใช่ตำแหน่งสุดท้าย
- }
- }
-```
-
-## รีเคอร์ซีพ
-```js
-function factorial(value) {
- if (value <= 0) {
- return 1;
- } else {
- return value * factorial(value-1); // บรรทัด a -- ไม่ใช่การเรียกฟังก์ชั่นในตำแหน่งสุดท้าย
- }
- }
-console.log(factorial(4)); // จะได้ค่าเป็น 24 เพราะ 4! = 4 x 3 x 2 x 1 = 24
-// จะเกิด RangeError เพราะ stack frame โตเกินไป จนใช้หน่วยความจำหมด
-console.log(factorial(200000));
-```
-
-```js
-// ต้องประกาศเพื่อทำ TCO แต่ถ้าเขียนบน Traceur หรือ Babel ซอร์สโค้ดจะเป็นสตริคท์โหมดโดยอัตโนมัติ
-"use strict";
-function factorial(value) {
- return callFac(1, value);
-}
-function callFac(temp, val) {
- if (val <= 1) {
- return temp;
- } else {
- return callFac(temp * val, val-1); // บรรทัด a -- เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
- }
-}
-console.log(factorial(4)); // 24
-console.log(factorial(200000)); // infinity
-```
-
-
-## นิพจน์อื่นที่เป็น Tail call
-### กรณีที่ 1
-```js
-let arrowFunc = param => param ? foo() : bar();
-```
-
-จะเสมือนเขียน
-
-```js
-let arrowFunc = param => {
- if(param){
- return foo(); // เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
-}else{
- return bar(); // เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
-}
-};
-```
-
-
-## กรณีที่ 2
-```js
-let arrowFunc = () => (foo(), bar(), zoo());
-```
-
-จะเสมือนเขียน
-
-```js
-let arrowFunc = () => {
- foo();
-bar();
- return zoo(); // เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
-};
-```
-
-## กรณีที่ 3
-```js
-let arrowFunc = () => foo() || bar();
-```
-
-จะเสมือนเขียน
-
-```js
-let arrowFunc = () => {
- let temp = foo();
- if (temp) {
- return temp;
- } else {
- return bar(); // เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
- }
-};
-```
-
-## กรณีที่ 4
-```js
-let arrowFunc = () => foo() && bar();
-```
-
-
-```js
-let arrowFunc = () => {
- let temp = foo();
- if (!temp) {
- return temp;
- } else {
- return bar(); // เรียกฟังก์ชั่นในตำแหน่งสุดท้าย
- }
-};
-```
diff --git a/examples_book/Chapter8.md b/examples_book/Chapter8.md
deleted file mode 100644
index 8b13789..0000000
--- a/examples_book/Chapter8.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/examples_book/README.md b/examples_book/README.md
index 92efc03..580d594 100644
--- a/examples_book/README.md
+++ b/examples_book/README.md
@@ -1,13 +1,35 @@
-# [โค้ดตัวอย่างจากหนังสือทั้งหมด]( https://www.se-ed.com/product/พัฒนาเว็บแอปพลิเคชั่นด้วย-JavaScript.aspx?no=9786160825394)
-
+# [โค้ดตัวอย่างจากหนังสือทั้งหมด]([https://www.mebmarket.com/web/index.php?action=BookDetails&data=YToyOntzOjc6InVzZXJfaWQiO3M6NzoiMTcyNTQ4MyI7czo3OiJib29rX2lkIjtzOjY6IjE1Njg1NCI7fQ)
+
-* [บทที่ 1](Chapter1.md)
-* [บทที่ 2](Chapter2.md)
-* [บทที่ 3](Chapter3.md)
-* [บทที่ 4](Chapter4.md)
-* [บทที่ 5](Chapter5.md)
-* [บทที่ 6](Chapter6.md)
-* [บทที่ 7](Chapter7.md)
+[สามารถสั่งซื้อได้ที่เว็บ MEB (ขายเป็นอีบุ๊ก)](https://www.mebmarket.com/web/index.php?action=BookDetails&data=YToyOntzOjc6InVzZXJfaWQiO3M6NzoiMTcyNTQ4MyI7czo3OiJib29rX2lkIjtzOjY6IjE1Njg1NCI7fQ)
+[ ส่วนเล่มที่วางขายใน shopee ตอนนี้เลิกทำแล้ว เพราะต้นทุนแพงเกินไปทำไม่ไหว](https://shopee.co.th/product/159315996/18595064435/)
+* บทที่ 1 แนะนำจาวาสคริปต์
+* [บทที่ 2 รันจาวาสคริปต์อย่างง่าย](Chapter02.md)
+* [บทที่ 3 ทบทวนมาตรฐานเก่า](Chapter03.md)
+* [บทที่ 4 ทบทวนประโยคคำสั่งเบื้องต้น](Chapter04.md)
+* [บทที่ 5 ทบทวนอ็อบเจ็กต์](Chapter05.md)
+* [บทที่ 6 ทบทวน Regex](Chapter06.md)
+* [บทที่ 7 ทบทวน HTML DOM](Chapter07.md)
+* [บทที่ 8 ฟีเจอร์ใหม่ของตัวเลข สตริง และ regex](Chapter08.md)
+* [บทที่ 9 การประกาศตัวแปร และการกำหนดค่า](Chapter09.md)
+* [บทที่ 10 ฟังก์ชั่น](Chapter10.md)
+* [บทที่ 11 เทมเพลตสตริง](Chapter11.md)
+* [บทที่ 12 ซิมโบล](Chapter12.md)
+* [บทที่ 13 ฟีเจอร์ใหม่ของอ็อบเจ็กต์](Chapter13.md)
+* [บทที่ 14 คลาส](Chapter14.md)
+* [บทที่ 15 คอลเลคชั่น](Chapter15.md)
+* [บทที่ 16 อิเทอเรเตอร์ และเจนเนอเรเตอร์](Chapter16.md)
+* [บทที่ 17 เมต้าโปรแกรมมิ่ง](Chapter17.md)
+* [บทที่ 18 พรอมิส](Chapter18.md)
+* [บทที่ 19 การใช้งาน async กับ await](Chapter19.md)
+* [บทที่ 20 มอดูล](Chapter20.md)
+* [ภาคผนวก ข](Appendix_B)
+* [ภาคพนวก ง](Appendix_G.md)
+
+### หมายเหตุ [สามารถทดลองรันโค้ดตัวอย่างในหนังสือได้ (ควรเปิดบนคอม ไม่แนะนำให้เปิดบนมือถือ หรือแท็บเล็ต)](https://patanasongsivilai.com/myblog/main.php?id=756)
+
+#### ปล. เล่มนี้ตามรูปข้างล่างเนื้อหาเก่าแล้ว (ปัจจุบันไม่มีตีพิมพ์เพิ่ม)
+
diff --git a/examples_book/ajax.php b/examples_book/ajax.php
new file mode 100644
index 0000000..a6ae76a
--- /dev/null
+++ b/examples_book/ajax.php
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/examples_book/free_ebook/Readme.md b/examples_book/free_ebook/Readme.md
new file mode 100644
index 0000000..c89ef47
--- /dev/null
+++ b/examples_book/free_ebook/Readme.md
@@ -0,0 +1,13 @@
+# เอกสารแจกฟรี (อ่านบนเว็บ MEB)
+
+* [ปูพื้นฐาน Node.js ฉบับย่อ เข้าใจ MongoDB](
+https://www.mebmarket.com/web/index.php?action=BookDetails&data=YToyOntzOjc6InVzZXJfaWQiO3M6NzoiMTcyNTQ4MyI7czo3OiJib29rX2lkIjtzOjY6IjI0OTQwOCI7fQ)
+
+
+
+* [พื้นฐาน React - ขออนุญาตแก้ไขลิงค์ รวมทั้งเนื้อหาในหนังสือ เดี่ยวเปิดให้อ่านสักประมาณต้นเดือน มกราคม 2567 ]()
+
+เลยให้ลิงก์ชั่วคราวไปก่อน
+[อ่าน React ชั่วคราว](https://www.mebmarket.com/web/index.php?action=BookDetails&data=YToyOntzOjc6InVzZXJfaWQiO3M6NzoiMTcyNTQ4MyI7czo3OiJib29rX2lkIjtzOjY6IjI0ODU5NiI7fQ)
+
+
diff --git a/examples_book/json.php b/examples_book/json.php
new file mode 100644
index 0000000..13c071a
--- /dev/null
+++ b/examples_book/json.php
@@ -0,0 +1,15 @@
+name = "Somchai";
+$myObj->age = 30;
+$myObj->city = "Bangkok";
+
+$myJSON = json_encode($myObj);
+
+echo $myJSON;
+?>
\ No newline at end of file
diff --git a/images/chap01/quotes.png b/images/chap01/quotes.png
index 1d6ec08..6d991aa 100644
Binary files a/images/chap01/quotes.png and b/images/chap01/quotes.png differ
diff --git a/images/cover_new.png b/images/cover_new.png
new file mode 100644
index 0000000..1c9883a
Binary files /dev/null and b/images/cover_new.png differ