web-4

講師

Eating

目錄

  • JS 介紹
  • JS 變數
  • JS 運算子
  • JS 流程控制
  • JS 型別
  • 非同步
  • Github Page

JS 基礎

JS 是啥

JavaScript 簡稱 JS ,是一個程式語言,專門用於網頁前端*1的互動。

他能夠實現(不只)以下功能

變更網頁上的元素、做簡單運算、製作遊戲、動態抓取資料、建立假的多頁網站

 

它的優點就是超簡單,瀏覽器通常只認他,但就是因為太簡單了所以寫 JS 可能被看不起

*1 透過 node.js,JavaScript 也能用來撰寫後端。

JavaScript  跟 JAVA 有啥關係

那時候很 JAVA 很紅所以她取名子的時候就蹭一下 JAVA 的熱度

 

啊不要問我 JAVA 是啥我不會,感覺不是很好用啦。

Hello, World!

學程式第一件事就是 Hello, World!

感覺 JS 的 Hello, World! 應該最好寫了。

1. 打開 F12

2. 找到 Console 

3. 輸入 :

就好了!

你也可以試試看這個:

console.log("Hello, World!");
alert("hello, world");

那正常一點的引入方式是啥

建立一個 script.js 的檔案

 <script type="text/javascript" src="script.js"></script>

然後在 HTML 中可以這樣引入,打開這個網頁後他的輸出會在 F12 的 Console 中

那正常一點的引入方式是啥

不想開檔案也可以這樣

<script>
	// 在這裡寫 JS 程式碼
	console.log(123);
</script>

然後在 HTML 中直接放一個 script 標籤,JS 直接寫裡面

JS 基礎 實作

引入一個檔案後,用剛剛兩個方法輸出 Hello, World!

JS 語法-變數

變數

變數是一個存東西的東西

相信大家都知道是啥了

變數宣告

宣告就是讓電腦知道這個變數存在

Python 都不宣告超怪

var a = 1;
let b = 2;
const c = 3;

變數宣告

作用域

相信大家也都會了因為 APCS 會考

啊但那是 C++ 

啊不過他們很像

ㄜ有幾個不一樣的地方

變數宣告

作用域

先講一些常識

1. 全域變數通常在所有東西外面嘛然後大家都可以用他

2. 在 Function 中宣告的變數只有在 Function 中能用

3. 還有一個區塊變數就是在{}裡面,每個{}中宣告的變數就只有他能用

4. 讀取的時候名字一樣會讀到域最小(最近)的那個

變數宣告

作用域

let g = 100; // 全域變數

function test() {
    let x = 10; // 區域變數
    
    if (true) {
          let y = 20; // 區塊變數
     }
}

test();

變數宣告

作用域 C++ vs JS

let g = 100; // 全域變數

function test() {
    let x = 10; // 區域變數
    
    if (true) {
      	let y = 20; // 區塊變數
      	var z = 5; // 他會變區域變數
    }
  	//這裡讀的到 z!
  
}

test();

不同的地方 1. 有 var 這種鬼東西

他會自己提升成區塊變數

變數宣告

作用域 C++ vs JS

// JavaScript
console.log(x); // undefined (不會報錯!)
var x = 5;

不同的地方 2. var 可以先用他再宣告,初始值是 undefined

變數宣告

作用域 C++ vs JS

let age = 25;
let name = "小明";
let price = 99.99;
let isStudent = true;

age = "二十五"; // 可以改成字串
age = [1, 2, 3]; // 也可以變成陣列
age = { value: 30 }; // 甚至可以變成物件

不同的地方 3. 不用指定類型

ㄜ這功能評價有好有壞但我是覺得爛透了

變數宣告

所以 let 和 const 是啥

let age = 18;
age = 19;      // 可以改變
age = 20;      // 可以再改變

const pi = 3.14;
pi = 3.14159;  // 錯誤!const 不能重新賦值

let 就是最正常的變數宣告

