JS MDN Learn

系统学习 JavaScript 第一步——MDN 的 Learn 部分,相当于基础入门。

第一步

什么是 JavaScript?

从全局来看 JS,讨论 JS 是什么、你能用它做什么等问题,明确使用 JS 的目的。

抽象定义:JS 是一种编程语言,允许你在网页中实现复杂功能。

还有,如果可以通过 CSS 对文本进行改变就不应该通过 JS 实现。

一段更新文本的 JS 代码:

1
2
3
4
5
6
7
8
const para = document.querySelector('p');

para.addEventListener('click', updateName);

function updateName() {
  const name = prompt('Enter a new name');
  para.textContent = `Player 1: ${name}`;
}

有一些被称为 APIs(Application Programming Interfaces,应用编程接口)功能,大致分为两类——浏览器 APIs 和第三方 APIs。

JS 能在页面加载完毕后动态修改页面内容。每个浏览器标签都处在独立的执行环境互不干涉。JS 代码从上到下依次执行。

解释(interpreted)型代码与编译(compiled)型代码:对于解释型编程语言,代码从上到下依次执行,代码的执行结果是即刻返回的;对于编译型编程语言,在由电脑运行以前先被转换为另一种形式,例如 C 语言会被编译成机器码再被电脑执行。JS 是轻量级的解释型编程语言。现代 JS 解释器使用了一种名为即时编译(just-in-time compiling)的技术来改善性能,在实际运行 JS 代码时,代码会被转换为一种二进制格式,执行速度更快。虽然应用了该种技术,但 JS 仍被视为解释型编程语言,因为这里的编译过程是在运行时进行的而不是提前完成。

服务端(Server-side)代码与客户端(Client-side)代码:在本次 JS Learn 部分,讲述的全部是客户端 JS——运行在用户主机上的 JS 代码。服务端代码运行在服务器上,服务端编程语言有 PHP、Python。

动态代码与静态代码:动态包括客户端 JS 和服务端语言,它们能够在不同情况下更新网页显示不同内容,按需生成新内容。服务端代码在服务器生成新内容,而客户端 JS 在客户端的浏览器内生成。不会动态更新内容的网页被称为动态网页,我的博客就是这样的静态网页组成的,进而可称为静态博客。

第一次尝试 JavaScript

像程序员一样思考,通过程序解决现实生活中的问题。如何像程序员一样思考?

  • 知道程序的功能
  • 知道具备这些功能需要哪些代码层面的东西
  • 如何将代码组合在一起工作

这需要各种努力:熟悉编程语言语法、持续练习以及一点创造力。

这一节给一个“猜数字”的例子,输入1-100的任意数字,程序根据是否与给定数字相等,并返回相应结果。

出了什么问题?JavaScript 故障排除

错误种类:语法错误和逻辑错误。

存储你需要的信息——变量

变量是值的容器,值可能是数字、字符串、布尔值、数组、对象、等等。可通过 const、let、var 声明变量。变量的初始化,const 必须初始化。变量提升

JavaScript 中的基本数学——数字和操作符

十进制数的不同类型:整数、浮点数、双精度浮点数。不同的数字系统:二进制、八进制、十六进制。JavaScript 对应的数据类型——Number

一些 Number 方法:

  • toFixed() 保留几位小数
  • Number(string) 将字符串转化为数字

算术操作符:+、-、*、/、%、**(指数)。它们存在优先级,和数学中的一样,“先算乘除、后算加减”。自操作符: -- 、++。赋值操作符:=、 +=-=*=/= 。比较操作符: ===!== 、<、>、<=、>=。

在 JavaScript 中处理文本——字符串

JS 中的字符串——由单双引号围起的字符。用反斜杠转义引号。字符串拼接用 ``+ 。用 ``\n 能输出多行字符串。

通过 Number() 可以把字符串转换成数字;而相应的,通过 toString() 可以把数字转换成字符串。

可以在字符串中插入运算符。

有用的字符串方法

  • String length
  • String[0]
  • String.prototype.includes()
  • String.prototype.startsWith()
  • String.prototype.endsWith()
  • String.prototype.indexOf()
  • String.prototype.slice()
  • String.prototype.toLowerCase()
  • String.prototype.toUpperCase()
  • String.prototype.replace()
  • String.prototype.replaceAll()

数组

