【Javascript教学课程 (入门篇) 】12个章节 - 由浅入深学习Javascript

直至2021年的今天,Javascript其实已经是无所不能。

除了可以制作网站的前端开发,它还可以拿来做后台,例如:nodejs、app、react、vue、ionic。

在这篇「Javascript教学课程 (入门篇)」,我分开了12个章节,让你由浅入深学习Javascript,包括:

  • Javascript 基本概念
  • 变数 (Variable)
  • 函数 (Function)
  • Logic: If...else
  • Logic: while
  • Logic: For loop
  • Array
  • Object
  • Callback Function
  • Redirection
  • 处理String
  • Debug

准备好了吗?我们开始吧!

目录

第1章

Javascript 基本概念

第2章

变数 (Variable)

第3章

函数 (Function)

第4章

Logic: If...else

第5章

Logic: while

第6章

Logic: For loop

第7章

Array

第8章

Object

第9章

Callback Function

第10章

Redirection

第11章

处理String

第12章

Debug

第1章Javascript 基本概念

当大家学习了HTML及CSS的语言后,现在终于来到Frontend最后一个要学习的语言,就是Javascript。

直至2021年的今天,Javascript其实已经是无所不能。

除了可以制作网站的前端开发,它还可以年来做后台,
例如:node js、app、react、angular、ionic。

如果大家想学习好Javascript,练习好基本功,是非常重要!

今天,我会与大家由浅入深,一起学习Javascript的Programming。

准备好了?我们开始吧!

Javascript 基本概念

第一课要了解的,就是什么是Javascript,其实Javascript是一种很厉害的语言。

因为无论你需要制作的是frontend、backend、app还是website,基本上是甚么都能做得到。

其实之前大家学习的html及css,都不是真的programing language,而Javascript才是真正的编程语言。

*如果你还不会HTML, 请先学习: HTML教学课程 (入门篇)


首先,我们一起在桌面开一个「javascript」的文件夹,然后打开visual studio code软件。


在visual studio code按 File,选择Open。


然后选择桌面「javascript」的文件夹,按打开 / Open。


在左手方位置,按右键开一个New File,


文件名称可以输入「index」,记得文件的名称为index.html。

我们首先输入一个script Tag,在这个tag里面所运行的语法,
不再是html语法,而是javascript语法。


对于每一个第一次学习javascript的朋友们,第一句输入的句子是:

alert('Hello World!');


储蓄后,用Chrome打开它,来运行这句源码。

如果你运行成功,应该会像上图般,
弹了一个alert box视窗,写著「Hello World!」。

记得每写完一个javascript句子,都要加上一个「;」


如果你输入了上图般的3句alert box,


你就发现,视窗会一句一句地运行显示。


如果有时候,你只想运作第一及第二行,第三行不想运作的话,

我们只需要在不想运行的句子前面,加上「//」便可以了。

「//」是代表Comment,
意思是程式不会运作,只是让我们编程员去看而已。


这里要注意的是,「//」只限用了一行的,
如果要用于几行,便要输入「/* 内文 */」。

这种输入法,只要是/*与*/中间的内文,都不会运行的,无论是多少行都是一样的。

如果有什么code不想运行的,便可以用上以两种输入法来实行。

第2章变数 (Variable)

了解完Javascript基本概念后,正式进入写编程第一个要学的概念便是 - 变数 (Variable)。

变数的意思,就如小学代数般。

变数可以代表著很多类别,这些类别,我们称之为data type。

准备好了?我们开始吧!

变数 (Variable)

了解完Javascript基本概念后,正式进入写编程第一个要学的概念便是 - 变数 (Variable)。

我们先去看看这个有关Variable介绍的Youtube录像,大概一分钟左右:

看完录像后,我们学到的第一个概念就是变数,变数意思就如小学代数般。

例如:
X + 1 = 5

那么:
X是什么?X就是4

小学代数就代表一个数字,可是在编程的世界里,变数可以代表著很多类别,
这些类别,我们称之为data type。

