# JavaScript
# 介绍
- JavaScript 是一种轻量级的脚本语言
- JavaScript 可以插入 HTML 页面(网页),浏览器会执行它
- JavaScript(简称“JS”)是一种具有函数优先的轻量级解释型语言,在程序的运行过程中逐行进行解释,主要用于Web开发,但也可以用在其他环境中
- JavaScript是弱类型语言,使用时,对数据类型没有严格的要求
# 导入页面
要在 Web 页面中使用 JavaScript 时需要将 js 代码导入 HTML 中,以下是导入 js 的方法:
# 使用 <script>
标签
我们可以使用<script>
标签在html文件中插入JavaScript代码,在浏览器中执行
你可以把<script>
标签放在<body>
标签或<head>
标签中
<script>
alert("hello,world");
</script>
# 使用外部js文件
你也可以通过这种方式把外部的js文件导入网页中
<script src="myScript.js"></script>
这样在网页中就可以使用这个文件里的代码,相对于把代码直接嵌入网页,引入外部js文件的方式更安全
# 变量
在 JavaScript 中变量是这样使用的
// 设置一个变量a
var a
// 设置一个变量a并初始化为0
var a = 0
// 设置一个变量a并赋值为0
var a
a = 0
a
是变量名 var
是变量声明,除了 var
还有 let
和const
声明 | 作用域 | 是否可重新赋值 | 示例说明 |
---|---|---|---|
var | 函数作用域 | ✅ | 在函数内声明,整个函数可用;无块级作用域 |
let | 块级作用域 | ✅ | 仅在 {} 代码块内有效(如 if 、for ) |
const | 块级作用域 | ❌ | 同 let ,但需初始化且不能重新赋值 |
在使用 const
声明时,变量一定要初始化
var myName; // 正确,不需要初始化
const myName; //错误,必须初始化
命名规则
- 变量名区分大小写 (myVar ≠ myvar)
- 避免使用保留字 如
class
,function
等 - 变量名开头不能用数字,只能是字母或
_
和$
var name //正确
var _name //正确
var $name //正确
var 1name //错误
# 数据类型
一般常见的数据类型有 number
、string
、boolean
、undefined
number
是数字类型,包括整数和浮点数 例如
var age = 25
string
是字符串类型,当值为字符串类型时需要加上 ""
(双引号)或者 ''
(单引号),不论用哪个引号作用都是一样的
var name = "yoseya"
如果字符串中包含单引号或双引号时我们就可以换另一个引号括住值,保证不出错
var name = '"yoseya"'
console.log(name) // 输出结果:"yoseya"
boolean
类型只有两个值 true
(真) 或 false
(假)
let isActive = true;
undefined
类型是一个特殊的类型,当变量的值不确定时该值为 undefined
,当访问的值不存在是就会出现 undefined
var a
console.log(a) // 输出结果为 undefined
null
表示空值,当需要变量为空时就可以赋值为 null
var data = null;
# 回收机制
JavaScript 中有一套叫做 Garbage Collection 的垃圾回收机制,用于释放那些不再使用的内存空间
例如以下这段代码
var a = 16
a = 100
我们设置了一个变量 a
并赋值为 16
,这时内存空间存放了变量 a
和值 16
,并将 a
指向值 16
的地址,然后我们又将变量 a
赋值为100
,这时内存中又保存了一个值 100
,并将变量 a
指向的地址改为值 100
的地址,但之前的值 16 现在已经多余了,这时 js 中的回收机制就会将存放这个值的内存空间标记为没有被指向的内存空间,在之后一并清理
# 字符串的连接
字符串连接是将多个字符串合并为一个字符
使用运算符 +
将两段字符串类型的变量进行连接
let str1 = "Hello";
let str2 = "World";
let result = str1 + " " + str2; // "Hello World"
使用运算符 +
将两段字符串进行连接
var str1 = "Hello" + "World"
console.log(str1); //输出结果:HelloWorld
使用运算符 +
将变量与字符串进行连接
var str1 = "Hello"
console.log(str1 + "World"); //输出结果:HelloWorld
使用模板字符串的方式连接字符串
let str1 = "Hello";
let str2 = "World";
let result = `${str1} ${str2}`; // 使用反引号进行字符串插值
console.log(result); // 输出结果: Hello World
将数组中的字符串进行拼接
let words = ["I", "love", "JavaScript"];
let sentence = words.join(" "); // "I love JavaScript"
使用 String.concat() 进行字符串连接
let str1 = "Hello".concat(" Wor", "ld");
console.log(str1); // "Hello World"
# 对象
对象是一种复合数据类型,用于存储键值对的集合。
- 将现实生活中的实体时抽象成对象,在计算机中进行研究
- 使用对象进行结构化数据存储
# 创建对象
这就是一个对象,里面的值就是对象所具有的属性,他们以键值对的形式展示
var obj = {
name: "小明",
age: 18,
height: "180cm",
hobby: ["足球", "篮球"]
}
也可以先创建对象然后再插入值
var obj = {}
obj.name = "小明"
obj.age = 18
obj.height = "180cm"
obj.hobby = ["足球", "篮球"]
console.log(obj);
输出结果
{
"name": "小明",
"age": 18,
"height": "180cm",
"hobby": [
"足球",
"篮球"
]
}
# 使用对象
以该对象为例
var obj = {
name: "小明",
age: 18,
height: "180m",
hobby: ["足球", "篮球"]
}
可以通过这样的方式读取对象中的值,使用对象时可以用 x.y
的形式也可以使用 x[y]
的形式
var a = obj.name // 方法1
var b = obj["age"] // 方法2
console.log(a,b) // 输出结果:小明 18
添加新的属性和修改原有属性的值
obj.sex = "男" // 添加新的属性
obj["age"] = 19 // 修改原有属性的值
console.log(obj)
输出结果
{
"name": "小明",
"age": 19,
"height": "180m",
"hobby": [
"足球",
"篮球"
],
"sex": "男"
}
# 嵌套对象
在一个对象中,它的属性也是对象,就可以称作嵌套对象
var obj = {
name: "小明",
age: 18,
height: "180cm",
hobby: ["足球", "篮球"],
address: {
province: "浙江",
city: "杭州",
district: "西湖区"
}
}
高亮部分就是嵌套的对象,当我们要读取对象里嵌套的对象时可以使用 a.b.c
的形式
var a = obj.address.city // 读取嵌套属性
obj.address.district = "拱墅区" // 修改嵌套属性
obj.address.street = "文三路" // 添加新的嵌套属性
console.log(a,obj)
也可以这样使用,但一般建议使用 a.b.c
这样链式访问的方式,方便表示层级结构
var a = obj.address["city"]
obj.address["district"] = "拱墅区"
obj.address["street"] = "文三路"
输出结果
杭州
{
"name": "小明",
"age": 18,
"height": "180cm",
"hobby": [
"足球",
"篮球"
],
"address": {
"province": "浙江",
"city": "杭州",
"district": "拱墅区",
"street": "文三路"
}
}
注意
对象中的同级属性不能重名,如果对象中还有嵌套的对象,父对象的属性与子对象中的属性可以出现重名
# 删除对象中的属性
删除对象中的属性可以用关键字 delete
var obj = {
name: "小明",
age: 18,
height: "180m",
hobby: ["足球", "篮球"]
}
delete obj.name // 删除对象 obj 中的 name 属性
console.log(obj)
输出结果
输出结果中没有了 obj.name
{
"age": 18,
"height": "180m",
"hobby": [
"足球",
"篮球"
]
}
# 属性名命名规则
- 字母、数字、下划线
_
、$
可以用于属性名命名,但数字不能作为标识符的首字符 - 属性名可以是任何字符串,若属性名包含空格或其他特殊字符则需要用
"
括起来 - 如果属性名是数字,它会被自动转换为字符串
示例
const obj = {
name: "张三",
_age: 25,
$salary: 50000,
// 包含特殊字符的属性名要用引号括起来
"full-name": "张三丰",
"user email": "zhangsan@maill.com",
// 数字属性名会被转换为字符串类型
123: "value"
};
若属性名为字符串时访问该属性则需要使用括号表示法
var obj = {
name: "小明",
"your-age": 18
};
console.log(obj["your-age"]);
# 对象与内存
实验一
var obj = {
name: "小明",
age: 18
};
var obj2 = obj;
console.log(obj.name, obj2.name);
obj.name = "小红"
console.log(obj.name, obj2.name);
输出结果
小明 小明
小红 小红
我们先设置了一个对象 obj
又设置了一个变量 obj2
,然后将 obj
赋值给 obj2
,同时输出 obj.name
和 obj2.name
,两者都输出了小明。
我们再将 obj.name
改成小红 再同时输出 obj.name
和 obj2.name
,两者都输出了小红。
我只修改了 obj.name
,为什么 obj2.name
也跟着变呢?
这时因为 obj
和 obj2
本身就指向同一个对象,我们把 obj
赋值给 obj2
的过程就是将变量 obj2
指向 obj
的内存地址。
实验二
var obj = {
name: "小明",
age: 18
};
var obj2 ={
name: obj.name,
age: obj.age
};
console.log(obj.name, obj2.name);
obj.name = "小红"
console.log(obj.name, obj2.name);
输出结果
小明 小明
小红 小明
与上一个实验相反,这次当我们修改 obj.name
后 obj2.name
并没有跟着一起变。
这时因为这次我们并没有把 obj
直接赋值给 obj2
而是将 obj
的属性值赋值给了 obj2
中对应的属性上,当我们改变 obj.name
时只是将 obj.name
指向了新的值,而 obj2.name
指向的依然是原本 obj.name
的值。
# 表达式与运算符
# 表达式
JavaScript 中的表达式是任何可以产生值的代码单元。表达式可以是简单的值,也可以是复杂的组合。
如果一段代码可以产生值则这段代码就是表达式,如果没有结果或者输出的结果为 undefined
则这段代码不是表达式。
# 算数运算符
运算符 | 说明 | 示例 |
---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取余 | a % b |
* * | 指数 | a ** b |
++ | 自增 | ++a 或 a++ |
-- | 自减 | --a 或 a-- |
++a
或 a++
的区别(自减同理)
++a
表示前缀递增,先将a
的值增加,然后返回增加后的值a++
表示后缀递增,先返回a
的当前值,然后将a
的值增加1
let a= 0;
console.log(a++); // 输出 0
let b = 0;
console.log(++b); // 输出 1
# 赋值运算符
运算符 | 说明 | 示例 |
---|---|---|
= | 赋值 | a = 1 |
+= | 加法赋值 | a += 1 |
-= | 减法赋值 | a -= 1 |
*= | 乘法赋值 | a *= 1 |
/= | 除法赋值 | a /= 1 |
%= | 取模赋值 | a %= 1 |
**= | 指数赋值 | a **= 1 |
# 比较运算符
运算符 | 说明 | 示例 |
---|---|---|
== | 相等(值相等,不比较类型) | a == b |
=== | 严格相等(值和类型都相等) | a === b |
!= | 不相等 (值不相等,不比较类型) | a != b |
!== | 严格不相等(值和类型都不相等) | a !== b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
# 逻辑运算符
运算符 | 说明 | 示例 |
---|---|---|
&& | 逻辑与 | A && BB |
|| | 逻辑或 | A || B |
! | 逻辑非 | !C |
# 位运算符号
运算符 | 说明 | 示例 |
---|---|---|
& | 按位与 | a & b |
| | 按位或 | a | b |
^ | 按位异或 | a ^ b |
~ | 按位非 | ~A |
<< | 左移 | a << 1 |
>> | 右移 | a >> 1 |
>>> | 无符号右移 | a >>> 1 |
# 三元运算表达式
语法
condition ? value1 : value2
condition
表示条件,如果满足条件则返回 value1
否则返回 value2
# 可选链操作符
可选链操作符 ?.
,用于安全地访问嵌套的对象属性,即使其中某个属性不存在也不会报错。
基本语法
obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)
当你不确定一个对象是否有某个属性或方法时,使用可选链操作符可以让你安全地访问它。
如果这个属性或方法存在,就正常返回值;如果不存在也不会报错,而是是返回 undefined
const user = {
name: "yoseya",
address: {
city: "beijing"
}
};
console.log(user.address?.city); // 对象存在,则输出 "beijing"
console.log(user.address?.postal); // 对象不存在 输出 undefined
# 访问数组元素
const users = [
{ name: "张三", hobbies: ["读书", "游泳"] },
{ name: "李四" }
];
console.log(users[0]?.hobbies?.[0]); // 输出 "读书"
注意
users[0]?.hobbies?.[0]
和 users[0]?.hobbies[0]
的区别
users[0]?.hobbies?.[0]
- 先检查
users[0]
是否存在 - 若存在,则继续检查
hobbies
属性是否存在 - 若存在,则再检查索引
[0]
是否存在 - 若存在,则访问
hobbies[0]
;若不存在则输出undefined
而不报错
- 先检查
users[0]?.hobbies[0]
- 先检查
users[0]
是否存在 - 若存在,则继续检查
hobbies
属性是否存在 - 若存在,则直接访问
hobbies[0]
;若不存在就会报错
- 先检查
由此可得,若 hobbies
属性存在,则两者效果相同;若 hobbies
属性不存在,则前者输出 undefined
而不报错,但后者会报错。
这是因为后者并不会对数组索引进行安全检查就直接访问了,如果 hobbies
属性不存在,它就会返回 undefined
,这时你访问索引 [0]
就相当于你访问了 undefined[0]
,所以会出现报错。
# 调用函数
const obj = {
method: function() {
return "Hello";
}
};
console.log(obj.method?.());
# 扩展运算符
扩展运算符 ...
,可以将对象中的内容作为独立的元素使用
语法
// 在数组中使用
[...iterable]
// 在对象中使用
{...obj}
// 函数调用时用作参数
func(...args)
示例
const arr1 = [1, 2, 3];
const merged = [...arr1, 4, 5, 6];
console.log(merged); // [1, 2, 3, 4, 5, 6]
# 运算符优先级
运算符优先级决定了表达式中运算执行的先后顺序,优先级高的运算符会先执行。
运算符 | 描述 | |
---|---|---|
1 | () [] . ?. | 分组、成员访问 |
2 | new | 带参数列表的构造函数调用 |
3 | new | 不带参数列表的构造函数调用 |
4 | ++ -- | 后置递增/递减 |
5 | ! ~ + - typeof void delete | 一元运算符 |
6 | ** | 指数运算符 |
7 | * / % | 乘法、除法、取模 |
8 | + - | 加法、减法 |
9 | << >> >>> | 位移运算符 |
10 | < <= > >= in instanceof | 比较运算符 |
11 | == != === !== | 等值运算符 |
12 | & | 按位与 |
13 | ^ | 按位异或 |
14 | | | 按位或 |
15 | && | 逻辑与 |
16 | || ?? | 逻辑或、空值合并 |
17 | ? : | 条件(三元)运算符 |
18 | = += -= *= /= %= **= <<= >>= >>>= &= ^= \|= | 赋值运算符 |
19 | yield yield* | yield表达式 |
20 | , | 逗号运算符 |