const 是宣告一個你不會改他的變數 好其實 c++ 也有所以你們應該懂

變數命名

先講一些常識

1. 必須使用字母、_、$ 作為開頭
2. 名稱可包含數字(0-9)
3. 'A' ~ 'Z' 和 'a' ~ 'z' 皆可使用且大小寫敏感(例:Name ≠ name)
4. 不能使用保留字(啊保留自有啥自己去找)

變數命名

好習慣

一般變數用:小寫開頭、大寫分隔

常數變數通常用:全大寫、"_"分隔

函式可用動詞開頭:calculateTax、getUserInfo

變數如果是布林值就用疑問句開頭:isActive 、shouldUpdate 

let score = 55;        // 分數
let extraPoints = 5;   // 加分
let finalScore = score + extraPoints;
 
const PI = 3.14159;
const EULER_NUMBER = 2.71828;

變數參考

有點怪

分兩種變數,一個是基本型別

另一個是參考型別

他們在"複製"的時候有不同行為

變數參考

基本型別 會複製"值"

string, number, boolean, null, undefined, symbol

// 基本型別 - 複製的是「值」
let a = 10;
let b = a;  // b 得到 10 的「副本」

b = 20;     // 改變 b

console.log(a);  // 10 - a 不受影響 ✓
console.log(b);  // 20

變數參考

參考型別 會複製"地址"

object, array, function

// 物件 - 複製的是「地址」(參考)
let person1 = { name: "小明", age: 18 };
let person2 = person1;  // person2 指向「同一個物件」!

person2.age = 20;  // 改變 person2

console.log(person1.age);  // 20 - person1 也變了! 
console.log(person2.age);  // 20
const student1 = { name: "小明", score: 85 };
const student2 = student1;  // 共用同一個物件!

student2.score = 95;

console.log(student1.score);  // 95 - 被改了!
console.log(student2.score);  // 95

const arr1 = [1, 2, 3];
const arr2 = arr1;  // 這不是複製!是共用!

arr2.push(4);

console.log(arr1);  // [1, 2, 3, 4] - arr1 也被改了!
console.log(arr2);  // [1, 2, 3, 4]

至於要怎麼複製請看後面有一個 展開運算子

JS 語法-變數-實作

APCS 不會考

超簡單

let z = 0;
function f(x) {
    if (true) {
        console.log(x);
        var x = 10;
    }
    z += x;
    console.log(x);
}

f(f(x));
var x = 2;

console.log(x);
console.log(z);

依序輸出啥/或是哪裡會噴錯

猜猜看變數可以存多大

真好玩

JS 語法-資料型態

資料型態

隨便啦只講有用一點的

模板字串

let product = "心";
let price = 100000000;

console.log(`您購買的商品是${product},價格為 ${price} 元`);
// 您購買的商品是心,價格為 100000000 元

資料型態

隨便啦只講有用一點的

Undefined&Null:

Undefined:變數宣告但未賦值

Null:表示「無值」,通常是開發者明確設定的

條件判斷的時候他們都是 false

let notAssigned;           // 變數宣告但未賦值
console.log(notAssigned);  // undefined

let empty = null;          // 明確將變數設為 null
console.log(empty);        // null

資料型態

隨便啦只講有用一點的

物件 

反正就 key 對 value

key 通常是字串

value 隨便你

	
const phoneBook = {
  小明: "0928440308",
  小美: "0919680246",
  張三: "0982727329",
  李四: 0968802962
};

資料型態

隨便啦只講有用一點的

物件

let person = {
  name: 'Alice',
  age: 25,
  greet: function () {
    console.log('Hello!');
  }
};
person.age = 3000;
console.log(person.name,person.age); // Alice,3000
person.greet();           // Hello!

資料型態

隨便啦只講有用一點的

物件

const student = {
  name: "小明",
  age: 18,
  grade: "A"
};

const keys = Object.keys(student);
console.log(keys);  // ["name", "age", "grade"]