以下是一些常用的data type:

  • Integer (数字)
  • Float (有小数点的数字)
  • String (文字)
  • Boolean(TRUE/FALSE)
  • Array (数组)
  • Object (物件)

我会先从这3个简单功能与大家分享,好让大家简单明了,
包括:Integer (数字)、Float (有小数点的数字)及String (文字)。

Integer (数字)

让我们先学习Integer (数字)。


要定义一个变数,你可以使用var,或直接为一个变数指派一个数值:

我们一起输入:
var x =1;

在javascript语法中,你是不需要定义这个变数是什么data type的,

例如,它是string还是integer,

你只需要直接给它输入一个value就可以。


我们一起在var下层输入:
alert(x);

储存后打开Chrome看看,是不是山现了「1」这个数字呢。

可能有朋友会问,为何不是出x?

因为x是一个变数,而你现在是alert这个变数,所以就会显示出1。

关于变数的设定上,其实我们也可以去做一些算术。


我们一起在var下层输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


上图大家看到:

输入 x = 1,y = x + 3,
所以alert x 是出4。

从以上的例子可见,变数若是Integer (数字)的话,你是可以为它们进行运算的。

  • y = x + 10 (加)
  • y = x - 10 (减)
  • y = x * 10 (乘)
  • y = x / 10 (除)
  • y = x % 2 (余数)

Float (有小数点的数字)

Integer (数字)是齐数的数字,如果有时候需要显示小数点,我们就会利是用到Float。

Float (有小数点的数字)和Integer (数字)是一模一样。只不过Float的数字是点数,而Integer的数字是整数。

String (文字)

数字以外,还有另一种变数是string (文字)。


若变数储存的是String(文字)的话,你则需要利用一个单引号'或双引号"包著它,例如:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



从以上的例子可见,alert这个temp,我们做了一个变数为z,

上图加了一个var temp,用了z + ‘内文’,这就是Combine string,意思是将两条字串串连起来。

如上图的' I am Jack' + ' he is COOL' ,
就会显示出「I am Jack and he is COOL」。


如果我把alert的temp加入引号,无论是单引号或是双引号,它就是一个字串。

所以它会显示「temp」这个文字,而不是var temp的内容。


其实这里还可以继续输入的,
例如在alert括号入面输入「temp + and he is fine」。

所以它会显示出:

I am Jack and he is COOL and he is fine

所以大家现在知道字串的用法了吧,以上这些功能,便是string的用法了。

在现阶段,你先学习这3种Data Type。

其他的data type,如Array (数组)及Object (物件)等,
会在接下来的章节深入讨论。

第3章函数 (Function)

当我们在编程时,许多时都要重复去写一些同样的东西。

为了避免浪费时间,去写同样的东西,我们便可以使用函数 (Function)。

函数 (Function)用作把一段program包著,让你日后可以重复使用。

今天,我会与大家由浅入深,一起学习函数 (Function)。

准备好了?我们开始吧!

函数 (Function)

函数 (Function)是另一个非常重要的编程概念。你可以先看看以下影片:

当我们在编程时,许多时都要重复去写一些同样的东西。为了避免浪费时间,去写同样的东西,我们便可以使用函数 (Function)。

函数 (Function)用作把一段program包著,让你日后可以重复使用。


现在我们一起看看这个例子,例如我有一段code是这样的:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



如果以上两段code会经常用到的,我们便可以使用Function来包著:

function alertx(){}

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


{}是叫做scope的bracket,意思记是在{}里面的内容,define这一个function。

上文只是定义了这个function,如果用Chrome把网站打开,其实是什么都没有。


所以,如果要用这个function,你就需要call这个function,所以你需要输入:

alertx();


同样地,如果输入三次「alertx();」,就会运行三次这个function。

这里可以注意的是,当你看到define一个function,alertx括号。大家可以记住,只要一见到括号,就知道它就是function了。

你看上图的alertx有括号,正正是代表著运行上层那行function。


