JavaScript初探索

JavaScript 是一种可插入 HTML 页面的轻量级的编程语言。

初识JavaScript

JavaScript的功能

  1. 直接写入 HTML 输出流
  2. 对事件的反应
  3. 改变 HTML 内容
  4. 改变 HTML 图像
  5. 改变 HTML 样式
  6. 验证输入

JavaScript 用法

内部的 JavaScript

HTML 中的 Javascript 脚本代码必须位于 <script></script>标签之间,加上标签后的代码代码可被放置在 HTML 页面的 <body><head> 部分中。

外部的 JavaScript

外部 JavaScript 文件的文件扩展名是 .js。使用以下代码,可将代码引入外部的 JavaScript

1
<script src="the_url_of_your_.js"></script>

​ 由于混合 JavaScript 和 HTML 会使代码难以维护和理解,所以与CSS一样,将js代码文件与html文件分离

JavaScript 运行次序

当浏览器执行到一段 JavaScript 代码时,通常会按从上往下的顺序执行这段代码。如果 JavaScript 先于要修改的 HTML 和 CSS 加载和运行,则可能发生错误。在引用对象之前必须确保该对象已经存在,对象还不存在,就不能为它增添一个事件监听器。

脚本调用设置

异步加载:指在 HTML 文档解析过程中,同时下载其他资源的过程。

默认情况

浏览器会立即下载并执行脚本。这意味着脚本会阻塞 HTML 文档的解析和渲染过程,直到脚本执行完毕。如果脚本文件很大或加载时间较长,这可能会导致页面加载速度变慢。

异步下载立即执行(限外部JS)

带有 async 属性的脚本,浏览器会异步下载脚本文件,并且不会阻塞 HTML 文档的解析和渲染。一旦脚本文件下载完成,浏览器会立即执行它,而不会等待其他资源的加载完成。

async 属性的脚本将在下载完成后立即执行。这将阻塞页面,并不保证任何特定的执行顺序。

异步下载等待页面渲染后顺序执行

内部的 JavaScript

可以使用以下结构:

1
2
3
document.addEventListener("DOMContentLoaded", () => {
// 在这里编写你的 JavaScript 代码
});

外部的 JavaScript

可以使用了defer标签:

1
<script src="the_url_of_your_.js" defer></script>

带有 defer 属性的脚本将按照它们的顺序加载,并且只有在所有脚本加载完毕后才会执行。

总结:

  • 如果脚本无需依赖html解析渲染出的对象,且无依赖其他资源独立运行,那么应使用 async
  • 如果脚本需要依赖html解析渲染出的对象,或依赖于其他脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 的相应 <script> 元素中。

一些我奇怪的想法

  • 如果脚本需要依赖html解析渲染出的对象,但不依赖于其他脚本,使用defer属性
  • 如果脚本无需要依赖html解析渲染出的对象,且依赖于其他脚本,使用defer属性或者将两个js写在一块,用async属性

总之一般情况下都用defer,比较万金油,默认模式一般都不推荐使用

基础概念

函数(Function)

函数是可复用的代码块,可以一次编写,反复运行,从而节省了大量的重复代码。

函数的格式包括了关键字 function 、一个函数名、一对小括号定义了一个函数。随后是一对花括号({ })。花括号内部是调用函数时要运行的所有代码。

1
2
3
function the_name_of_function() {
your code;
}

事件(Event)

理想中,我们希望在点击某个按钮时调用某个函数,为此,我们需要使用事件。事件就是浏览器中发生的事儿,比如点击按钮、加载页面、播放视频,等等,我们可以通过调用代码来响应事件。侦听事件发生的结构称为事件监听器(Event Listener),响应事件触发而运行的代码块被称为事件处理器(Event Handler)。

对象(Object)

在JavaScript中,一切都是对象。对象是一种复合数据类型(类似C语言的结构体),它可以包含属性和方法,由逗号分隔开。例如:

1
2
3
4
5
6
7
8
9
10
// 定义一个对象
const person = {
// 属性
name: "John",
age: 30,
// 方法
greet: function() {
console.log("Hello, my name is " + this.name);
}
};

点符号(.)来访问对象的属性和其他方法,例如:

1
person.greet(); // 调用对象的方法

属性是对象的特征或数据是任何JavaScript数据类型,包括字符串、数字、布尔值、数组、甚至其他对象。

方法(method)

与对象关联的函数。方法是在对象上定义的,它可以访问对象的属性和其他方法,并执行特定的操作。是对象能够执行的操作或行为。可通过浏览器的JavaScript 控制台操作浏览器对象