// 搭配 forEach 遍歷
keys.forEach(key => {
  console.log(`${key}: ${student[key]}`);
});

資料型態

隨便啦只講有用一點的

陣列

// 宣告陣列
let num1 = ['壹', '貳', '參'];
// new Array(),功能與上面的相同
let num2 = new Array('壹', '貳', '參');

console.log(num1);  // [ '壹', '貳', '參' ]
console.log(num2);  // [ '壹', '貳', '參' ]

// 也可以宣告空陣列
let emptyArray = [];

console.log(emptyArray);  // []
let num = [1, 2, 3];

// 訪問元素
console.log(num[2]);     // 3

// 修改元素
num[2] = 2;			     // [ 1, 2, 2 ]

// 新增元素
num.push("3");		     // [ 1, 2, 2, '3' ]
num.unshift(false);	  	 // [ false, 1, 2, 2, '3' ]
num[5] = 5;			  	 // [ false, 1, 2, 2, '3', 5 ]

// 刪除元素
num.pop();			     // [ false, 1, 2, 2, '3' ]
num.shift();		     // [ 1, 2, 2, '3' ]


// 查看長度
console.log(num.length); // 4

// 陣列轉字串
console.log(allNum.join('-'));   // 1-2-2-3
let num = [1, 5, 3, 7, 5];

// 搜尋元素
console.log(num.indexOf(5));      // 1
console.log(num.includes(3));     // true
console.log(num.includes(2));	  // false

// 複製&切割
let subArray = num.slice(1, 3);   // [ 5, 3 ]

// 新增&刪除
num.splice(3, 2, 3); 			  // 從索引 3 刪除 2 個元素,並插入 3
console.log(num);				  // [ 1, 5, 3, 3 ]

// 排序
num.sort();					 	  // [ 1, 3, 3, 5 ]
num.reverse();				 	  // [ 5, 3, 3, 1 ]

// 合併
let moreNum = [10, 23, 12];
let allNum = num.concat(moreNum); // [ 5, 3, 3, 1, 10, 23, 12 ]

資料結構

陣列操作(ES6)

const numbers = [1, 2, 3, 4, 5];

// 不用 map 的寫法(笨方法)
const doubled = [];
for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}

// 用 map 的寫法(聰明方法)
const doubled = numbers.map(function(num){
  return num * 2
});
console.log(doubled); // [2, 4, 6, 8, 10]

map 填的參數是一個 Function ,會自動把陣列的每個值傳入那個 Function 並且將原本的值替換成函式的返回值

const students = [
  { name: "小明", score: 85 },
  { name: "小華", score: 92 },
  { name: "小美", score: 78 }
];

// 加上 index 參數
const processed = students.map((student, index) => ({
  id: index + 1,  // 從 1 開始編號
  name: student.name,
  score: student.score,
  grade: student.score >= 90 ?'A' :
  	student.score >= 80 ? 'B' :'C',
  passed: student.score >= 60
}));

console.log(processed);
// [
//   { id: 1, name: "小明", score: 85, grade: "B", passed: true },
//   { id: 2, name: "小華", score: 92, grade: "A", passed: true },
//   { id: 3, name: "小美", score: 78, grade: "C", passed: true }
// ]

至於這邊的 Function 跑去哪? => 又是啥可以看下一章

const students = [
  { name: "小明", score: 85 },
  { name: "小華", score: 92 },
  { name: "小美", score: 78 }
];

// 加上 index 參數
const processed = students.map((student, index) => ({
  id: index + 1,
  ...student,  // 保留原有的 name 和 score
  grade: student.score >= 90 ? 'A' :
  	student.score >= 80 ? 'B' : 'C',
  passed: student.score >= 60
}));