如果大家有留意,alert()本身就是function这个功能,直接输入便能使用。

除javascript本身设定的function外,我们也可以自行定义一些function。


另外在alert()后面,你会见到这个{}括号,这是非常常见的scope bracket来的。

{}是一个scope bracket,我们会用它去包著function的内容。

在scope内定义的variable,叫local variable。

意思是这些variable只能在这个scope内使用,在scope外并不可以取存这些variables。


比如{}内的alert(x),是不能显得x出来的,因为图中的alert(x)只能在local variable使用。


所以必须要外面定义,比如上图的:

var y = 1;
这样,才能alert到1出来。


Functions更可以接受parameter,例如输入在:

alertx(x)

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


这时候,我们每次call这个functions,都可以定义这个x是什么。

例如第一次alert是1,
第二次alert是3。

这是一个很重要的概念来,就是可以自行take parameter。

虽然大定都是同一个function,
但是当parameter不同,output出来的东西就会有所不同。


这些paramete是可以多过一个的,例如输入一个逗号y,逗号z。

然后内层增加一个新的变数:

var temp = x * y + z -1;
内层alert(temp);
然后alertx(2,3,5);

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


再用Chrome把网站打开,就会显示出10这个数字了。

这个就是function的厉害之处了,当你输入了一些program后,就可以造一些parameter出来,

只要每一个call这个function,输入不同的parameter,计算出来的东西就会不同。

Return

我们接著了解更多的function,而其中还有一样很重要功能,就是叫return。

按以下例子,我们先输入以下格式:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


再用Chrome把网站打开,就会显示出这样的效果:


我们如果不在这里alert,又能怎样改动呢?


我们可以把alert del,然后需要输入一条string,比如是输入:

var temp =


然后在下层输入:

return temp;

可能你会问,这个return到底是什么输入法来的?

return输入法,原来是我pass了内里一些东西入去,它最尾会return回一个variable。

比如我一call calAge这个function后,它就会return回一个variable出来的。

意思即是我们在外面,其实可以收回这个variable。


所以这里我们要更改输入:

var x = calAge(2019,1990);

因为现在calAge,是会return一个东西,

Return了temp这个东西,而temp就会被pass到x那里。


接著输入:

alert(x);

再用Chrome把网站打开,就会显示出上图的结果了。

再来输入一次,内容是这样的:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


有时候,我们都可以在这个算式中再加入一些东西,


比如var x下层再输入:

x = '***' + x;

结果就会得出:

***I was born at year1990. I am 29 years old.

以上就是return的输入方法了!

要记得我们在使用这个function时,需要再设立一个新的变数(在以上例子就是temp),去储存这个function return回来的数值。

第4章Logic: If...else

正常的Program,是会一句一句的跟著去运行。

然而,在某些情况下,我们只想运行某一部份的Program。

在另一些情况下,又只运行另一部份的Program。

这时候,我们便要利用编程中的一个非常重要的概念,就是Condition。

最常用控制condition的方法,就是通过if...else来控制。

准备好了?我们开始吧!

Logic: If...else

来到下一个概念,就是condition,意思是正常的Program,会一句一句的跟著去运行。

然而,在某些情况下,我们只想运行某一部份的Program。

在另一些情况下,又只运行另一部份的Program。

这时候,我们便要利用编程中的一个非常重要的概念,就是Condition。

我们先看看这段影片:

我们最常用控制condition的方法,就是通过if...else来控制的。


我们一起输入:

if (){ }

然后增加一个变数:

var x = 1;
If括号中输入,x > 1
然后alert(' x is bigger than 1')

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



接著下层输入:

else{alert(' x is smaller than 1')}

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


我们一起细看,整个内容到底是代表著什么呢?

意思是:

x等于1,如果x大于1,就会行x是大于1的那段code。
如果不是,就会会行x是小于1的那段code。


所以当x=1时,结果就会是运行「else」那一段。


同样地,我将x更改为等于5,结果就会是运行「if」那一段。


