js基础
零、前言
js是一种高级、解释型的编程语言,通常用于为网页添加交互性和动态功能。是一种基于对象和事件驱动的脚本语言,可以嵌入到HTML中使用。js广泛用于前端开发,可以实现用户界面操作、表单验证、动态内容更新等功能。
0.1 作用:
js 的主要作用是在网页上实现交互功能。它可以用来创建动态的网页内容,例如表单验证、图像滑动、内容加载等。
此外,js 也可以用于创建网页游戏、移动应用和服务器端应用。它是一种非常灵活的语言,可以在各种环境中运行。
0.2 其他
ECMAScript 规定了基础的语法和核心知识,包括变量、分支语句、循环语句、对象等。而 Web APIs 则提供了一系列的功能,用于操作网页的 DOM(文档对象模型)和 BOM(浏览器对象模型)。这些功能包括对页面元素进行移动、大小、添加删除等操作,以及对浏览器进行操作,如页面弹窗,检测窗口宽度,存储数据到浏览器等。
0.3 书写位置
0.3.1 内部式
直接写在html文件里,用script标签包住 规范:script标签写在上面
alert(‘你好,js’)页面弹出警告对话框
<!DOCTYPE html>
<html>
<head>
<title>My Web Page</title>
</head>
<body>
<h1>Hello, World!</h1>
<script>
// 这里是你的 js 代码
alert('Hello, World!')
</script>
</body>
</html>
注意事项
将 js 代码放在 HTML 页面的底部附近可以确保 HTML 内容已经加载完毕,这样 js 代码就可以安全地操作这些内容。
如果先加载的 Js 期望修改其下方的 HTML,那么它可能由于 HTML 尚未被加载而失效。
因此,将Js代码放在HTML页面的底部附近通常是最好的策略。
0.3.2 外部式
可以将代码写在一个外部的 Js 文件中,然后在 HTML 文件中通过 <script>
标签引入这个外部文件。
<!DOCTYPE html>
<html>
<head>
<title>My Web Page</title>
</head>
<body>
<h1>Hello, World!</h1>
<script src="script.js"></script>
</body>
</html>
注意事项
1.script标签中间无需写代码,否则会被忽略
2.外部Js代码更加有序,更易于复用, 且没有了脚本的混合,HTML 也会更加易读,因此这是个好的习惯
0.3.3 内联式
内联式(Inline)指的是直接在 HTML 元素的属性中写入 Js 代码。这通常用于处理一些简单的交互,如点击按钮时弹出提示框。
<button onclick="alert('Hello, World!')">Click me</button>
0.3.4 书写位置的注意
在 HTML 中,通常建议将外部的 Js 文件的 <script>
标签放在文档的末尾,这样可以确保在加载和执行 Js 代码时,HTML 内容已经被完全加载。这有助于提高页面的加载性能。
一、基本语法
1.1 注释和结束符
- 单行注释:以
//
开头,直到行尾的所有内容都会被当作注释
// 单行注释
- 多行注释:以
/*
开头,以*/
结尾,之间的所有内容都会被当作注释。
/*
多行
注释
*/
结束符通常指的是分号 ;
。Js 代码的每一行都应该以分号结束。
Js 有自动插入分号的机制【约定:为了风格统一(团队要求),要么每句都写,要么都不写】
1.2 输入输出
通常通过浏览器的控制台进行。
- 输入:
prompt()
函数来获取用户的输入。这个函数会弹出一个对话框,用户可以在这个对话框中输入内容。
let name = prompt("Please enter your name:")
- 输出:
console.log()
函数来输出内容到控制台,用于程序员调试
console.log('控制台打印')
- 显示在页面上:
document.write()
如果输出的内容写的是标签,也会被解析成网页元素
document.write("Hello, World!")
document.write('要输出的内容')
- 页面弹出警告对话框
alert('要出的内容')
1.3 字面量和变量
-
字面量:表示数据的固定的不能被改变值。
"Hello, World!"
、42
、true
都是字面量。 -
变量:变量是用于存储数据的容器。值可以是任何类型的数据,可以被改变。
1.3.1 使用
- 声明变量:
var
、let
或const
关键字来声明变量。
构成:声明关键字、变量名(标识)
var name
let age
const PI = 3.14
name
、age
和 PI
都是变量,它们分别存储了字符串、数字和常量的值
// 1. 声明一个 age 变量
let age
// 2. age 变量赋值为 18
age = 18
// 3. 输出age变量
alert(age)
- 使用变量:一旦声明赋值,就可以使用
console.log(name) //"John"
console.log(age) //30
- 改变变量的值:赋值操作符
=
来改变变量的值
name = "Jane"
age = 25
1.3.2 变量的本质
程序在内存中申请的一块用来存放数据的小空间。该空间可存储各种类型的数据,如数字、字符串、对象等。
声明一个变量时,实际上是在告诉解释器需要在内存中为这个变量分配一块空间。这块空间的大小和类型取决于赋给变量的值。
当变量的值改变时,内存随之更新。
1.3.3 命名规范
使用有意义的名称、驼峰命名法、使用 const 和 let、 避免保留字、不要数字开头、 区分大小写、对于常量全大写
- 避免使用关键字和保留字:确实,像
let
、var
、if
、for
等都是 Js 的关键字,它们有特殊的含义,不能用作变量名或函数名。 - 保留字,虽然目前可能没有特殊用途,但在将来的语言标准中可能会被用作关键字,因此也应避免使用。
- 命名字符限制:变量名只能包含字母、数字、下划线
_
和美元符号$
,并且不能以数字开头。这是因为数字开头的命名可能会被解释器误认为是数值。 - 区分大小写:Js 是区分大小写的语言,因此
Age
和age
会被视为两个不同的变量。 - 有意义的命名:变量和函数的名称应该能够清楚地表达它们的用途或所存储的数据的类型,这样可以提高代码的可读性和可维护性。
- 小驼峰命名法:对于变量和函数名,推荐小驼峰命名法(userName),即第一个单词以小写字母开始,后续每个单词的首字母大写,如
userName
。
1.3.4 let 和 var 区别
-
作用域:
var
声明的变量拥有函数作用域或全局作用域。当在函数外部使用var
声明变量,那么这个变量是全局可见的。当在函数内部使用var
声明变量,那么这个变量只在函数内部可见。let
声明的变量拥有块级作用域(block scope),即变量仅在包含它的代码块(if 语句、for 循环)内部可见。
-
提升(Hoisting):
var
声明的变量会被提升到其作用域的顶部,但是在声明之前访问这个变量只会得到undefined
,而不是引发错误。let
声明的变量也存在提升,但是它们被绑定在一个“暂时性死区”(Temporal Dead Zone, TDZ)直到声明语句被执行。当在声明之前访问let
变量,Js 会抛出一个引用错误。
-
重复声明:
- 在同一作用域内,使用
var
可以重复声明同一个变量,后面的声明会覆盖前面的声明。 let
声明变量时,在相同作用域内重复声明同一个变量,Js 会抛出一个语法错误。
- 在同一作用域内,使用
-
全局对象属性:
var
声明的变量会成为全局对象(在浏览器中是window
对象)的属性。let
在全局作用域中声明的变量不会成为全局对象的属性。
由于 let
提供了更加精确的作用域控制和避免了一些潜在的问题(如变量提升导致的错误),推荐优先使用 let
(和 const
)来声明变量。
1.4 数组
用于存储多个值的单一变量。
数组中的每个值(元素)可以是任意数据类型,包括数字、字符串、对象甚至其他数组。使用方括号 []
定义的,元素之间用逗号 ,
分隔。
字面量声明(推荐)
`let 数组名=[数据1,数据2,数据3,数据n]`
new一个
`let 数组名=new Array(数据1,数据2,数据3,数据n)`
Test
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(arr.filter(x => x % 2 === 0))
for (let lengthKey in arr){
console.log(lengthKey)
}
1.4.1 创建数组
// 创建一个空数组
let emptyArray = []
let fruits = ["Apple", "Banana", "Cherry"]
1.4.2 访问数组元素
通过索引访问,索引是元素在数组中的位置,从 0 开始计数。
let firstFruit = fruits[0] // 访问第一个元素,"Apple"
let secondFruit = fruits[1] // 访问第二个元素,"Banana"
1.4.3 修改数组元素【通过索引】
fruits[2] = "Orange" // 将第三个元素修改为 "Orange"
1.4.4 数组属性和方法
length
属性用于获取数组的长度(元素数量)。
let count = fruits.length // 获取数组的长度
//遍历
for(let i=0;i<数组名.length;i++){
}
push()
方法用于在数组的末尾添加一个或多个元素,并返回新的长度。
fruits.push("Mango") // 在数组末尾添加 "Mango"
pop()
方法用于移除数组的最后一个元素,不带参数,并返回那个元素
let lastFruit = fruits.pop() // 移除并返回数组的最后一个元素
shift()
方法用于移除数组的第一个元素,不带参数,并返回那个元素
let firstFruit = fruits.shift() // 移除并返回数组的第一个元素
unshift()
方法用于在数组的开头添加一个或多个元素,并返回新的长度
fruits.unshift("Strawberry") // 在数组开头添加 "Strawberry"
indexOf()
方法用于搜索数组中的元素,并返回其索引(如果不存在,则返回 -1)
let index = fruits.indexOf("Banana") // 获取 "Banana" 的索引
splice(操作下标, 删除个数)
let arr=[1,2,3,4,5]
console.log(arr.splice(1,2))
1.5 常量
const
关键字用于声明一个常量。一旦赋值后,其值就不能再改变。
尝试重新赋值一个已经声明的常量会导致运行时错误。
当某个变量永远不会改变的时候,就可以使用 const 来声明,而不是let。
1.5.1 声明常量
const PI = 3.14
1.5.2 特性
- 块级作用域:与
let
类似,const
也具有块级作用域(block scope),意味着在声明它的块、语句或表达式之外无法访问。
if (true) {
const MAX = 5
}
console.log(MAX) // ReferenceError: MAX is not defined
- 不可重新赋值:一旦给
const
声明的变量赋值后,就不能再对其重新赋值。
const MAX = 5
MAX = 10 // TypeError: Assignment to constant variable.
- 不可重复声明:在同一作用域内,不能重复声明同一个常量。
const MESSAGE = "Hello, world!"
const MESSAGE = "Hello again!" // SyntaxError: Identifier 'MESSAGE' has already been declared
- 初始化时赋值:
const
声明的常量需要在声明时就进行初始化,即赋值。
const GREETING // SyntaxError: Missing initializer in const declaration
1.6 数据类型
基本:number 数字型、string 字符串型、boolean 布尔型、undefined 未定义型、null 空类型
引用:object 对象
NaN代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果
console.log('str' - 2) // NaN
NaN是粘性的。任何对NaN的操作都会返回 NaN
console.log(NaN + 2) // NaN
1.6.1 字符串
字符串是用于存储文本数据的一种数据类型。字符串可以包含字母、数字、空格、符号等字符,它们被包裹在单引号 ''
、双引号 ""
或反引号 ``中。
(1)创建字符串
let greeting = "Hello, world!"
let name = 'John Doe'
let message = `Hello, ${name}`
greeting
和 name
是使用双引号和单引号创建的普通字符串。
message
是使用反引号创建的模板字符串,它允许嵌入变量和表达式。
(2)常用字符串操作
-
连接字符串:可以使用
+
操作符连接两个或多个字符串数字相加,字符相连
let fullName = "John" + " " + "Doe" // "John Doe"
- 获取字符串长度:
.length
属性获取字符串的长度(字符数)
let length = greeting.length // 字符串 "Hello, world!" 的长度
- 访问单个字符:可以方括号
[]
语法或.charAt()
方法访问字符串中的特定字符
let firstChar = greeting[0] // "H"
let char = greeting.charAt(2) // "l"
-
字符串不可变性:字符串是不可变的,一旦字符串被创建,内容就不能被改变。要修改字符串,需要创建一个新的字符串。
-
模板字符串:反引号 ``创建模板字符串,可以在其中嵌入变量和表达式。
let age = 30
let introduction = `My name is ${name} and I am ${age} years old.`
- 字符串方法:Js 提供了许多字符串方法来进行搜索、替换、切割等操作,例如
.toUpperCase()
,.toLowerCase()
,.slice()
,.split()
,.replace()
等。
let upperCaseGreeting = greeting.toUpperCase() // "HELLO, WORLD!"
let lowerCaseName = name.toLowerCase() // "john doe"
let slicedGreeting = greeting.slice(0, 5) // "Hello"
let words = greeting.split(" ") // ["Hello,", "world!"]
let replacedGreeting = greeting.replace("world", "everyone") // "Hello, everyone!"
(3)注意事项
- 成对使用单引号或双引号:字符串可以用单引号
'
或双引号"
包裹,但必须确保开头和结尾使用的是同一种引号。
let correctString = "This is correct."
let incorrectString = "This is incorrect.' // 语法错误
- 单引号和双引号的嵌套使用:为了在字符串中包含引号,可以通过“外双内单”或“外单内双”的方式来嵌套引号,这样可以避免结束字符串的引号与字符串内部的引号混淆。
let quoteInString = "He said, 'Hello, world!'"
let anotherQuoteInString = 'She replied, "Hi, there!"'
这种方法允许在字符串内部使用引号,而不需要转义字符。
- 使用转义符
\
:使用转义符\
来实现。转义符可以让引号被解释为字符串的一部分,而不是字符串的结束标志。
let escapedQuote = "He said, \"Hello, world!\""
let anotherEscapedQuote = 'She replied, \'Hi, there!\''
(4)模版字符串
``(反引号)
内容拼接变量时,用${}包住变量
模板字符串使用反引号(` `)标识,而不是传统的单引号(’ ')或双引号(" ")。
- 多行字符串:模板字符串可以很容易地跨越多行,而不需要使用连接符或特殊字符。
let multiLineString = `这是一个
跨越多行的
字符串`
- 字符串插值:模板字符串允许在字符串中嵌入变量或表达式,这些变量或表达式的值将在运行时被计算并插入到字符串中。嵌入表达式使用
${expression}
语法。
let name = '张三'
let greeting = `你好,${name}!`
console.log(greeting) //你好,张三!
- 表达式计算:在模板字符串中,可以嵌入任何有效的 Js 表达式,包括函数调用、运算等。
let price = 10
let taxRate = 0.05
let total = `总价是:${price * (1 + taxRate)}元`
console.log(total) // 总价是:10.5元
- 标签模板:模板字符串可以与函数结合使用,形成所谓的“标签模板”。这种方式允许函数对模板字符串进行解析和处理。
function tag(strings, ...values) {
console.log(strings) // 字符串数组
console.log(values) // 表达式值数组
return "处理后的字符串"
}
let taggedResult = tag`这是${name}的模板字符串,总价${total}`
1.6.2 布尔类型、未定义型号undefined、null
(1)布尔类型
布尔类型有两个值:true
和 false
。
let isTrue = true
if (isTrue) {
console.log("真")
}
(2)未定义(undefined
)
当一个变量被声明了但没有被赋值时,它的值就是 undefined
。表示变量未持有值的特殊类型和值。
let num
console.log(num) //undefined
console.log(undefined + 1) //NaN
(3)空(null
)
null
是一个表示无值的特殊值。
与 undefined
不同,null
通常被视为一个空对象引用或用来表示变量被显式清空。
let obj = null
console.log(obj) //null
console.log(null + 1) //1
(4)null
和 undefined
的区别
- 含义:
undefined
表示变量已声明但未赋值;null
表示变量已赋值,但值为空。 - 类型:
undefined
是自己的类型(undefined
);null
是一个对象(错误地,因为历史原因)。 - 运算:在数学运算中,
undefined
会被转换为NaN
,而null
会被转换为0
。
尽管 null
和 undefined
都表示“没有值”,但它们的用途和含义有细微的差别。
在实践中,null
通常用于初始化一个变量,以便稍后将其赋值为对象,而 undefined
通常表示变量未被初始化。
1.6.3 检测数据类型
1.作为运算符: typeof x (常用的写法)
2. 函数形式: typeof(x)
1. 作为运算符:typeof x
typeof
后面直接跟着变量或表达式,中间有一个空格。
let num = 42
console.log(typeof num) //"number"
2. 函数形式:typeof(x)
let str = "Hello, world!"
console.log(typeof(str)) //"string"
1.6.4 类型转换
隐式类型转换
字符串拼接:当使用 + 操作符连接字符串和非字符串时,非字符串类型会被转换为字符串类型。
let result = "The number is " + 123 // "The number is 123"
数学运算:在数学运算中(除了 + 操作符),如果操作数之一是非数字,Js 会尝试将其转换为数字。
let result = "6" / "2" // 3
console.log(result)
显式类型转换
转换为字符串
使用 String() 函数。
使用 .toString() 方法(注意:null 和 undefined 没有这个方法)。
使用模板字符串。
let value = 123
console.log(String(value)) // "123"
console.log(value.toString()) // "123"
console.log(`${value}`) // "123"
转换为数字:
使用 Number() 函数。
使用一元加号 +。
使用 parseInt() 或 parseFloat() 函数。
let str = "123"
console.log(Number(str)) // 123
console.log(+str) // 123
console.log(parseInt(str)) // 123
转换为布尔值
let str = "hello"
console.log(Boolean(str)) // true
1.6.5 基本数据类型(也称为简单类型或值类型)和引用数据类型。
基本数据类型(值类型)
基本数据类型包括:string
、number
、boolean
、undefined
、null
、symbol
(ES6新增)和 bigint
(ES2020新增)。这些类型的特点是,它们的值直接存储在变量访问的位置。也就是说,当你创建一个变量并赋予一个基本类型的值时,变量中存储的就是这个值本身。当你将一个基本类型的变量赋值给另一个变量时,会在内存中创建这个值的一个副本。
例如:
let a = 10;
let b = a;
b = 20;
console.log(a); // 输出 10,a的值不会因为b的改变而改变
引用数据类型
引用数据类型包括:object
(对象)、array
(数组)、function
(函数)等。这些类型的特点是,变量中存储的不是数据本身的值,而是数据所在的地址(也就是引用)。这意味着,当你创建一个变量并赋予一个对象时,变量中存储的是这个对象在内存中的地址。当你将一个引用类型的变量赋值给另一个变量时,复制的是这个地址,因此两个变量指向内存中的同一个对象。
例如:
let obj1 = { name: 'Alice' };
let obj2 = obj1;
obj2.name = 'Bob';
console.log(obj1.name); // 输出 'Bob',因为obj1和obj2指向同一个对象
1.7 作用域
作用域是指在代码中定义变量的区域,JavaScript中有全局作用域和局部作用域。
全局作用域中的变量可以在整个代码中访问,而局部作用域中的变量只能在其定义的区域内访问。
函数创建了自己的作用域,变量在函数内部定义时只能在函数内部访问。
JavaScript采用词法作用域,即变量的作用域在代码编写时就确定了。
全局有效作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件
局部有效作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
二、语句
2.1运算符
‘=’ 是赋值运算符
+=
-=
*=
/=
%=
比较运算符(推荐用三等) ‘’
'=’
‘!=’
‘!==’
Test
NaN不等于任何值,包括它本身
console.log(3>=5)
console.log(3!=5)
console.log(3!=='5')
console.log(undefined==null)
console.log(undefined===null)
//NaN不等于任何值,包括它本身
console.log(NaN===NaN)
console.log(3!=='3')
console.log('a'<'b')
console.log('aa'<'ab')
2.1.1 逻辑中断
console.log(1 && 0)
console.log(0 || 1)
console.log(0 || 0)
console.log(!1)
console.log(1 == 2 && 1 >=0)
- 短路现象只存在于逻辑运算符 && 和 || 中。
- 短路发生在左侧为false时的 && 运算和左侧为true时的 || 运算。
- 左侧结果已确定整个表达式的值,因此无需计算右侧。
- 逻辑运算符的结果取决于最后执行的表达式的值。
- 通常用于条件赋值。
2.1.2 转换为布尔类型显示转换:
使用 Boolean(内容)
进行转换。记忆规则是:0
、undefined
、null
、false
、NaN
转换为布尔值后都是 false
,其余值则为 true
。
console.log(false && 20) // false
console.log(5 < 3 && 20) // false
console.log(undefined && 20) // undefined
console.log(null && 20) // null
console.log(0 && 20) // 0
console.log(10 && 20) // 20
console.log(false || 20) // 20
console.log(5 < 3 || 20) // 20
console.log(undefined || 20) // 20
console.log(null || 20) // 20
console.log(0 || 20) // 20
console.log(10 || 20) // 10
转换为布尔类型隐式转换:
- 字符串的加法
"" + 1
结果为"1"
- 减法
-
只能用于数字,会将空字符串""
转换为0
null
经过数字转换后会变为0
undefined
经过数字转换后会变为NaN
2.2 表达式(Expression)
在Js中,表达式是任何有效的代码单元,它可以被解释(计算)为一个值。简单来说,表达式是一个或多个值、变量、操作符的组合,它们一起可以计算出一个值。
一段可计算并返回一个值的代码片段。它可以是简单的常量、变量、函数调用,也可以是复杂的包含各种运算符连接起来的式子。
在执行时会被求值(evaluated),其结果可以被进一步赋值给变量、作为函数参数传递、参与条件判断以及其他各种计算过程。
2.2.1 示例
- 数值表达式:
5
,8.2
- 字符串表达式:
"hello"
,'world'
- 算术表达式:
5 + 6
,7 * 3
- 逻辑表达式:
true && false
,5 > 3
- 函数调用表达式:
console.log("Hello, world!")
- 赋值表达式:
let x = 5
,y = x + 2
表达式根据其操作数(如果有的话)和产生的值的类型,可以进一步分类为“算术表达式”、“字符串表达式”、“逻辑表达式”等》》
2.2.2 分支语句
(1)if语句
根据条件表达式的真值(true
或 false
)来决定是否执行特定的代码段。
基本语法
if (条件) {
// 当条件为 true
}
带 else
的 if
语句
if (条件) {
// 当条件为 true
} else {
// 当条件为 false
}
if
-else if
-else
链
if (条件1) {
// 当条件1为 true
} else if (条件2) {
// 当条件1为 false 且条件2为 true
} else {
// 当上述条件都不满足时执行的代码
}
(2)特殊的分支语句–三元运算符
一种简洁的条件表达式,在两个表达式之间做出选择,基于条件表达式的真值(true
或 false
)
条件 ? 表达式1 : 表达式2
当条件为 true
,则执行并返回 表达式1
的结果;当条件为 false
,则执行并返回 表达式2
的结果。
let score = 75
let result = score >= 60 ? "及格" : "不及格"
console.log(result) // 及格
适合用于简单赋值和决策,但对于更复杂的逻辑和多个条件的情况, if
-else
语句会更清晰易读。
(3)switch语句
switch
语句用于执行多个条件分支的一种控制流语句。根据表达式的值与不同的 case
标签匹配来执行相应的代码块。
当没有任何 case
匹配,且存在 default
分支,则执行 default
分支的代码。
基本语法
switch (表达式) {
case 值1:
// 当表达式的结果等于值1时执行的代码
break
case 值2:
break
// 可以有任意数量的 case 语句
default:
// 当没有任何 case 匹配,执行这里的代码
}
注意事项
- 每个
case
后面通常都会跟一个break
语句,用于退出switch
语句。如果省略break
,程序将会继续执行下一个case
的代码,直到遇到break
或switch
语句结束。 default
分支是可选的。case
的值必须是常量,且所有的case
值在同一个switch
语句中必须是唯一的。
- switch case语句一般用于等值判断,不适合于区间判断
- switch case一般需要配合break关键字使用没有break会造成case穿透
let fruit = "apple"
switch (fruit) {
case "banana":
console.log("香蕉")
break
case "apple":
console.log("苹果")
break
case "orange":
console.log("橙子")
break
default:
console.log("未知的水果")
}// 苹果
(4)if 和switch的区别
if
语句
- 灵活性:
if
语句可以处理范围更广的条件测试,包括各种逻辑表达式。 - 条件:可以使用任何返回布尔值的表达式作为条件。
- 适用场景:适合于条件数目不多,且条件较为复杂的情况。
switch
语句
- 简洁性:当需要根据同一个表达式的不同值来执行不同代码块时,
switch
语句比多个if
-else if
结构更简洁。 - 条件限制:
switch
的条件表达式的结果必须是一个常量或字面量。每个case
标签也必须是唯一的常量或字面量。 - 适用场景:适合于有多个固定选项需要判断的情况,特别是当这些选项是同一个变量或表达式的不同值时。
主要区别
- 条件复杂度:
if
语句可以处理更复杂的逻辑条件,switch
语句主要用于检查单个变量或表达式的多个特定值。 - 性能:在检查多个值时,
switch
语句在某些情况下可能比多个if
-else if
语句更高效,因为switch
通常使用跳转表来实现。 - 默认行为:
switch
语句有一个default
分支,用于处理所有未明确列出的情况,而在使用if
-else
语句时,最后的else
分支承担类似的角色,但使用上更灵活。
2.2.3 循环语句
当明确了循环的次数的时候推荐for循环
当不明确循环的次数的时候推荐while循环
1. for
循环
for (初始化; 条件表达式; 增量表达式) {
// 循环体
}
2. while
循环
while (条件) {
// 循环体
}
3. do...while
循环
无论条件如何,循环体至少执行一次
do {
// 循环体
} while (条件);
4. for...in
循环
用于遍历对象的属性。
for (变量 in 对象) {
// 变量访问对象的每个属性
}
5. for...of
循环
ES6 引入,用于遍历可迭代对象(如数组、字符串等)的值。
for (变量 of 可迭代对象) {
// 变量访问可迭代对象的每个值
}
Js 循环的特点
- 灵活性:根据不同的需求选择最合适的循环方式。
- 可迭代对象支持:
for...of
循环提供了一种简单的方法来迭代元素。 - 对象属性遍历:
for...in
循环允许遍历一个对象的所有可枚举属性,这在处理对象时非常有用。 - 循环控制语句:
break
和continue
语句可以用于在特定条件下退出循环或跳过循环的某次迭代。 - 标签语句:Js 支持标签语句,与
break
和continue
一起使用,可以实现复杂的跳出循环和继续循环的逻辑。
2.2.4 退出循环
break
语句用于立即退出最近的包围它的循环,无论是 for
、while
还是 do...while
循环。
一旦执行了 break
语句,循环将停止执行,控制流将移至循环后的下一条语句。
let i =1
while (i<=5){
console.log(`${i}`)
i++
if(i===2){
i++
continue
}
if(i===4)break
}
(1) break
退出循环的示例
退出 for
循环
for (let i = 0; i < 10; i++) {
if (i === 5) {
break // 当 i 等于 5 时退出循环
}
console.log(i)
}// 0 1 2 3 4
退出 while
循环
let i = 0
while (i < 10) {
if (i === 5) {
break // 当 i 等于 5 时退出循环
}
console.log(i)
i++
}// 0 1 2 3 4
(2) break
与标签
使用标签与 break
语句结合的方式,来退出指定的外层循环。
使用标签退出嵌套循环
outerLoop: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outerLoop; // 当 i 和 j 都等于 1 时,退出外层循环
}
console.log(`i = ${i}, j = ${j}`)
}
}
// i = 0, j = 0
// i = 0, j = 1
// i = 0, j = 2
// i = 1, j = 0
continue
语句用于跳过循环中的当前迭代,并继续执行循环的下一次迭代
与 break
语句不同,continue
并不会完全退出循环,而是仅仅跳过当前的迭代步骤
(3) continue
的示例
在 for
循环中使用 continue
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) {
continue // 当 i 是偶数,则跳过当前迭代
}
console.log(i) // 只打印奇数
}
在 while
循环中使用 continue
let i = 0
while (i < 10) {
i++
if (i % 2 === 0) {
continue // 当 i 是偶数,则跳过当前迭代
}
console.log(i) // 只打印奇数
}
使用 continue
时,需要注意更新循环条件中的变量,以避免造成无限循环
(4) continue
与标签
与 break
语句类似,continue
也可以与标签一起使用,以跳过当前迭代并继续执行特定外层循环的下一次迭代
使用标签与 continue
跳过嵌套循环的当前迭代
outerLoop: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
continue outerLoop; // 跳过外层循环的当前迭代
}
console.log(`i = ${i}, j = ${j}`);
}
}
三、函数
函数的存在是一组可以随时运行实现某种特定功能的封装好的语句。其中包含了0个或者多个参数,可以包含返回值也可以没有。
例如我们之前就使用过的alert()、console.log()、prompt()等函数
3.1 定义函数与调用
函数名的命名规范和变量命名基本一致,使用小驼峰式命名法,前缀应该为动词。常用的动词约定可作为函数名的建议。
函数一次声明可以多次调用,每一次函数调用函数体里面的代码会重新执行一次
// 方法一:定义函数
function greet(name) {
return "Hello, " + name + "!";
}
// 调用方法一定义的函数
console.log(greet("Alice"));
// 方法二:使用函数表达式定义函数
const greet2 = function(name) {
return "Hello, " + name + "!";
};
// 调用方法二定义的函数
console.log(greet2("Bob"));
// 方法三:使用箭头函数定义数
const greet3 = (name) => {
return "Hello, " + name + "!";
};
// 调用方法三定义的函数
console.log(greet3("Charlie"));
// 方法四:使用Function构造函数定义函数
const greet4 = new Function('name', 'return "Hello, " + name + "!";');
// 调用方法四定义的函数
console.log(greet4("David"));
3.2 参数和带返回值函数
break结束循环
continue跳过本次循环
return结束函数
参数默认值只在缺少实参时才会被执行,有实参时会优先使用实参,否则默认为undefined。
// 有返回值的函数示例
function add(x, y) {
return x + y; // 返回x和y的和
}
// 调用add函数并将结果赋值给result
let result = add(3, 4);
// 输出结果
console.log(result);
说明:在函数体中使用return关键字可以将内部的执行结果交给函数外部使用。函数可以没有return语句,这种情况下函数默认返回值为undefined。
return会理解结束当前函数,所以我们在返回数据的时候不希望我们换行的失误丢失一定量的信息。
3.3 立即执行函数
(function(){})()
(function(){}())
// 立即执行函数示例
(function() {
console.log("这是一个立即执行函数");
})();
// 带参数的立即执行函数示例
(function(x, y) {
console.log("这是一个带参数的立即执行函数,参数相加的结果为: " + (x + y));
})(3, 4);
四、类对象
类对象是一种数据类型,用于描述某一类事物。
-
使用字面量方式声明类对象:
let obj = {}
这种方式使用了对象字面量的语法,通过一对大括号表示一个对象。
-
使用构造函数方式声明类对象:
let obj = new Object()
这种方式使用了对象的构造函数
Object()
来创建一个新的对象。通过new
关键字创建对象实例。
两种方式都可以创建一个空的类对象。然后你可以通过给对象添加属性和方法来描述这个类对象。例如:
obj.name = "Apple"
obj.color = "Red"
obj.getInfo = function() {
return this.name + " is " + this.color;
}
null是JavaScript中的一个特殊值,用于表示空值或者不存在的对象。它是基本数据类型,可以赋值给变量表示该变量没有有效值。
4.1 属性
属性是类对象中的数据项,用于存储描述该对象特征的值。
可以将属性视为对象的特征描述或状态。
在JavaScript中,属性由键值对表示,其中键是属性的名称,值是属性的值。类对象可以具有多个属性,每个属性可以具有不同的名称和值。
-
添加属性:可以使用点表示法或方括号表示法来添加属性。
// 使用点表示法添加属性 obj.name = "Apple"; // 使用方括号表示法添加属性 obj["color"] = "Red";
例如可以使用赋值操作或者使用方括号形式添加新属性:
let obj = { name: '张三', age: 18, }; console.log(obj); // 输出:{ name: '张三', age: 18 } obj.sex = '男'; console.log(obj.sex); // 输出:男 obj['sex'] = '男'; console.log(obj); // 输出:{ name: '张三', age: 18, sex: '男' }
-
访问属性:可以使用点形式(
对象.属性
)或方括号形式(对象['属性']
)来访问属性。// 使用点表示法访问属性 console.log(obj.name); // 输出: "Apple" // 使用方括号表示法访问属性 console.log(obj["color"]); // 输出: "Red"
对于多词属性或包含特殊字符的属性,无法使用点操作符形式访问,此时可以使用方括号形式。
let obj = { 'user-Name': '张三', }; console.log(obj['user-Name']); // 输出:张三
两种访问方式的区别在于使用点操作符时,属性名不能包含特殊字符且不能为关键字,使用方括号形式则没有这个限制。
-
修改属性:可以直接对对象的属性进行赋值来修改属性的值。
obj.name = "Banana";
-
删除属性:可以使用
delete
关键字来删除属性。let obj = { name: '张三', age: 18, }; delete obj.name; console.log(obj.name); // 输出:undefined
删除属性后,再次访问该属性将会返回
undefined
。
注意,在访问属性时,使用点表示法更简洁直观,但是方括号表示法可以接受变量和动态属性名称。
4.2 方法
方法:就是对象能够完成的一些功能,方法就是函数,
函数是独立存在的,而方法就是对象中的函数。
- 定义对象方法:
let obj = {
name: '张三',
sayHello: function() {
console.log('你好!');
}
};
obj.sayHello(); // 输出:你好!
- 对象方法中访问对象属性:
let obj = {
name: '张三',
age: 18,
sayName: function() {
console.log('我的名字是' + this.name);
}
};
obj.sayName(); // 输出:我的名字是张三
在对象方法中,我们可以使用关键字this
来引用该对象的属性。
- 使用对象方法传递参数:
let obj = {
name: '张三',
sayHelloTo: function(person) {
console.log('你好,' + person + '!');
}
};
obj.sayHelloTo('李四'); // 输出:你好,李四!
需要注意的是,对象方法中的this
关键字指向调用该方法的对象本身,因此可以在方法中访问和修改该对象的属性。同时,对象方法可以访问其他对象的方法和属性,甚至可以在方法中创建新的属性和方法。
4.3 注意
-
方法由方法名和函数组成,它们之间使用冒号(:)分隔,将方法名与定义的函数关联起来。例如:
methodName: function() { }
。 -
对象的多个属性之间使用逗号(,)进行分隔。例如:
{ property1: value1, property2: value2 }
。 -
方法是依附在对象中的函数,意味着它们属于对象的一部分,可以通过对象名使用点操作符来调用。例如:
objectName.methodName()
。 -
方法名可以使用引号(单引号或双引号)括起来,也可以不加引号。通常情况下,如果方法名是一个有效的标识符且不包含特殊字符,可以省略引号。例如:
methodName: function() { }
和'method-name': function() { }
都是有效的方法定义。
如果方法名包含特殊字符,如空格、中横线等,那么必须使用引号将方法名括起来。例如:'method name': function() { }
和'method-name': function() { }
。
4.3 在Js中遍历对象
-
for…in循环:使用for…in循环可以遍历对象的属性。这种方法会将对象的每个可枚举属性包括在内,以及从原型链继承的可枚举属性。
k 是获得对象的属性名,对象名[k]是获得 属性值
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
// 执行你的操作
console.log(key + ": " + obj[key]);
}
}
- Object.keys()方法:Object.keys(obj)返回一个包含对象的所有可枚举属性的数组。
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
// 执行你的操作
console.log(key + ": " + obj[key]);
}
- Object.entries()方法:Object.entries(obj)返回一个包含对象的所有可枚举属性键值对的二维数组。
var entries = Object.entries(obj);
for (var i = 0; i < entries.length; i++) {
var key = entries[i][0];
var value = entries[i][1];
// 执行你的操作
console.log(key + ": " + value);
}