console.log(processed);
// [
//   { id: 1, name: "小明", score: 85, grade: "B", passed: true },
//   { id: 2, name: "小華", score: 92, grade: "A", passed: true },
//   { id: 3, name: "小美", score: 78, grade: "C", passed: true }
// ]
const users = [
  { id: 1, name: "小明", age: 18 },
  { id: 2, name: "小華", age: 20 },
  { id: 3, name: "小美", age: 19 }
];

// 根據 ID 找使用者
const user = users.find(u => u.id === 2);
console.log(user);
// { id: 2, name: "小華", age: 20 }

// 根據名字找
const user2 = users.find(u => u.name === "小美");
console.log(user2.age);  // 19

資料型態

隨便啦只講有用一點的

陣列

還有很多 ES6 的好用東西要看一下

超推薦下面這篇文章我之前要用都是查他

JS 語法-資料型態

-實作

JS 語法-運算子

運算子

超簡單

有次方可以直接用還不錯

let a = 10;
let b = 3;

console.log(a + b);  // 13
console.log(a - b);  // 7
console.log(a * b);  // 30
console.log(a / b);  // 3.33333333333333
console.log(a % b);  // 1
console.log(a ** b); // 1000

運算子

超簡單

這也是常識

let x = 10;

x += 5; // 等價於 x = x + 5,結果為 15
x -= 3; // 等價於 x = x - 3,結果為 12
x *= 2; // 等價於 x = x * 2,結果為 24
x /= 4; // 等價於 x = x / 4,結果為 6
x %= 5; // 等價於 x = x % 5,結果為 1

運算子

超簡單

這也是常識

let y = 5;
console.log(y == "5");  // true
console.log(y === "5"); // false
console.log(y != 3);    // true
console.log(y !== "5"); // true
console.log(y > 3);     // true
console.log(y <= 5);    // true

運算子

超簡單

這也是常識

// && (AND):兩邊都為 true,結果才為 true
console.log(true && false);  // false
console.log(true && true);   // true

// || (OR):只要一邊為 true,結果就是 true
console.log(true || false);  // true
console.log(false || false); // false

// ! (NOT):反轉布林值
console.log(!true);  		 // false
console.log(!false);  		 // true
console.log(!!false);       // false,假
console.log(!!undefined);   // false,未定義
console.log(!!null);        // false,空值
console.log(!!"");          // false,空字串
console.log(!!NaN);         // false,不是數字
console.log(!!0);           // false,(正)零
console.log(!!-0);          // false,負零

console.log(!!true);        // true,真
console.log(!!'hi');        // true,字串 hi
console.log(!!1);           // true,一
console.log(!![]);          // true,空陣列
console.log(!![0]);         // true,有一個零的陣列
console.log(!![1]);         // true,有一個一的陣列

運算子

展開運算子

const arr1 = [1, 2, 3];
const arr2 = [...arr1];  // 展開後複製

console.log(arr2);  // [1, 2, 3]
arr2.push(4);
console.log(arr1);  // [1, 2, 3] - 原陣列不受影響
console.log(arr2);  // [1, 2, 3, 4]

運算子

展開運算子

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// 舊方法
const merged1 = arr1.concat(arr2);

// 新方法 - 用展開運算子
const merged2 = [...arr1, ...arr2];
console.log(merged2);  // [1, 2, 3, 4, 5, 6]

// 可以加入額外元素
const merged3 = [0, ...arr1, 3.5, ...arr2, 7];
console.log(merged3);  // [0, 1, 2, 3, 3.5, 4, 5, 6, 7]

運算子

展開運算子

const basic = { name: "小明", age: 18 };
const extra = { city: "台北", hobby: "coding" };

const merged = { ...basic, ...extra };
console.log(merged);
// { name: "小明", age: 18, city: "台北", hobby: "coding" }

運算子

展開運算子

const user = { name: "小明", age: 18 };

// 展開在前 - 會被覆蓋
const result1 = { ...user, age: 20 };
console.log(result1);  // { name: "小明", age: 20 } ✓