这里,有一个重要要点要注意的,就是图中x>1那个括号位置。

括号()中间代表condition,当condition符合成立时,便会运行接下来的Program。

在condition中,我们会用到一些Compare Expression。

以下是6种常用的Compare Expression:

  • == 等于
  • != 不等于
  • > 大过
  • >= 大过或等于

我们也可以建立更复杂的condition,例如输入:

var y = 0;
if (x == 1 && y == 0){alert('condition1')}
else{alert('elsecondition')}

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


&&代表and。

表示两个condition必须皆符合,整个condition才算符合。


所以当x=1与y=0都符合要求,就会得出「condition1」。


现在我更改y=10,y不再是等于0时,结果就会得出「elsecondition」。


接著我再把&&更改成||,结果又会变回「condition1」。

||代表or。

表示两个condition,只要有一个符合,整个condition便会符合。

这里温馨提供一下,if括号内是不只是两种,还可以不断增加各类condition条件。

else if

除了if 和else外,我们也可以使用else if。

当if的condition不成立时,便会运行接下来的else if。

如果这次的condition也不成立,便会再运行接下来的else if,直到condition成立,或是运行else。


我们一起输入:

Var x = 9;
else if (x > 8){alert('condition2')}

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


你会发现,if增加了一个新的condition是else if,
只要条件对if不成立,便会运行接下来的else if,
所有的else if不成立,便会运行接下来的else。

所以你会看到得出了「condition2」的结论。


现在我再输入多一个else if,今次条件是x > 5,

而var x = 6,得出的结论就是「condition3」。

不过大家要注意的是,
else if在同一个比较语句中,可以使用很多次,但else就只能使用一次。

以上便是if、else if、else的基础教学了,大家努力练习吧。

第5章Logic: while

接下来,我们会学习另外一个概念 - Loop。

在javascript,常见的loop有两种的:。

第一种叫做while loop,第二种就叫for loop。

有时候,一些指令需要不断重复去执行,我们便会使用Loop。

准备好了?我们开始吧!

Logic: while

接下来,我们会学习另外一个概念 - Loop。

有时候,一些指令需要不断重复去执行,我们便会使用Loop。

可以看看以下短片:

在javascript,常见的loop有两种的,
第一种叫做while loop,
第二种就叫for loop。

我们先一起看看while loop。

首先输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



与if...else一样,while()内的是condition。

当这个condition成立时,电脑会不断去重复运行当中的program。

在以上的例子,由于1永远是等于1,因此,以上的program的123会不断重复去运行。

第6章Logic: For loop

有时候,一些Program需要的不是无限量地loop,比如是有限量的loop。

这时候,你就需要学习使用For loop的功能。

准备好了?我们开始吧!

Logic: For loop

如果有时候,

你的program需要的不是无限量地loop,比如是有限量的loop。

来看看以下短片:

我们一起输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



在以上的例子,这个loop会运行9次。

