經過前面學過的HTML,CSS的學習,相信大家已經可以使用進行常用的頁面開發,接下來我們就要學習JavaScript,鑒于內容過多,需要長期練習
流程為:數據類型>>運算>>語法,語句>>對象>>數組>>函數>>類
軟件使用:谷歌瀏覽器(當然如果你了解的話可以用nodejs試一下,但是為了方便,本系列都是用的瀏覽器)
JavaScript相比起HTML,CSS是有一定難度的,可以作為一門編程語言而學的,但是學會
JavaScript對于后期我們學習nodejs(包括python爬蟲的學習)的時候幫助很大,所以仍然要細心學習
JavaScript在前端開發有什么用呢:
在開發房子中HTML相當于房子水泥鋼筋鑄的結構骨架,CSS相當于房子的裝修風格,而JavaScript相當于智能家居一樣,可以讓網站變得動態(也就是我們看到的動畫效果)
學習JavaScript之前,我們先學數據類型,這個東西有過學習其他開發語言的朋友應該了解
數據類型
一、基本數據類型(Primitive Data Types)
基本數據類型是構成 JavaScript 最基礎的單位,存儲在棧內存中,直接存儲實際的數據值。JavaScript 的基本數據類型包括以下幾種:
String(字符串):用來表示文本數據,可以是一個字符或一串字符序列,例如"Hello"、'JavaScript'、"42"等。字符串是不可變的,每次對字符串的操作都會產生新的字符串實例。
Number(數字):表示數字,包括整數和浮點數。例如42、3.14、-7等。JavaScript 中的數字沒有區分整型和浮點型,統一用 Number 表示。
Boolean(布爾值) :表示邏輯實體,只有兩個值:true 和 false。通常用于條件判斷中。(在之前的皮卡丘靶場中的布爾類型的內容中我們短暫的了解過)
Undefined(未定義):表示變量未被賦值,或者尚未聲明的變量的默認值。例如:let x;,此時 x 的值就是 undefined。
Null(空值):表示沒有值,或者對象為空。null 是一個空對象引用。它和 undefined 常常容易混淆,但它們表示的意義不同。
二、引用數據類型(Reference Data Types)
引用數據類型是復合數據類型,通常存儲在堆內存中,變量存儲的是對象在內存中的地址(引用)。以下是常見的引用數據類型:
Object(對象):是 JavaScript 中最通用的引用數據類型,以鍵值對的形式存儲數據。例如:let person = { name: 'John', age: 30 }。
Array(數組):是一種特殊的對象,用于存儲多個值,這些值可以通過索引來訪問。例如:let arr = [1, 2, 3, 'JavaScript']。
Function(函數):在 JavaScript 中,函數其實也是一種特殊的對象,可以被賦值、傳遞和返回。例如:function add(a, b) { return a + b; } 或者箭頭函數:const add = (a, b) => a + b;。
以上是數據類型的知識,雖然看起來很簡單,但是在開發語言中,這是非常重要的地基,如果沒有記牢的話會影響后面的學習
運算
接下來我們學習運算(類似于你學習數學,你得先知道各類數字比如:整數,有小數點的,有分號的,今天的運算相當于了解加減乘除的符號用法)
直接用谷歌瀏覽器來運行即可:我們按壓F12打開console(如果你漢化過叫"控制臺")在里面輸入即可
一,算數運算符
作用:執行基本的數學運算
+ 加法
- 減法
* 乘法
/ 除法
% 求余
示例
let?a =?5;let?b =?3;console.log(a + b);?// 8console.log(a - b);?// 2console.log(a * b);?// 15console.log(a / b);?// 1.666...console.log(a % b);?// 2
類似以上內容,直接把內容放到控制臺運行即可
二,比較運算符
作用:比較運算符用于比較兩個值,返回布爾值(true
?或?false
)
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
示例
let?a =?5;let?b =?3;console.log(a == b);?// falseconsole.log(a != b);?// tureconsole.log(a > b);?// trueconsole.log(a <= b);?// false
三,邏輯運算符
作用:邏輯運算符用于組合布爾值,返回布爾結果。
&& 邏輯與(AND)
|| 邏輯或(OR)
! 邏輯非(NOT)
示例
let?a =?5;let?b =?3;console.log(a >?2?&& b <?4);?// trueconsole.log(a <?2?|| b >?4);?// falseconsole.log(!(a == b));?// true
四,賦值運算符
作用:賦值運算符用于給變量賦值
= 簡單賦值
+= 加法賦值
-= 減法賦值
*= 乘法賦值
/= 除法賦值
%= 取模賦值
示例
let?c =?10;c?+=?5; // c =?15c?-=?3; // c =?12c?*=?2; // c =?24c?/=?4; // c =?6c?%=?5; // c =?1console.log(c); //?1
由此我們還可以知道JavaScript讀取時顯示的的是最后一個結果,是因為每次運算的結果會覆蓋之前的值,或者你只在最后調用了輸出函數
語法語句
接下來是語法,語句
傳統的語法定義:音義結合的各結構單位之間的組織規則的匯集。但是在JavaScript學習中,語法意為描述合法代碼書寫規則的集合(就是拼拼圖,必須按照固定搭配才能拼好)
語句:是程序中執行一個操作的基本單元,它是構成程序的基本結構元素之一(就好像寫作文,是一句話一句話拼起來的)
語法:
代碼塊:
代碼塊是用花括號 {}括起來的代碼片段,通常用于表示代碼的邏輯結構。
比如在if語句、for循環、while循環和函數中,代碼塊用來定義執行的具體操作。(在 JavaScript 中,語句通常以分號(;)結尾,表示一個完整的操作結束。)
if?(age >=?18) {console.log("成年了");console.log("可以參加選舉了");}這里的 {} 中的內容就是代碼塊,表示當條件滿足時,要執行的多個操作。
注釋:
注釋是用來解釋代碼片段的,它不會被瀏覽器執行,但可以幫助我們理解代碼的邏輯。(類似于你背英語單詞,考試的時候不會看你了不了解,只看你寫出來的回答這就是瀏覽器執行的內容,你背在腦子里的翻譯語法就是注釋)
單行注釋:
使用?//
,它只能注釋這一行的內容
// 這是單行注釋,解釋變量的作用let?x =?10;?// 初始化變量 x
多行注釋:
使用?/*
?和?*/
?包裹內容,可以注釋多行代碼。
/*這是一個多行注釋,可以用來解釋一個復雜的功能模塊或者代碼邏輯*/
語句:
變量聲明
var語句:是 JavaScript 中最初用于聲明變量的關鍵字。它具有函數作用域,也就是說在函數內部用?var
?聲明的變量,只在該函數內部有效。
function?test() {var?x =?10;}console.log(x);?// 會報錯,因為 x 只在 test 函數內部有效
let語句:用于聲明變量的關鍵字,它具有塊級作用域。塊級作用域是指在一對大括號({})內聲明的變量,只在該大括號內有效。
{let?y =?20;}console.log(y);?// 會報錯,因為 y 只在大括號內有效
const:const?用于聲明常量,也具有塊級作用域。一旦聲明后,常量的值不能被改變。
const?PI =?3.14;console.log(PI); // 輸出?3.14PI?=?3; // 會報錯,不能修改常量的值
條件語句
(類似于如果...我就..這種說法內容)
if
?語句:if?語句用于根據條件執行不同的代碼。
語法格式
if (條件) {代碼塊}
var?age =?18;if(age >=?18){console.log("你好");}
if...else
?語句:當需要在條件為真和為假時分別執行不同的代碼時,可以使用?if...else
?語句。
語法格式
if?(條件) {代碼塊?1}?else?{代碼塊?2}
var?score =?60;if(score >=?60){console.log("及格");}else{console.log("不及格");}如果?`score >= 60`?為真,就執行代碼塊?1?,輸出 “及格”;否則執行代碼塊?2?,輸出 “不及格”。
if...else if...else
?語句:當有多個條件需要判斷時,可以使用?if...else if...else
?語句。
語法格式
if?(條件?1) {代碼塊?1}?else?if?(條件?2) {代碼塊?2}?else?{代碼塊?3}
var?num =?5;if(num >?10){console.log("大于 10");}else?if(num >?5){console.log("大于 5");}else{console.log("小于等于 5");}
循環語句
for
?循環:for?循環用于重復執行一段代碼,直到滿足特定條件為止。
語法格式
for?(初始化表達式; 條件表達式; 更新表達式) {代碼塊}* 解釋:* 初始化表達式:通常用于初始化循環變量。* 條件表達式:在每次循環開始前進行判斷,如果為真,則執行循環體;如果為假,則退出循環。* 更新表達式:在每次循環體執行完畢后更新循環變量。* 例如:for(let?i =?0; i <?3; i++){console.log(i);?// 輸出 0、1、2}這里初始化變量?`i`?為?0?,條件是?`i < 3`?,每次循環后?`i`?增加?1?。循環會執行?3?次,依次輸出?0、1、2。
while
?循環:while
?循環也是用于重復執行一段代碼,
while?(條件) {代碼塊}* 先判斷條件是否為真,如果為真,就執行代碼塊,然后再次判斷條件,直到條件為假。* 例如:let?count =?0;while(count <?3){console.log(count);?// 輸出 0、1、2count++;}如果不注意在循環體中更新變量(如這里的?`count++`?),可能會導致死循環,因為條件一直為真。
do...while
?循環:do...while
?循環和?while
?循環類似,但它的區別在于不管條件是否為真,都會先執行一次代碼塊,然后再判斷條件
語法格式
do?{代碼塊}?while?(條件);
{let?num =?1;?// 這個 num 只在這個花括號的作用域內有效do?{console.log(num);?// 輸出 num 的值num++;?// num 值加 1}?while?(num <=?5);?// 只要 num 小于等于 5,就繼續循環}
循環語句區別
條件判斷時機
for
?循環:在每次循環開始前都會先執行條件表達式的判斷。
while
?循環:同樣在每次循環開始前判斷條件,但沒有內置的初始化和更新表達式。
初始化和更新
for
?循環:將初始化、條件判斷和更新操作集中在一個語句中,結構更緊湊,適合有明確的初始化和更新邏輯的場景。
while
?循環:沒有內置的初始化和更新操作,需要在循環體內部手動處理。
執行條件
do...while
?循環:do...while
?循環會先執行一次循環體,然后才判斷條件。因此,它至少會執行一次循環體,即使條件一開始就不滿足。
for
?和?while
?循環:如果條件一開始就不滿足,循環體可能一次都不執行。
適用點
for?循環
適用場景:當你需要在循環中初始化一個變量,并且每次循環后需要更新這個變量時,for
?循環是一個很好的選擇。它將初始化、條件判斷和更新操作集中在一個地方,代碼更清晰。
示例:
遍歷數組或集合。
執行固定次數的循環。
for?(let?i =?0; i <?5; i++) {console.log(i);?// 輸出 0, 1, 2, 3, 4}
while
?循環
適用場景:當你需要在循環中動態地控制條件,或者循環的次數不確定時,while
?循環更適合。它更靈活,因為你可以根據需要在循環體中動態地改變條件變量。
示例:
讀取用戶輸入,直到用戶輸入特定的值。
執行一個任務,直到某個條件滿足。
let?num =?0;while?(num <?5) {console.log(num);?// 輸出 0, 1, 2, 3, 4num++;}
for
?循環:適合有明確的初始化和更新邏輯,循環次數相對確定的場景。
while
?循環:適合循環次數不確定,或者需要在循環體中動態控制條件的場景。
break
?語句
break
?語句用于完全終止當前的循環,跳出循環體,繼續執行循環之后的代碼。
當你需要在滿足某個條件時立即退出循環時,可以使用?break
。
常用于避免無限循環或在找到目標后提前退出循環。
const?numbers = [1,?3,?5,?12,?8,?15];for?(let?i =?0; i < numbers.length; i++) {if?(numbers[i] >?10) {console.log("找到第一個大于 10 的數字:", numbers[i]);break;?// 找到后立即退出循環}}console.log("循環結束");
continue
?語句
continue
?語句用于跳過當前循環的剩余部分,直接開始下一次循環迭代。
當你需要跳過某些特定條件的迭代,但仍然繼續執行后續的迭代時,可以使用?continue
。
常用于過濾掉不符合條件的元素,只處理符合條件的元素。
const?numbers = [1,?2,?3,?4,?5,?6];for?(let?i =?0; i < numbers.length; i++) {if?(numbers[i] %?2?!==?0) {continue;?// 如果是奇數,跳過當前迭代}console.log("偶數:", numbers[i]);}
break
?和?continue
?的區別
break
:
完全終止循環,跳出循環體,繼續執行循環之后的代碼。
用于提前退出循環。
continue
:
跳過當前迭代的剩余部分,直接開始下一次迭代。
用于跳過某些特定條件的迭代,但仍然繼續執行后續的迭代。
至此,語法語句內容完成
對象
接下來,來接觸一下對象
首先:此對象非彼對象,學校里面學好了說不定有對象
什么是編程中的對象呢:在 JavaScript 中,對象是一個獨立的、可以存儲多個值的實體,它由一系列的鍵值對(key-value pairs)組成。鍵(key)是對象的屬性名稱,值(value)可以是任何數據類型,包括數字、字符串、布爾值、函數(方法)等。你可以把對象想象成一個裝滿各種信息的“盒子”。
例如,一個描述人的對象:
let?person = {name:?"張三",age:?25,isStudent:?true,hobbies: ["閱讀",?"運動"],greet:?function() {console.log("你好,我叫"?+?this.name);}};// 調用 greet 方法person.greet();
在這個對象中:
name
、age
、isStudent
?是屬性,它們的值分別是?"張三"
、25
、true
。
hobbies
?是一個數組類型的屬性,它的值是包含兩個字符串的數組。
greet
?是一個方法(即對象中的函數,在下一篇會詳細介紹函數的),它可以輸出?"你好,我叫張三"
。
創建對象
方法:對象字面量
最常見的方式是使用對象字面量來創建對象,就像上面示例中的?person
?對象。這種方式簡單直觀,適合直接定義對象的屬性和方法。
語法:
let?對象名 = {屬性1: 值1,屬性2: 值2,// ...};
訪問對象的屬性和方法
方法1:點語法
console.log(person.name);?// 訪問屬性person.greet();?// 調用方法
方法2:方括號語法
console.log(person["name"]);person["greet"]();
添加、修改和刪除屬性
添加屬性
person.gender?=?"男"; // 添加屬性
修改屬性
person.age?=?26; // 修改屬性
刪除屬性
delete?person.age;?// 刪除屬性
對象的遍歷
(遍歷在之前的文章中講過,就是一個盒子里有很多小球然后一個一個拿出來)
可以使用?for...in
?循環來遍歷對象的屬性:
for?(let?key?in?person) {console.log(key +?": "?+ person[key]);}
可能聽的云里霧里的,之后會有一篇關于傳統前端實戰的分析文章
數組
接下來我們來了解數組
什么是數組:數組是一種非常常用的數據結構,用于存儲一組有序的值。這些值可以是數字、字符串、對象,甚至是其他數組。數組中的每個值都有一個索引(從 0 開始),可以通過索引來訪問和操作數組中的元素。
(類似于我們學過的數學里的集合,但只是表現上類似而已)
創建數組
方法 :數組字面量
這是最常用的方式,直接用方括號?[]
?包裹一組值。
let?fruits = ["蘋果",?"香蕉",?"橙子"];let?numbers = [1,?2,?3,?4,?5];let?mixed = [1,?"hello",?true, {?name:?"張三"?}, [1,?2,?3]];
訪問數組元素
數組中的每個元素都有一個索引,從 0 開始。可以通過索引來訪問和修改數組中的元素。
let?fruits = ["蘋果",?"香蕉",?"橙子"];// 訪問元素console.log(fruits[0]);?// 輸出 "蘋果"console.log(fruits[1]);?// 輸出 "香蕉"// 修改元素fruits[1] =?"草莓";console.log(fruits);?// 輸出 ["蘋果", "草莓", "橙子"]
數組的常用方法
添加和刪除元素
push()
:向數組末尾添加一個或多個元素,并返回新數組的長度。
fruits.push("葡萄");console.log(fruits);?//?輸出 ["蘋果",?"草莓",?"橙子",?"葡萄"]
pop()
:從數組末尾移除一個元素,并返回被移除的元素。
let removedItem = fruits.pop();console.log(removedItem);?//?輸出?"葡萄"console.log(fruits);?//?輸出 ["蘋果",?"草莓",?"橙子"]
shift()
:從數組開頭移除一個元素,并返回被移除的元素。
let?firstItem = fruits.shift();console.log(firstItem);?// 輸出 "蘋果"console.log(fruits);?// 輸出 ["草莓", "橙子"]
unshift()
:向數組開頭添加一個或多個元素,并返回新數組的長度。
fruits.unshift("櫻桃");console.log(fruits);?//?輸出 ["櫻桃",?"草莓",?"橙子"]
查找元素
indexOf()
:查找某個值在數組中的索引,如果找不到返回?-1
。
let?index = fruits.indexOf("橙子");console.log(index);?// 輸出 2
(因為計數的時候第一個數字記為0,也就是說你覺的蘋果應該是1但他的序號實際為0)
includes()
:檢查數組是否包含某個值,返回布爾值。
console.log(fruits.includes("草莓"));?// 輸出 trueconsole.log(fruits.includes("西瓜"));?// 輸出 false
遍歷數組
for
?循環
for?(let?i =?0; i < fruits.length; i++) {console.log(fruits[i]);}
數組的拷貝和拼接
slice()
:返回數組的一個淺拷貝,不會修改原數組。
let?newFruits = fruits.slice(1,?3); // 從索引?1?到?3(不包括?3)console.log(newFruits); // 輸出?["草莓", "橙子"]
concat():將多個數組拼接成一個新數組,不會修改原數組。
let?moreFruits = ["西瓜",?"芒果"];let?allFruits = fruits.concat(moreFruits);console.log(allFruits); // 輸出 ["櫻桃",?"草莓",?"橙子",?"西瓜",?"芒果"]
數組的排序
sort()
:對數組進行排序,會修改原數組。
let?numbers = [3,?1,?4,?1,?5,?9];numbers.sort();console.log(numbers);?// 輸出 [1, 1, 3, 4, 5, 9]
如果需要按照數值大小排序,需要提供一個比較函數:
numbers.sort(function(a, b) {return?a - b;?// 升序});console.log(numbers);?// 輸出 [1, 1, 3, 4, 5, 9]
數組的過濾和映射
filter()
:創建一個新數組,包含通過測試的所有元素,不會修改原數組。
let?evenNumbers = numbers.filter(function(num) {return?num %?2?===?0;});console.log(evenNumbers);?// 輸出 [4]
map()
:創建一個新數組,其元素是調用一次提供的函數后的返回值,不會修改原數組。
let?squaredNumbers = numbers.map(function(num) {return?num * num;});console.log(squaredNumbers);?// 輸出 [1, 1, 9, 16, 25, 81]
由于沒有足夠的實際生活應用,所以大家可能會覺得很莫名其妙,但是現在只要了解基礎理論就行了,后面會有實踐內容的
函數
在數學中函數的概念就像機器人一樣,通過特定的指令做出特定的動作,在JavaScript開發中概念也差不多
函數的定義
函數是代碼塊,用于執行特定行為。在 JavaScript 中,可以通過多種方式定義函數。
函數聲明:
以 function 關鍵字開頭,后面跟著函數名、參數列表(括在圓括號中,用逗號分隔)和函數體(用大括號括起來)。
function?functionName?(parameter1, parameter2, ...)?{// 函數體,執行的代碼// 可以使用 return 語句返回值}
我們來分析一個例子
function?addNumbers (num1, num2) {let?sum?= num1 + num2;return?sum;}這里定義了一個名為?addNumbers 的函數,它接收兩個參數?num1 和 num2,將它們相加并將結果存儲在變量?sum?中然后通過?return?語句返回這個結果。
函數表達式:
它將函數賦值給一個變量。可以是匿名函數或者有名字的函數
const?functionName =?function?(parameter1, parameter2, ...) {// 函數體};
比如
const?multiplyNumbers =?function?(num1, num2) {return?num1 * num2;};
或者
const?divideNumbers?=?function?division?(num1, num2)?{return?num1 / num2;};
這樣做的好處是函數可以作為一個值來傳遞,比如在事件處理等場景中非常有用。
函數的調用
調用函數時,使用函數名后跟一對圓括號,括號中包含實際參數(實參)。
let?result = addNumbers (5,?3);console.log?(result);?// 輸出 8
這里調用了之前定義的?addNumbers
?函數,傳入了實際參數 5 和 3,函數執行后返回它們的和 8,然后將這個結果賦值給變量?result
。
函數的參數
默認參數?:在定義函數時,可以給參數指定默認值。如果調用函數時沒有提供對應的參數,就會使用默認值。
function?greet?(name =?"Guest") {console.log?(`Hello,?${name}!`);}greet ();?// 輸出 "Hello, Guest!"greet ("Alice");?// 輸出 "Hello, Alice!"
參數的類型檢查?:在 JavaScript 中,參數的類型是動態的。可以在函數內部使用?typeof
?運算符來檢查參數類型
function?checkType?(value) {console.log?(`The type of the parameter is:?${typeof?value}`);}checkType (123);?// 輸出 "The type of the parameter is: number"checkType ("Hello");?// 輸出 "The type of the parameter is: string"
函數的返回值
使用?
return?語句可以將值返回給調用者。如果函數中沒有?
return?語句,或者?
return?后面沒有值,返回值是 undefined。
function?sayHello?() {console.log?("Hello!");}let?result = sayHello ();console.log?(result);?// 輸出 undefined
這個函數只是輸出了 "Hello!",沒有返回任何值,所以?result
?的值是?undefined
。
函數的作用域
函數作用域?:在函數內部聲明的變量只能在函數內部訪問,這是函數作用域。而變量的聲明方式會影響其作用域。
function?createVariable?() {var?functionScopedVar =?"I'm function - scoped";console.log?(functionScopedVar);}createVariable ();?// 正常輸出// console.log (functionScopedVar); // 會報錯,因為變量只在函數內部
高階函數
函數可以作為參數傳遞給其他函數。
function?execute?(func, value)?{return?func?(value);}function?double?(num)?{return?num *?2;}let result =?execute?(double,?5);console.log?(result);?// 輸出 10
這里?execute
?是一個高階函數,它接收一個函數?func
?和一個值?value
?作為參數,然后調用?func
?函數并將?value
?傳遞給它。
函數可以作為返回值從其他函數返回。
function?createMultiplier?(multiplier) {return?function?(num) {return?num * multiplier;};}let?triple = createMultiplier (3);console.log?(triple (5));?// 輸出 15
閉包
閉包是一個函數及其詞法環境的組合。它可以訪問其詞法作用域中的變量。
function?createCounter?() {let?count =?0;return?function?() {count++;return?count;};}let?counter = createCounter ();console.log?(counter ());?// 輸出 1console.log?(counter ());?// 輸出 2
這里?createCounter
?函數返回了一個閉包函數。閉包函數可以訪問?createCounter
?函數中的變量?count
,并能夠修改它。每次調用閉包函數時,count
?的值都會增加并返回新的值。
遞歸函數
遞歸函數是指在函數內部調用自身的函數。
function?factorial?(n) {if?(n ===?0) {return?1;}?else?{return?n * factorial (n -?1);}}console.log?(factorial (5));?// 輸出 120
這個?factorial
?函數計算了 5 的階乘。它不斷調用自身,每次將參數減 1,直到參數為 0 時返回 1,然后逐層返回計算結果。
立即調用函數表達式(IIFE)
它是一種定義并立即執行的函數模式,用于創建一個封閉的作用域,避免污染全局作用域。
(function?() {let?privateVariable =?"I'm private";console.log?(privateVariable);})();// console.log (privateVariable); // 會報錯,變量在 IIFE 內部
這個函數定義后立即執行,privateVariable
?在 IIFE 內部被聲明和使用,外部無法訪問它。
類
類的基本定義
使用?class
?關鍵字定義一個類,類名首字母通常大寫,以區分于其他變量名。
class?MyClass?{//?類體}
示例:定義一個簡單的 “Person” 類,用于表示一個人。
class?Person?{//?類體暫時為空}
構造函數
構造函數是一個特殊的方法,用于初始化對象的屬性。它使用?constructor
?關鍵字定義。
當使用?new
?關鍵字創建類的實例時,構造函數會被自動調用。
示例:在 “Person” 類中添加構造函數,用于初始化人的姓名和年齡。
class?Person?{constructor(name, age) {this.name?= name;?// 將傳入的 name 參數賦值給對象的 name 屬性this.age?= age;?// 將傳入的 age 參數賦值給對象的 age 屬性}}// 創建 Person 類的實例const?person1 =?new?Person('Alice',?25);console.log(person1.name);?// 輸出:Aliceconsole.log(person1.age);?// 輸出:25
類的方法
在類中定義的方法是對象的行為,用于實現對象的功能。
方法的定義方式與普通函數類似,但要寫在類的內部。
示例:在 “Person” 類中添加一個方法,用于打印個人信息。
class?Person?{constructor(name, age) {this.name?= name;this.age?= age;}// 定義一個方法introduce() {console.log(`My name is?${this.name}, I am?${this.age}?years old.`);}}const?person1 =?new?Person('Alice',?25);person1.introduce();?// 輸出:My name is Alice, I am 25 years old.
類的繼承
通過繼承,一個類可以繼承另一個類的屬性和方法,從而實現代碼的復用。
使用?extends
?關鍵字實現繼承,子類通過?super()
?關鍵字調用父類的構造函數。
示例:創建一個 “Student” 類,它繼承自 “Person” 類,用于表示學生。
class?Person?{constructor(name, age) {this.name?= name;this.age?= age;}introduce() {console.log(`My name is?${this.name}, I am?${this.age}?years old.`);}}// Student 類繼承 Person 類class?Student?extends?Person?{constructor(name, age, grade) {super(name, age);?// 調用父類的構造函數,初始化 name 和 agethis.grade?= grade;?// 子類獨有的屬性}// 子類自己的方法study() {console.log(`I am a student in grade?${this.grade}.`);}}const?student1 =?new?Student('Bob',?18,?'10th');student1.introduce();?// 繼承自父類的方法student1.study();?// 子類自己的方法
靜態方法和屬性
靜態方法和屬性屬于類本身,而不是類的實例。使用?static
?關鍵字定義。
靜態方法通過類名直接調用,靜態屬性也通過類名訪問。
示例:在 “Person” 類中添加一個靜態方法和一個靜態屬性。
class?Person?{constructor(name, age) {this.name?= name;this.age?= age;}introduce() {console.log(`My name is?${this.name}, I am?${this.age}?years old.`);}// 靜態方法static?sayHello() {console.log('Hello, everyone!');}// 靜態屬性static?species =?'Homo sapiens';}Person.sayHello();?// 調用靜態方法console.log(Person.species);?// 訪問靜態屬性
訪問修飾符
在 JavaScript 中,類的屬性和方法默認都是公開的(public),即可以在類的外部訪問。
也可以使用?#
?來定義私有屬性和方法,它們只能在類的內部訪問。
示例:在 “Person” 類中添加一個私有屬性和一個私有方法。
class?Person?{constructor(name, age) {this.name?= name;this.age?= age;this.#privateData =?'This is private data';?// 私有屬性}introduce() {console.log(`My name is?${this.name}, I am?${this.age}?years old.`);this.#privateMethod();?// 調用私有方法}// 私有方法#privateMethod() {console.log(this.#privateData);}}const?person1 =?new?Person('Alice',?25);person1.introduce();// 以下代碼會報錯,因為無法在類外部訪問私有屬性和方法// console.log(person1.#privateData);// person1.#privateMethod();
接下來我們整合內容,分析一個全面的實例
示例
目標
創建一個簡單的圖書管理系統,包含以下功能:
定義圖書類(Book
),包含書名、作者和頁數。
定義圖書館類(Library
),可以添加圖書、列出所有圖書、借閱圖書和歸還圖書。
使用數組存儲圖書數據。
使用函數實現圖書的借閱和歸還邏輯。
使用類的繼承擴展功能。
// 數據類型// 基本數據類型:String, Number, Boolean, Undefined, Null// 復合數據類型:Object, Array// 運算// 算術運算符:+、-、*、/、%// 比較運算符:==、===、!=、!==、>、<、>=、<=// 邏輯運算符:&&、||、!// 語法語句// if...else、for、while、switch// 對象// 使用對象表示圖書const?book1 = {title:?'JavaScript高級程序設計',author:?'Nicholas C. Zakas',pages:?600,isAvailable:?true};const?book2 = {title:?'你不知道的JavaScript',author:?'Kyle Simpson',pages:?300,isAvailable:?true};// 數組// 使用數組存儲圖書const?books = [book1, book2];// 函數// 借閱圖書的函數function?borrowBook(book) {if?(book.isAvailable) {book.isAvailable?=?false;console.log(`您已成功借閱《${book.title}》。`);}?else?{console.log(`《${book.title}》當前不可借閱。`);}}// 歸還圖書的函數function?returnBook(book) {book.isAvailable?=?true;console.log(`您已成功歸還《${book.title}》。`);}// 類// 定義圖書類class?Book?{constructor(title, author, pages) {this.title?= title;this.author?= author;this.pages?= pages;this.isAvailable?=?true;}}// 定義圖書館類class?Library?{constructor() {this.books?[];= ?}// 添加圖書addBook(book) {this.books.push(book);console.log(`圖書《${book.title}》已添加到圖書館。`);}// 列出所有圖書listBooks() {console.log('圖書館中的圖書:');this.books.forEach(book?=>?{console.log(`-?${book.title}(作者:${book.author},頁數:${book.pages},狀態:${.isbookAvailable ??'可借閱'?:?'已借出'})`);});}// 借閱圖書borrowBook(title) {const?book =?this.books.find(book?=>?book.title?=== title);if?(book) {if?(book.isAvailable) {book.isAvailable?=?false;console.log(`您已成功借閱《${book.title}》。`);}?else?{console.log(`《${book.title}》當前不可借閱。`);}}?else?{console.log(`圖書館中沒有找到《${title}》。`);}}// 歸還圖書returnBook(title) {const?book =?this.books.find(book?=>?book.title?=== title);if?(book) {book.isAvailable?=?true;console.log(`您已成功歸還《${book.title}》。`);}?else?{console.log(`圖書館中沒有找到《${title}》。`);}}}// 類的繼承// 定義一個特殊圖書館類,繼承自 Libraryclass?SpecialLibrary?extends?Library?{constructor() {super();this.specialBooks?= [];}// 添加特殊圖書addSpecialBook(book) {this.specialBooks.push(book);console.log(`特殊圖書《${book.title}》已添加到特殊圖書館。`);}// 列出特殊圖書listSpecialBooks() {console.log('特殊圖書館中的特殊圖書:');this.specialBooks.forEach(book?=>?{console.log(`-?${book.title}(作者:${book.author},頁數:${book.pages},狀態:${book.isAvailable ??'可借閱'?:?'已借出'})`);});}}// 測試代碼// 創建圖書館實例const?myLibrary =?new?Library();// 創建圖書實例const?book3 =?new?Book('JavaScript權威指南',?'David Flanagan',?1200);const?book4 =?new?Book('深入理解計算機系統',?'Randal E. Bryant',?1000);// 添加圖書到圖書館myLibrary.addBook(book3);myLibrary.addBook(book4);// 列出所有圖書myLibrary.listBooks();// 借閱圖書myLibrary.borrowBook('JavaScript權威指南');myLibrary.listBooks();// 歸還圖書myLibrary.returnBook('JavaScript權威指南');myLibrary.listBooks();// 創建特殊圖書館實例const?specialLibrary =?new?SpecialLibrary();// 添加特殊圖書specialLibrary.addSpecialBook(book1);specialLibrary.addSpecialBook(book2);// 列出特殊圖書specialLibrary.listSpecialBooks();
數據類型:使用了基本數據類型(如字符串、數字、布爾值)和復合數據類型(對象、數組)。
運算:在判斷圖書是否可借閱時使用了比較運算符和邏輯運算符。
語法語句:使用了?if...else
、for
、while
?等語句。
對象:通過對象表示圖書,包含書名、作者、頁數和是否可借閱的狀態。
數組:使用數組存儲圖書數據,方便管理和遍歷。
函數:定義了借閱和歸還圖書的函數,封裝了邏輯。
類:定義了?Book
?類表示圖書,Library
?類表示圖書館,SpecialLibrary
?類繼承自?Library
?類,擴展了功能。
至此,JavaScript完成,傳統前端開發也完成了