数组是一串字符串组成的一个分组。数组例子: ['abc', 'def', '123', '456']['abc', 'def', [ '123', '456' ]] 。第二个是一个多维数组。

  • Array.prototype.length
  • Array[0]
  • Array.prototype.indexOf()
  • Array.prototype.push()
  • Array.prototype.unshift()
  • Array.prototype.pop()
  • Array.prototype.shift()
  • Array.prototype.splice()
  • Array.prototype.map()
  • Array.prototype.filter()
  • String.prototype.split() 字符串转换成数组
  • Array.prototype.join() 数组转换成字符串
  • Array.prototype.toString() 数组转换成字符串

任务:蠢故事生成器

See the Pen Silly story generator by tianheg (@tianheg) on CodePen.

构建块

在代码中做决定——条件句

  • if…else
  • if…
  • if…else if…else

使用逻辑操作符: && , || , !

使用 switch 语句时,default 不是必须要加上去的。case 后只能跟一个值,可见以下对比:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
switch (expression) {
  case value1 || value2:
    ...
}

switch (expression) {
  case value1:
  case value2:
    ...
}

第一个 switch 用法错误(如果是表达式就可以用逻辑操作符连接,如下所示),第二个是正确的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
switch (true) {
  case score >= 0 && score < 20:
    response = "";
    break;
  case score >= 20 && score < 40:
    response = "";
    break;
  case score >= 40 && score < 60:
    response = "";
    break;
  case score >= 60 && score < 80:
    response = "";
    break;
  case score >= 80 && score < 100:
    response = "";
    break;
}

三元操作符。

在进行条件判断时,false, undefined, null, 0, NaN, 空字符串 会返回 false ,其他情况均返回真。

循环

在一个元素集合中循环迭代,这些元素集合有几类——Array、Set、Map。

循环句式:

  • for…of

更特殊的循环方法:map(), filter()。

标准 for 循环:

1
2
3
for (initializer; condition; final-expression) {
  // code to run
}

注意,与 for…of 的区别。

break、continue

while:

1
2
3
4
5
6
initializer
while (condition) {
  // code to run

  final-expression
}

如何选择循环句式:

  1. 迭代数组时,不需要特别指定次序,使用 for…of 最佳
  2. 其他情况,用 for while do…while 彼此大概率可互换

person === "Phil" || person === "Lola"person === ("Phil" || "Lola") 在 if 句式中并不相同,为何?

phonebook[i].name.toLowerCase() 可以, phonebook[i][name].toLowerCase() 报错,为何?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
while (i > 1) {
  if (isPrime(i) === true) {
    para.textContent += `${i} `
  } else {
    i--
    continue
  }

  i--
}

// Refer:
// https://discourse.mozilla.org/t/assessment-request-for-loops-3-skill-test-confused-on-using-continue-statement-with-loops/67100

上面代码,如果没有第一个 i-- 就会陷入无限循环。

函数——可复用的代码块

JS 有很多内建函数,比如 string.replace(), array.join(), Math.random() 等等。

如果函数是属于对象的就被称为方法。函数表达式、函数参数、指定默认函数参数、匿名函数与箭头函数、函数作用域。

可为函数指定默认参数。

1
2
3
4
5
6
function hello(name = "Jim") {
  console.log(`Hello ${name}!`);
}

hello();
hello("tianheg");

匿名函数,函数表达式:

1
2
3
4
5
6
7
(function () {
 alert('hello');
})

const helloAlert = function () {
  alert('hello');
}

与函数声明不同,函数表达式不提升。

函数作用域:

全局作用域

Test your skills: Functions 3 的解决办法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const names = [
  "Chris",
  "Li Kang",
  "Anne",
  "Francesca",
  "Mustafa",
  "Tina",
  "Bert",
  "Jada"
];
const para = document.createElement("p");
const section = document.querySelector("section");

// Add your code here
// Refer https://codepen.io/MacNulty/project/editor/XxYjLw
function random(lowerBound, upperBound) {
  return Math.floor(Math.random() * (upperBound - lowerBound)) + lowerBound;
}

function chooseName() {
  return names[random(0, 7)];
}
para.textContent = chooseName();

// Don't edit the code below here!

section.appendChild(para);

构建自己的函数

btn.addEventListener("click", funcName)btn.addEventListener("click", funcName()) 有区别,前者只有 click 事件发生时才执行,后者只要页面 reload 就立即执行不等待 click 事件发生,在此种上下文中 funcName() 中的括号还被称为“函数调用运算符(function invocation operator)”。 btn.addEventListener("click", () => funcName("sth")) 此种匿名函数形式,则不会如上述第二种立即执行,该种不在立即执行的作用域中。

函数返回值

有些函数无返回值。通过函数返回计算值。使用 return 返回值。

Layout of comment panels