让我们在了解一下(i=0;i

i=0,是variable i的初始状态。
ii++,代表每过一个loop,i的数值都会加1。

一开始i的数值是0运行了一遍后,i的数值加了1,变成1。

但由于它还是少于10,因此它由会运行多一遍。

运行多一遍后,i的数值再加1,变成2。但由于它还是少于10,因此它又会再运行多一遍。

如此类推,直到i变成10的时候,i不再少于10,这个loop便会中断了,所以最多只会运行至9。

学到这里,大家大概都明白到for loop的功能了吧。

第7章Array

Array的中文是「数组」,意思是一组相似的数据,通常会使用这个功能去表达。

这时候,你就需要学习使用Array的功能,来整合你的数据。

准备好了?我们开始吧!

Array

来到下一章,我们要学习 - Array。

Array的中文是「数组」,意思是一组相似的数据,通常会使用[]去表达。

比方说,我有一班学生,一共有30人。

要在电脑记下他们的名字,与其建立30个变数,倒不如只建立一个变数,其data type是array。

这样,我们只用一个变数,便可以储存这30人的名字了。

我们一起输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


在以上的例子,我们定义了一个array 叫people。

内里有3个数值(jack,peter及jenny),每一个数值用去分隔。


people[0]代表这个array中的第1个数值,就是jack。
people[1]代表这个array中的第2个数值,就是peter。
people[2]代表这个array中的第3个数值,就是jenny。

由于这个叫people的array共有3个数值,因此,它的长度是3。

要注意array的第一个数值,是[0],不是[1]。

关于array的操作有很多,比方说:

为array新增一个数值,删除数值,排序...你不用全部背进脑里。

其实关于array其实有好多不同的function可以用,大家可以按以下延伸阅读来了解更多不同的array设定。

延伸阅读:

Array Functions:
https://www.w3schools.com/js/js_array_methods.asp
Array Sorting:
https://www.w3schools.com/js/js_array_sort.asp


比如,我想为array新增一个数值,原来可以使用push()来新增:

people.push('jan');

这时候,你会发现alert[3]就可以成功显示新的值。

另外一个比较常用的用法,是array会配合for去使用:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


我们一起看看for loop中的意义是什么:

i=0:由于i等于0,代表people[]就是jack。
iI++:接著i等于2,所以是jenny。


其实这里也有一个较好的输入法,就是有时候你不会知道这个array的大小是甚么,

所以我们在这里可以直接用:

people.length

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


这个输入法,会把array里的所有东西都loop出来了。

.length会返回array的长度。与for loop配合一流!

这是一个array的常用输入法来的,大家记得努力练习吧。

第8章Object

Object是我们要学习最后的一个data type,

功能上Object比Array更为强大,

因为它可以储存一大组不同data type的数据,甚至是functions。

这时候,你就需要学习使用Object的功能。

准备好了?我们开始吧!

Object

Object是我们要学习最后的一个data type,

我们通常会用{}去表达。

Object比Array更强大,

因为它可以储存一大组不同data type的数据,甚至是functions。

我们来看看Object的写法:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



在上面的例子,我们建立了一个名为person的object。

里面有多个variable,包括:

name、age、job等等,
每个variable会有自己的数值。

我们可以利用.去输出这个object的variable。例如:

person.name

输入后,就会得出jack这个结果。

温馨提示:

object里面的variable,学名称为property;
object里面的function,学名称为method。


我们一起尝试输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


Object内的Variable也可以是Array,如上面的例子般。

当然,我们可以使用for loop去输出这个object入面Array的数值:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



这个object里面,我们还可以增加一些function叫personalStatement:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


输入后,你会发出这个结果:

My name is jack and my job is IT


这里我会慢慢解释,到底发生什么事情。

其实this.name的this,是这一个function的拥有者,就是person。

所以这个person.name,就会拿到'jack'。


从以上object,你可以见到会有properties,包括有:name、age、job、schools这些普通的variables。


也会declare一些function,就是method。


其实这里你可能会问,我们这里define function,没有给function起名字。

有些function是不需要有名的,因为你只会用一次而已。

这些没有名的function,我们称它为anonymous function。


另外. 有一种常见的结构化资料,叫JSON。

原来, 当你看到如上图般,全部使用双引号的javascript object,就是JSON。

javascript内的object可演变成JSON,JSON是一种常用数据格式,用于资料传输。

JSON将来我会更详细与大家分享,这里先让大家了解初步概念为止。

以上便是Object的基本概念教学,大家记得多加练习喔。

第9章Callback Function

Callback Function是一个比较深层次的概念。

代表当一个Function运行完后,接下来会运行另一个Function。

这个Function,我们称之为Callback Function。

准备好了?我们开始吧!

Callback Function

Callback Function是一个比较深层次的概念。

代表当一个Function运行完后,接下来会运行另一个Function。

这个Function,我们称之为Callback Function。


首先我们一起在Chrome Google:settimeout


原来javascript里有一个function称为setTimeout。


在这页面中,拉下一点,你会发现这个function,是会take一些parameter。

第一个parameter,会take一个function;
第二个parameter,会take一个秒数(毫秒milliseconds);

毫秒是什么来的?我们一起输入看看:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


在以上的例子,3000就代表3秒(javascript的时间是以毫秒计算的)。

因此,3秒后,它便会运行function(){}。

Callback Function 由于只运行一次,我们通常都不用为这个Function改名,直接用function(){}便可以。

这些不用改名的Function,我们 称之为Anonymous Function。


因此,你会看到,等待3秒后,会出现alert「123」及「456」。

所以,现在你明白到,setTimeout的使用方法了吧。

以上便是Callback Function的基本概念教学了。

第10章Redirection

很多朋友都会问,Javascript有没有redirect页面的功能?

其实,Javascript也可以redirect页面的。

如果在你的程式设计上,非常需要用到这类功能,

这时候,你就需要学习使用redirect了。

准备好了?我们开始吧!

Redirection

Javascript其实也可以redirect页面。

我们会使用window.location来输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.



比如输入google页面连结,你就能成功redirect到google页面了。


Redirect功能,更可以配合setTimeout一起使用的,比如上图般输入3秒。

在等待3秒后,才会redirect到google页面。

第11章处理String

接著,我们将会学习更多String的其他功能。

我们在先前章节所学习的+,是一种基本的处理String方法,表示combine String。

除了+外,关于处理String的function有很多。

这时候,你就需要学习处理String的功能了。

准备好了?我们开始吧!

处理String

接著,我们将会学习更多String的其他功能。

我们在先前章节所学习的+,是一种基本的处理String方法,表示combine String。

除了+外,关于处理String的function有很多。

我们来学学其中两个,比较常用处理String的方法 :substring和indexof。

substring

第一个是substring,我们一起输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


substring()可以让你,把String的一部分抽出来。


比如说"something text".substring(1, 4),

会把第1个字元(s)以及第4个字元(t),中间的String抽出来,变成「ome」。

你可以看到,s是第0个,0是第一个,如此类推。

所以抽出第一个character和第二四个character前面的东西,

结果就会是ome。

这就是一个常用的substring,大家记得努力练习喔。

indexof

下一个常用的,就是indexof。

indexOf()则可以返回字元或字串的位置(以数字表示)。

我们一起输入:

See the Pen by Chan Ying Yeung (@chan-ying-yeung) on CodePen.


T是第一个字元(s),
h是第二个字元(s),
i是第三个字元(s),
如此类推,空格也会计算作一个字元(s)。


所以,要显示出text的位置,而text前面总共有13个字元(s)。

以上,就是indexof的使用方法了。

第12章Debug

来到最后一堂要学习的,就是Debug。

写Program时, 我们一定会遇到错误。要了解哪里出错, 就会使用Debug功能。

这功能是为了方便大家记录某些变数,了解其数值多少,从而更容易去Debug的。

最后一堂,大家准备好了吗?我们开始吧!

Debug

来到最后一堂要学习的,就是Debug。

在上面分享的各种例子,我们常常会使用alert()去查看变数的值。


比如是alert123,就会显示出123。

然而,alert并不是最好的方法去debug/查看变数的值。

因为有些data type,例如array和object,

并不可以在alert中好好显示出来。

因此, 我们会使用console log。


当你refresh页面时,发现空白一片,什么都没有。

但其他它是Log住了,记录了这个data。


我们只需要空白页按右键,按「检查」,


然后按console,你会发现多了「123」,

这一个就是console.log了。

将来大家用javascript输入多点程式码的时候,我们就会经常使用console.log,

检记录某些变数,了解数值是多少,从而更容易去Debug的。

以上,便是Debug的基本概念了。

总结

学习javascript并不容易!

以上的12个课程,只是javascript的基础编程概念。

你还需要好好去做练习,巩固每一章的概念,才能充份理解和运用javascript。

大家好好去学习,加油!

本文由作者【鬍子Jack】创作,原文刊登于【鬍子科技學院】,如未经授权不得转载。
回应