// 展開在後 - 覆蓋前面的值
const result2 = { age: 20, ...user };
console.log(result2); 
// { age: 18, name: "小明" } - age 被 user.age 覆蓋了!

JS 語法-流程控制

流程控制

if (條件) {
    // 當條件為 true 時執行的程式碼
}

if (條件) {
    // 當條件為 true 時執行的程式碼
}
else {
    // 當條件為 false 時執行的程式碼
}

if else

流程控制

for

for (初始化; 條件; 更新) {
    // 迴圈內執行的程式碼
}

// 範例
for (let i = 0; i < 5; i++) {
    console.log(i); // 輸出 0, 1, 2, 3, 4
}

跟 C++ 一樣

流程控制

WHile

while (條件) {
    // 程式碼
}

// 無限迴圈
while (true) {
    // blablabla
}

跟 C++ 一樣

喔然後不要在無線迴圈操作 DOM 會爛掉

(操作 console 也會)

流程控制

break、continue

for (let i = 0; i < 10; i++) {
    if (i === 5) {
        break; // 當 i 等於 5 時,停止迴圈
    }
    console.log(i); // 0 1 2 3 4
}

for (let i = 0; i < 10; i++) {
    if (i % 2 === 0) {
      	continue;   // 略過偶數
    }
    console.log(i); // 1 3 5 7 9
}

流程控制

switch

switch (表達式) {
    case 值1:
        // 當表達式等於 值1 時執行的程式碼
        break;
    case 值2:
        // 當表達式等於 值2 時執行的程式碼
        break;
    ...
    default:
        // 當表達式不符合任何情況時執行的程式碼
}

條件語句

超好用

let age = 18;
let canVote = age >= 18 ? "Yes" : "No";
console.log(canVote); // Yes

(canVote == "Yes") && console.log("歡迎投票!");
// canVote 是 Yes 才會印出來

函式

一樣基礎

// 基本函式
function greet(name) {
  return "你好, " + name;
}
console.log(greet("小明")); // "你好, 小明"
// 有預設值
function greet(name = "訪客") {
  return "你好, " + name;
}
console.log(greet());      // "你好, 訪客"
console.log(greet("小華")); // "你好, 小華"

// 多個參數
function add(a, b) {
  return a + b;
}
console.log(add(5, 3)); // 8

// 沒有 return (回傳 undefined)
function sayHi(name) {
  console.log("嗨, " + name);
}
sayHi("小明"); // 只印出訊息,沒有回傳值

const greet = function(name) {
  return "你好, " + name;
};
console.log(greet("小明")); // "你好, 小明"
// 基本箭頭函式
const greet = (name) => {
  return "你好, " + name;
};
console.log(greet("小明")); // "你好, 小明"

// 傳統函式
const numbers = [1, 2, 3];
const doubled = numbers.map(function(num) {
  return num * 2;
});

// 箭頭函式 - 簡潔多了!
const doubled = numbers.map(num => { return num * 2});

// 箭頭函式 - 更簡潔的!
const doubled = numbers.map(num => num * 2);

反正就是省略 Function

直接寫括弧傳入參數之後用 =>{} 在 {} 中正常寫函式

如果只有一行而且剛好是 return 的話可以連 {} 和 return 都省略

JS 語法-類型!??

大家都說 JS 類型是智障

啊他到底哪裡智障

靜態型別 動態型別
定義 在編譯時期就指定變數的型別 在執行時期才會決定變數的型別
特點 型別不可隨意更改 型別可隨時更改
優缺 提升程式的執行效能與穩定性 程式更加靈活,但寫的時候較容易出錯
例子 C、C++、Java JavaScript、Python、Ruby

大家都說 JS 類型是智障

啊他到底哪裡智障

強型別 弱型別
定義 不允許隱式轉換或任意混合使用不同型別的資料 允許隱式轉換,可混合不同型別的資料
特點 除非你主動說要轉換類型不然不會變 型別可能會偷偷被更改
優缺 要把字串和庶子接起來要轉換 可能會意外轉換,加上 js 判斷相等的方式很酷
例子 Python、Java JavaScript、PHP