函数与方法的差别

  1. 归属关系:方法是与对象关联的函数。它们通常是在对象的上下文中定义的,并且可以访问对象的属性和其他方法。方法是对象的行为或操作。函数是独立的代码块,不依赖于特定的对象。它们可以在任何地方定义和调用,而不需要依赖于对象。

  2. 调用方式:方法通过对象来调用。它们使用对象名和方法名的结合形式进行调用,例如 objectName.methodName()。方法的调用是基于对象的,因此方法可以使用对象的属性和其他方法。函数可以直接通过函数名进行调用,例如 functionName()。函数的调用是独立的,不依赖于特定的对象。

  3. 参数传递:方法通常将对象本身作为第一个参数传递给方法(通常称为 thisself,以便在方法内部访问对象的属性和其他方法。方法可以接受其他参数作为输入。函数可以接受任意数量的参数,并且可以通过参数来接收外部值。

    例:

    1
    2
    3
    4
    5
    6
    7
    8
    const person = {
    name: "Wells",
    greet: function() {
    console.log("Hello, my name is " + this.name); //使用this作为对象本身
    },
    };

    person.greet(); // 输出 "Hello, my name is Wells"
  4. 定义方式:方法是在对象或类的定义中声明的。它们可以使用对象字面量语法或类的方法定义语法进行定义。函数可以在全局范围内或其他函数内部进行定义。它们可以使用函数声明语法或函数表达式语法进行定义。

运算符(Operator)

JavaScript 运算符允许我们执行比较、做数学运算、连接字符串等等。

算术运算符

运算符 描述
+ 加法
- 减法
* 乘法
**
/ 除法
% 取模(余数)
++ 自增
自减
  • 自增和自减运算符放置在变量前和变量后与区别(与C语言类似)

    1. 前置自增/自减运算符会先对变量进行自增或自减操作,然后返回更新后的值。
    2. 后置自增/自减运算符会先返回变量的原始值,然后再对变量进行自增或自减操作。
  • 运算符用于把文本值或字符串变量加起来(连接起来)。

    例如:

    1
    2
    3
    txt1="What a very";
    txt2="nice day";
    txt3=txt1+txt2;

    txt3What a verynice day

  • 如果数字与字符串相加,此时数字会被认为是字符串,返回字符串

    例如

    1
    z="Hello"+666;

    zHello666

赋值运算符

赋值运算符用于给 JavaScript 变量赋值。

运算符 例子 等同于
= x=y (将y赋值给x)
+= x+=y x=x+y
-= x-=y x=x-y
*= x*=y x=x*y
/= x/=y x=x/y
%= x%=y x=x%y

比较运算符

比较运算符在逻辑语句中使用,以测定变量或值是否相等。

以x=5为例:

运算符 描述 比较 返回值
== 等于(类型不等时会进行转化) x==8 false
x==5 true
x==”5” true
=== 严格等于(值和类型均相等) x===”5” false
x===5 true
!= 不等于 x!=8 true
x!=”5” false
!== 严格不等于(值和类型有一个不相等,或两个都不相等) x!==”5” true
x!==5 false
> 大于 x>8 false
< 小于 x<8 true
>= 大于或等于 x>=8 false
<= 小于或等于 x<=8 true

严格的版本往往导致更少的错误,建议使用这些严格的版本。

逻辑运算符

逻辑运算符用于测定变量或值之间的逻辑。

运算符 描述
&& and(同时成立为真)
|| or(一个成立为真)
! not

条件(三元)运算符

条件元素运算符把两个结果中其中一个符合运算逻辑的值返回。

1
2
? :
(condition ? ifTrue : ifFalse)

更多条件运算符参照:

表达式和运算符 - JavaScript | MDN (mozilla.org)

JavaScript基础

JavaScript的语句都是;作为结束,缺少;会导致报错

注释语法

单行注释

  • 在双斜杠(//)后添加单行注释,比如:

    1
    // 我是一条注释

多行注释

  • /**/之间添加多行注释,比如:

    1
    2
    3
    4
    /*
    我也是
    一条注释
    */

声明变量

声明一个变量,即创建一个变量。

声明一个变量的语法是在 varlet 关键字之后加上这个变量的名字,例如:

1
2
var Name2;
let Name1;

var 与 let 的区别

推荐在现代JavaScript中使用 let 来声明变量

  1. 作用域:使用 var 声明的变量具有函数作用域,而使用 let 声明的变量具有块级作用域。函数作用域意味着变量在声明它们的函数内部是可见的,而块级作用域意味着变量在声明它们的代码块(例如,{}包括起来的代码块:if语句、循环等)内部是可见的。

  2. 变量提升:使用 var 声明的变量会发生变量提升,意味着变量在其作用域内的任何位置都是可访问的,即使在变量声明之前也可以访问到。而使用 let 声明的变量不会发生变量提升,它们只能在声明之后才能被访问。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    myName = "Chris";

    function logName() {
    console.log(myName);
    }

    logName();//输出undefined

    var myName;

    感谢@Eneed_gl的指错,变量提升(指的是函数声明和变量声明(注意是声明,不包括初始化)会被提升到其所在作用域的最顶部)的时候是不会编译先前初始化的赋值语句的,故此时输出undefined

    1
    2
    3
    console.log(name); // 输出 undefined
    var name = "John";
    console.log(name); // 输出 "John"

    ​ 以上代码它仍然可以工作,若替换成let则就会报错

  3. 重复声明:使用 var 声明的变量可以被多次声明而不会引发错误,而使用 let 声明的变量在同一作用域内重复声明会引发错误

  4. 全局对象属性:使用 var 声明的变量会成为全局对象(在浏览器中是 window 对象)的属性,而使用 let 声明的变量不会成为全局对象的属性。

变量命名的规则

使用拉丁字符 (0-9,a-z,A-Z) 和下划线字符。

  • 你不应当使用规则之外的其他字符,因为它们可能引发错误,或对国际用户来说难以理解。
  • 变量名不要以下划线开头——以下划线开头的被某些 JavaScript 设计为特殊的含义,因此可能让人迷惑。
  • 变量名不要以数字开头。这种行为是不被允许的,将会报错。
  • 变量名大小写敏感——因此myagemyAge是 2 个不同的变量。
  • 避免使用 JavaScript 的保留字给变量命名。保留字,即是组成 JavaScript 的实际语法的单词

变量类型

JavaScript 是一种“动态类型语言”,你不需要指定变量将包含什么数据类型

数字

​ 包括整数也包括浮点数,统称为数字,例如:

1
let myAge = 17;

字符串

​ 当你给一个变量赋值为字符串时,你需要用单引号或者双引号把值给包起来,例如:

1
let prise = "You are smart";

布尔值

​ 布尔值有 2 种:true 或 false,用于进行判断

1
let iAmAlive = true;

数组

​ 数组将任何类型的元素存储在数组中 - 字符串,数字,对象,另一个变量,甚至另一个数组。也可以混合不同类型元素,方括号括起来(区别于C语言),并用逗号分隔,最开始的序号为0,例如:

1
2
3
4
let myNameArray = ["Chris", "Bob", "Jim"];
let myNumberArray = [10, 15, 40];
let sequence = [1, 1, 2, 3, 5, 8, 13];
let random = ["tree", 795, [0, 1, 2]];

其中

1
2
myNameArray[0]; // 将得到:Chris
myNumberArray[2]; // 将得到:40

对象

​ 见前文:基础概念·对象(Object),例如:

1
let dog = { name: "Spot", breed: "Dalmatian" };

与C语言调用结构体的成员类似,使用.用来表示对象中的某个信息,例如:

1
dog.name;

Undefined 和 Null

Undefined 这个值表示变量不含有值。

可以通过将变量的值设置为 null 来清空变量。

常量

概念:使用 const 声明的变量称为“常量”

当某个变量永远不会改变的时候,就可以使用 const 来声明,而不是let

注意:

  • 常量的命名规范和变量一致

  • 常量不允许重新赋值,声明的时候必须赋值(初始化)

  • 小技巧:可以利用const进行自定义函数,语法如下

    1
    2
    3
    const functionName = function(parameters) {
    // 函数体
    };

字符串

包裹字符串

在 JavaScript 中,可以选择单引号(')、双引号(")或反引号(```)来包裹字符串。字符串的开头和结尾必须使用相同的符号进行包裹

使用单引号声明的字符串和使用双引号声明的字符串是相同的

使用反引号声明的字符串是一种特殊字符串,被称为模板字面量。在大多数情况下,模板字面量与普通字符串类似,但它具有一些特殊的属性:

1.字符串插值(String interpolation):您可以在模板字符串中使用 ${} 语法来插入变量或表达式的值。例如:

1
2
3
4
const name = "Wells";

const message = `My name is ${name}.`;
console.log(message); // 输出 "My name is Wells."

但对于单引号(')、双引号(")可使用可以使用 + 运算符来连接字符串。

1
2
3
const greeting = "你好";
const name = "Wells";
console.log(greeting + "," + name); // "你好,Wells"

2.多行字符串:模板字面量可以跨越多行,而无需使用特殊的转义字符或字符串连接操作符。例如:

1
2
3
4
const multiLine = `This is a
multi-line
string.`;
console.log(multiLine);

输出:
This is a
multi-line
string.

在上面的例子中,模板字面量可以直接包含换行符,而不需要使用 \n 转义字符。

3.嵌套模板字面量:您可以在模板字面量中嵌套其他模板字面量,以构建更复杂的字符串。例如:

1
2
const nestedTemplate = `Hello, ${`My name is ${name}`}.`;
console.log(nestedTemplate); // 输出 "Hello, My name is John."

在上面的例子中,${name} 是嵌套在外部模板字面量中的。

字符串包含引号

要实现字符串:

1
She said "I think so!"

此时不能再使用"",一种常见的方法是换用其他字符来声明字符串:

1
2
const goodQuotes1 = 'She said "I think so!"';
const goodQuotes2 = `She said "I think so!"`;

另一种选择是转义存在问题的引号。转义字符意味着我们对它们做了一些处理,以确保它们被识别为文本,而不是代码的一部分。在 JavaScript 中,我们通过在字符之前加上反斜杠(\)来实现这一点。

操作字符串

把字符串当作对象,就可以有大量的原型和方法编辑它。以下为常用的属性和操作

获得字符串的长度

这很简单 — 你可以很轻松的使用 length属性。尝试输入以下的两行代码:

1
2
let browserType = "mozilla";
browserType.length;

因为”mozilla”的长度为 7 个字符,这个结果应该返回一个数字:7。说字符串的长度有用是有很多原因的,例如,你可能想算出一连串名字的长度,并用名字长度来作为名字排序的依据,亦或让一个用户知道他输入的用户名太长,已经超出了输入的字符串长度限制。

检索特定字符串字符

可以使用方括号表示法(在变量名的末尾包含方括号[ ])返回字符串中的任何字符.例如,要检索第一个字母,可以这样做:(如同数组)

1
browserType[0];

在字符串中查找子字符串并提取它

有时候你会想要找出一个较小的字符串是否存在于一个较大的字符串中(我们通常会说一个字符串中存在一个子字符串)。这可以使用indexOf()方法来完成,该方法需要一个parameter (en-US)— 你想要搜索的子字符串。例如:

1
browserType.indexOf("zilla");

返回的结果是子字符串起始的位置(原字符串第一个字母为0),若无结果将返回-1

转换大小写

字符串方法toLowerCase()toUpperCase()字符串并将所有字符分别转换为小写或大写。

替换字符串的某部分

使用replace()方法将字符串中的一个子字符串替换为另一个子字符串。

它需要两个参数 - 要被替换下的字符串和要被替换上的字符串。

数组

获取数组长度

使用 length属性获取数组的长度(数组中有多少项元素)

1
2
let sequence = [1, 1, 2, 3, 5, 8, 13];
sequence.length;// 将返回7

字符串与数组转换

将数组看作成对象,可使用 split() 方法将一个长长的字符串中的原始数据,分成更有用的数据,存储在数组中,例如:

1
2
3
let myData = "Manchester,London,Liverpool,Birmingham,Leeds,Carlisle";
let myArray = myData.split(",");//以,号来隔开
myArray;//输出['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle']

也可以使用 join()方法进行相反的操作,例如:

1
2
let myNewString = myArray.join(",");//以,进行连接
myNewString;//输出 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle'

添加和删除数组项

可以使用 push() 方法,在数组末尾添加项目,例如:

1
2
myArray.push("Cardiff");//增加一个
myArray.push("Bradford", "Brighton");//增加两个

​ 当方法调用完成时,将返回值为数组的新长度

1
var newLength = myArray.push("Bristol");//newLength为一个值

可以使用 pop()方法,在数组末尾删除一个项目,例如:

1
myArray.pop();

​ 当方法调用完成时,将返回值已删除的项目

1
let removedItem = myArray.pop();//removedItem为被删除的元素

除此之外,还有unshift()shift() 的方法分别作用于数组的开始进行添加或者删除元素,返回值与 push()pop()方法相同

条件语句

if…else 语法

基本的 if...else 语法看起来这样:

1
2
3
4
5
if (condition) {
/* 条件为真时运行的代码 */
} else {
/* 否则,运行其他的代码 */
}

添加{}时,内可以添加多个语句,没有{}时,只会运行if下的第一个语句,例如:

1
2
3
if (condition) 
/* 代码1; */
/* 代码2; */

只有条件为真时,代码1才会运行,不论条件是否为真,代码2都会运行。

更多选择:else if

使用 else if可以使判断更多的条件和选项,例如

1
2
3
4
5
6
7
8
9
if (condition1) {
/* 条件1为真时运行的代码 */
} else if (condition2) {
/* 条件2为真时运行的代码 */
} else if (condition3) {
/* 条件3为真时运行的代码 */
} else {
/* 否则,运行其他的代码 */
}

switch 语句

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
switch (表达式/值) {
case 选择1:
运行这段代码
break;

case 选择2:
否则,运行这段代码
break;

// .......其他情况

default:
出现未定义时的情况下,运行这段代码
}

注意

  1. switch后的括号内可以是表达式或值
  2. default 之后不需要再有选项,并且不需要 break 语句,因为之后没有任何运行代码。如果之前没有选项匹配,则运行 default 选项。

循环

for循环

语法

1
2
3
for (初始化操作; 开始/继续循环条件; 每次循环结束后的操作) {
// 每次循环运行的代码
}

在关键字for括号内,我们有三个项目,以分号分隔:

  1. 一个初始化器 - 这通常是一个设置为一个数字的变量,它被递增来计算循环运行的次数。它也有时被称为计数变量

  2. 一个开始/继续循环条件 - 如前面提到的,这个定义循环何时停止循环。这通常是一个表现为比较运算符的表达式,用于查看退出条件是否已满足的测试。

  3. 一个循环结束后的操作 - 这总是被判断(或运行),每个循环已经通过一个完整的迭代消失时间。它通常用于增加(或在某些情况下递减)计数器变量,使其更接近退出条件值。

while 语句

语法

1
2
3
while (开始/继续循环条件) {
// 每次循环运行的代码
}

do ... while 语句

语法

1
2
3
do {
// 每次循环运行的代码
} while (继续循环条件)

while 循环不同的是do...while 循环会先进行一次循环然后再判断条件满不满足循环的条件决定是否继续循环

跳出循环

break 语句

使用break 语句将立即退出本层循环

continue 语句

continue 语句与break类似,但不是完全跳出循环,而是跳过本次循环continue 语句后的余下代码,条件成立的话执行下一个循环

for循环语句中,使用continue语句,跳过本次循环continue 语句后的余下代码,仍然会进行每次循环结束后的操作的代码

函数

函数声明自定义函数

语法

1
2
3
function functionName(parameters) {
// 函数体
}

注意:形参在()无需再使用let或者var声明,直接输入参数名即可

调用函数

语法

1
functionName(parameters)

匿名函数

创建一个没有名称的函数,例如:

1
2
3
function() {
alert('hello');
}

这个函数叫做匿名函数——它没有函数名!它也不会自己做任何事情。通常将匿名函数与事件处理程序或者将匿名函数分配为变量的值一起使用。例如:

1
2
3
4
5
var myButton = document.querySelector("button");

myButton.onclick = function () { //将匿名函数与事件处理程序一起使用
alert("hello");
};
1
2
3
var myGreeting = function () {  //将匿名函数分配为变量的值
alert("hello");
};

函数作用域

函数内定义的变量和其他东西作用域仅在函数内,不能被函数外的代码访问。

假设一个 HTML 文件,它调用两个外部 JavaScript 文件,并且它们都有一个使用相同名称定义的变量和函数,若调用这个函数,只能访问到首先被引用文件的这个函数(第二个文件被忽视了),例如

1
2
3
4
5
6
<!-- Excerpt from my HTML -->
<script src="first.js"></script>
<script src="second.js"></script>
<script>
greeting();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
// first.js
let name = "Chris";
function greeting() {
alert("Hello " + name + ": welcome to our company.");
}
//偷懒写在一起了

// second.js
let name = "Zaptec";
function greeting() {
alert("Our company is called " + name + ".");
}

这两个函数都使用 greeting() 形式调用,但是你只能访问到 first.js 文件的greeting()函数(第二个文件被忽视了)。另外,第二次尝试使用 let 关键字定义 name 变量导致了一个错误。

返回值

函数的返回值可以是任意类型的数据,例如数组、对象等数据类型

一些函数和方法

函数

1.Number()函数

​ 将其参数转换为数字

2.String()函数

​ 将其参数转换为字符串

3.Math.random()

Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值

方法

3.Window:alert() 方法

window.alert() 令浏览器显示一个带有可选的信息的对话框,并等待用户离开该对话框。

在某些情况下(例如,当用户切换标签时)浏览器可能不会实际显示一个对话框,或者不等待用户离开对话框。

语法

1
2
alert()
alert(message)

参数

  • message可选

    是要显示在警告对话框中的字符串,如果传入其他类型的值,会转换成字符串。

返回值:无

完整内置对象以及其相关方法列表

JavaScript 标准内置对象 - JavaScript | MDN (mozilla.org)