大家都說 JS 類型是智障

這是有點智障又有點聰明的地方

1 + "2"        // "12"
"3" + 4 + 5    // "345"
3 + 4 + "5"    // "75"
[] + 1       // "1"
// 通常 + 的參數不是數字的時候結果會是字串

"10" - 2     // 8
"6" * "7"    // 42
"20" / 2     // 10
// 通常其他的時候他會盡量轉成數字

"" - 1       // -1
[] - 3       // "-3"
false - 2    // -2
// 這些通常是 0

大家都說 JS 類型是智障

這是超怪超智障的地方

0 == "0"   // true
0 == []    // true
"0" == []  // false

!!0        // false
!!"0"      // true
!![]       // true

NaN == NaN // false

null > 0     // false
null == 0    // false
null === 0   // false
null >= 0    // ture
Number(null) // 0
let num = 123;
let bool = true;

let str1 = String(num); // "123"
let str2 = num.toString(); // "123"
let str3 = String(bool)); // "true"

let str = "123";
let num1 = Number(str); // 123

let num2 = parseInt("123px"); // 123(忽略非數字部分)
let num3 = parseFloat("3.14"); // 3.14(保留小數部分)

console.log(Number(true));  // 1
console.log(Number(false)); // 0

console.log(Boolean(1));       // true
console.log(Boolean(0));       // false
console.log(Boolean("Hello")); // true
console.log(Boolean(""));      // false
console.log(Boolean(null));    // false

這是顯式轉換 蠻正常的 啊轉成同的類型之後去比較就不會出事

大家都說 JS 類型是智障

用 == 去比較的時候它會自動幫我們轉換

反正他愛怎麼轉就怎麼轉,所以會出現上面那些情況。

如果要避免的話可以改用 === 去比較

let y = 5;
console.log(y == "5");  // true
console.log(y === "5"); // false

JS 非同步處理

非同步處理

setTimeout、setInterval 

把很多東西放在同步的單線程會卡住,在網頁這種互動的地方更重要。

舉例來說你正在讀取最新的資料的時候,使用者可能要同時填寫表單並驗證?如果用單線程的同步操作可能會整個卡死。

非同步處理

console.log("開始");

setTimeout(() => {
  console.log("3秒後執行");
}, 3000);  // 3000 毫秒 = 3 秒

console.log("結束");

// 輸出順序:
// 開始
// 結束
// 3秒後執行  (3秒後才出現)

setTimeout

非同步處理

let count = 0;

setInterval(() => {
  count++;
  console.log(`執行第 ${count} 次`);
}, 1000);  // 每 1 秒執行一次

console.log("結束")

// 輸出:
// 結束
// 執行第 1 次
// (1秒後) 執行第 2 次
// (1秒後) 執行第 3 次
// ... 持續執行

setInterval 

// 錯誤:計時器會一直執行
function startTimer() {
  setInterval(() => {
    console.log("執行中...");
  }, 1000);
}

startTimer();
startTimer();  // 現在有兩個計時器在跑!

// ✓正確:儲存 ID 以便清除
let timerId;

function startTimer() {
  if (timerId) {
    clearInterval(timerId);  // 先清除舊的
  }
  timerId = setInterval(() => {
    console.log("執行中...");
  }, 1000);
}

Githib pages

要複習一下

Github pages

你應該有下面這個畫面

Github pages

點設定

Github pages

點 Pages

Github pages

點 None

Github pages

點 master 或是它顯示 main 就一樣點他

Github pages

點 Save

然後等他一下

Github pages

重新整理之後就會出現下面那樣

點進去

他會預設顯示你的根目錄下面的 index.html 檔案(或是 .md 檔案)

如果你不叫 index.html 就要在連結上加入

/<檔案名稱>.html 才能顯示

web-4

By 翊庭jx06 T