前言
- HTML 表示网页的 结构;
- CSS 表示网页的 样式;
- JavaScript 表示网页的 行为;
- 浏览器内核 = 渲染引擎 + JS引擎;
- JavaScript的组成:
- ECMAScript — JS的基础语法;
- Web APIs:
- DOM — 操作文档流的属性和方法(文档对象模型);
- 是HTML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式,可以在程序中对该结构进行访问,从而改变文档的结构、样式和内容。DOM将文档解析为一个由节点和对象(包含属性和方法)组成的结构集合。简言之,它会将 web页面和 程序 连接起来。进而操作网页的内容,实现各种功能和部分特效;
- BOM — 操作浏览器的属性和方法(浏览器对象模型);
![]()
- JS的本质: 通过 JS 的语法,让 浏览器 发生变换,让 文档 发生变化。
一、JavaScript书写位置
- 行内 JavaScript;
- 内部 JavaScript;
- 外部 JavaScript;
二、输入输出语法
- 小括号里面只要 不是纯数字 和 变量 必须要用 引号包裹(单、双、反)
alert() --- 警示框 prompt() --- 浏览器弹出输出框,用户可以输入信息 console.log() --- 控制台输出 document.write() --- 在文档页面输出(识别标签)
- 代码展示:
alert('你好, js'); prompt('JavaScript 基础'); console.log('它~会魔法吧~'); document.write('javascript我来');
三、字面量、变量、常量
3.1 字面量
- 用来在计算机中描述 事 / 物
- [ ] : 数组字面量
- { } : 对象字面量
- 数字字面量:数字
- 字符字面量:字符串
- 布尔字面量:布尔值
3.2 变量
- 变量:用来 存储数据 的 容器
- 变量的本质:内存里的一块空间,用来 存储数据
- 变量 必须 先声明 后使用
- 变量的初始化: 声明变量 并 赋值
- 变量命名规则:变量名只能是 数字、大小写字母、美元符($)、下划线组成;
- ❗ 注意:
- 如果是使用
var
声明变量,不能使用name
作为变量名;
- 因为
name
会将 数据类型 转换为 字符串类型;var name = 123; // 123 string var name = [1, 2, 3]; // 1, 2, 3 string var name = { a: 1 }; // [object Object] string var name = () => { console.log(123) }; // () => { console.log(123) } string console.log(name, typeof(name));
- 声明 变量使用 let
- 代码展示:
// 声明变量 // 声明变量不赋值 let a // 变量的初始化 --- 声明变量并赋值 let age = 18 // 声明多个变量(用逗号隔开)--- 不推荐 let a = 18, b = 'pink' // 更新变量 let age = 18 age = 19 console.log(age) // 19 // 用变量赋值 let myFood = '香蕉' let youFood = myFood console.log(youFood) // 香蕉
3.3 常量
- 声明常量使用 const;
- ❗ 常量不允许重新赋值,声明的时候必须赋值 (必须初始化);
- 注意:
const num = 10; num = 10; console.log(num); // 报错 - 常量不允许重新赋值
3.4 拓展:var 和 let 区别
- var
- 可以 先使用 再声明;
- var声明过的变量可以重复声明;
- 存在变量提升、没有块作用域等等。
- let / const
- 必须 先声明 后使用
- 不能 声明 重复变量;
- 不存在变量提升;
- 使用了 let / const 声明的变量存在块作用域;
- const声明变量的时候必须初始化;
四、❗❗ 数据类型
- 1️⃣ 值类型 (基本数据类型)(6)
number
— 数字型string
— 字符串型boolean
— 布尔型undefined
— 未定义型null
— 空类型symbol
(了解)bigint
— 大整数
- 2️⃣ 引用数据类型 (复杂数据类型)(3)
object
— 对象function
– 函数array
— 数组
4.1 数字型 - number
- 数字型 由 两部分 组成:
number
;NaN
;
4.1.1 Number
Number
:一切十进制表示的数字;
Number.MAX_VALUE // 数字中的最大值
Number.MIN_VALUE // 数字中的最小值
Infinity // 无穷大
-Infinity // 无穷小
NaN // 非数值
- isNaN(数据) 这个方法用来判定非数字,并且返回一个值,如果是数字返回 false,如果不是数字返回 true
-
4.1.2 NaN
NaN
代表一个计算错误,它是一个 不正确的 或者 一个未定义 的 数学操作 所得到的 结果;- ⚠
NaN
是 粘性 的。任何对NaN
的操作都会返回NaN
console.log(2 - NaN) // NaN
console.log('粘性' + NaN) // NaN
console.log(NaN === NaN) // NaN
4.2 字符串型 - string
- 用引号(单引号 / 双引号 / 反引号)包裹的都是字符串
4.2.1 字符串的长度
// lengtn 属性
let strMsg = '扶我起来,我还能干!';
console.log(strMsg.length) // 显示 10
4.2.2 字符串的拼接
- 多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 新的字符串
- 拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串
- “+”:数字相加,字符相连
4.2.3 ❗❗ 模板字符串
- 使用 反引号(``) 包裹;
- 模板字符串可以 嵌套变量:
- 嵌套变量的时候,使用
${变量}
包裹变量即可;
- 嵌套变量的时候,使用
- 代码展示:
let myName = `邵秋华` let age = 22 let str = `扶我起来,我还能干!` document.write(`我叫${myName},今年${age}岁了,我的座右铭是${str}`)
4.2.4 ❌ 转义字符
![image-20220623200802891](https://i-blog.csdnimg.cn/blog_migrate/1e43d7fa8da0ad5acd9b4a51ee5039c2.png)
4.3 布尔型 - boolean
- 布尔类型 有 两个值,true 和 false,其中 true 表示 真,而 false 表示 假
- 布尔型 和 数字型 相加 的时候,
true = 1
,false = 0
- ❗ 除了
0
、''
、undefined
、null
、NaN
、false
转换为布尔值后为 假,其余都为真
4.4 未定义类型 - undefined
- 只声明变量,不赋值 的情况下,变量的默认值为
undefined
undefined
这里本该有一个值,但是没有,就是undefined
- ❗
数字 + undefined = NaN
- 出现情况:
- 声明变量未赋值
- 数组 里面 没有 某个 元素
- 对象 里面 没有 某个 属性 或 方法
- 函数
- 形参多于实参(没有赋值的形参默认值是 undefined)
- 函数未指定返回值(没有 return 关键字)
console.log(undefind + 1) // NaN
condsole.log(undefined + 'purple') // undefinedpurple
console.log(typeof(undefined)) //undefined
4.5 空类型 - Null
- Null 这里有一个值,有一个空值
- ✅参与 数学运算 的时候,
null = 0
console.log(null + 1) // 1
console.log(null + 'purple') // nullpurple
console.log(typeof(null)) // object
![image-20220623194305096](https://i-blog.csdnimg.cn/blog_migrate/1ec5bbeaaace9475c1392e75988afc8c.png)
4.6 null 和 undefined 区别:
-
undefined 表示 声明了一个变量,但是没有赋值
-
let num console.log(undefined + 1) // NaN
-
-
null 表示 声明了一个变量 并且 赋值了,但是内容为空
-
let num = null console.log(null + 1) // 1
-
-
✅注意:
- ❗
null
和undefined
值相等,数据类型不相等
console.log(null == undefined) // true
- ❗
4.7 检测数据类型
- 1️⃣ 作为运算符:
typeof 数据
- 以 字符串 的形式 给你变量的数据类型
- ❗ 使用 typeof 检测 错误类型 为 undefined 的代码不会报错,检测结果是 undefined
- 2️⃣ 函数形式:
typeof(数据)
(推荐使用)- 以字符串的形式给你变量的数据类型
- 先运算小括号里面结果,然后去检测结果的数据类型
- 代码展示:
let num = 10; console.log(typeof num); // number let str = 'purple'; console.log(typeof str); //string let flag = true; console.log(typeof flag); //boolean let i = undefined; console.log(typeof i); //undefined let timer = null; console.log(typeof timer); //object // 注意 console.log(typeof (a)); // undefined
- 3️⃣
instanceof
- 用于检测构造函数的
prototype
属性是否出现在某个实例对象的原型链上。 - 返回值:布尔值(true / false)
- 注意:
- 只能检测引用数据类型;
- 检测基本数据类型的时候,得到的是
false
;
- 代码展示:
'123' instanceof String // false [1, 2, 3] instanceof Array // true
- 用于检测构造函数的
- 4️⃣ 究极方法:
Object.prototype.toString()
- 可以通过
toString()
来获取每个对象的类型。为了每个对象都能通过Object.prototype.toString()
的检测,需要以Function.prototype.call()
或Function.prototype.apply()
的形式来调用,传递要检查的对象作为第一个参数。 - 返回值:[ object type ]
- 代码展示:
// 引用数据类型 const obj = {uname: '迪迦', age: 22}; console.log(Object.prototype.toString.call(obj)); // [object Object] const arr = [1, 2, 3]; console.log(Object.prototype.toString.call(arr)); // [object Array] const fn = function () { console.log(1) }; console.log(Object.prototype.toString.call(fn)); // [object Function] // 基本数据类型 console.log(Object.prototype.toString.call(123)); // [object Number] console.log(Object.prototype.toString.call('123')); // [object String] console.log(Object.prototype.toString.call(false) ); // [object Boolean] console.log(Object.prototype.toString.call(undefined)); // [object Undefined] console.log(Object.prototype.toString.call(null)); // [object Null]
- 可以通过
4.8 数据类型转换
4.8.1 转数字
- 1️⃣
parseInt(string)
可以把 字符串型 转换为 整数型(不识别小数点)- 从 第一个字符开始 取第一个整数,如果取不到就是NaN
- ❗ 转换的字符开头如果不是数字,就是NaN
- 代码展示:
console.log(parseInt('3.14')) //3(取整数位) console.log(parseInt('3.99')) //3(取整数位) console.log(parseInt('120px')) //120 (自动去除单位,前面必须是数字) console.log((parseInt'rem120px')) //NaN console.log(parseInt(true)) //NaN console.log(parseInt(null)); // NaN
- 2️⃣
parseFloat(string)
可以把 字符串型 转换为 浮点型(识别小数点)- 从第一个字符开始取第一个小数,如果取不到就是NaN
- ❗ 转换的字符开头如果不是数字,就是NaN
- 代码展示:
console.log(parseFloat('3.14')); //3.14 console.log(parseFloat('3.99')); //3.99 console.log(parseFloat('120px')); //120 (自动去除单位,前面必须是数字) console.log(parseFloat('rem120px')); //NaN console.log(parseFloat(true)) //NaN console.log(parseFloat(null)); // NaN
- ❗ 注意:
parseInt 和 parseFloat 单词的大小写
- 3️⃣
Number(string)
强制转换- 转换的数据中不能包含非数字,如果有就是NaN
- 识别小数点
- 代码展示:
let num = '123'; console.log(Number(num)); //123 console.log(Number('12')); //12 console.log(NUmber('123.123'); // 123.123 console.log(Number('123abc'); //NaN console.log(Number(null)); // 0 console.log(Number(true)); // 1 console.log(Number(false)); // 0
- 4️⃣ 利用了算术运算 +(正号) - * / % 隐式转换;
- 代码展示:
console.log('12' - 0); //12 (先将 '12' 转换成数字型在进行减) console.log('123' - '120'); //3 console.lof('123' * 1); //123 console.log(+'123') //123 + 号作为正号解析可以转换成数字型(单用)
let year = prompt('请输入您的出生年份:'); //let age = 2022 - year; alert('您今年:' + (2022 - year) + '岁了');
- 注意:
- 隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型
- 代码展示:
let num1 = prompt('请输入第一个数据:'); //得到的num1是字符型的 let num2 = prompt('请输入第二个数据:'); //得到的num2是字符型的 let result = parseInt(num1) + parseInt(num2); alert(parseInt(num1) + '+' + parseInt(num2) + '=' + result); /* let num1 = +prompt('请输入第一个数据:'); let num2 = +prompt('请输入第二个数据:'); let result = num1 + parseInt(num2); */
- 代码展示:
![image-20220624101901837](https://i-blog.csdnimg.cn/blog_migrate/e8b2dce2cc8f5dda9f6ee127ad4d0572.png)
- ✅ 注意:
- 有字符串的加法 ‘’ + 1,结果是 ‘1’
- 减法 只能用于数字,它会使 空字符串 ‘’ 转换为 0
- null 经过 数字转换 之后会变为 0
-
parseInt(null); // NaN parseFloat(null); // NaN Number(null); // 0
-
- undefined 经过 数字转换 之后会变成 NaN
- undefined 做任何操作都是 NaN 除了拼接字符串
null == undefined // true 值都是空 null === undefined // false 数据类型不一样
4.8.2 转字符串
- 1️⃣ String(数据)
- 返回值:转换好的数据
- 代码展示:
console.log(String(123)) // '123'
- 2️⃣ 数据.toString()
- 返回值:转换好的数据
- ❗ 注意: 需要配合变量使用 或者 使用小括号包住数字;
- 代码展示:
let num = 123 console.log(num.toString()) // '123' console.log((456).toString()); // '456'
- 3️⃣ +(加号)
- 字符串的拼接
- 代码展示:
console.log(123 + '') // '123'
![image-20220623205607781](https://i-blog.csdnimg.cn/blog_migrate/f2ff299d32cfc9be04c5a59d101c3649.png)
toString() 和 String() 使用方式不一样。
三种转换方式,我们更喜欢用第三种加号拼接字符串转换方式, 这一种方式也称之为隐式转换。
4.8.3 转布尔
- Boolean(数据)
- 返回值:转换好的数据
- ⚠ 注意:代表 空、**否定的值 **会被 转换成 false
- ‘’、 0、 NaN、 null、 undefined、 false
- 代码展示:
console.log(Boolean('')) // false console.log(Boolean(0)) // false console.log(Boolean(NaN)) // false console.log(Boolean(null)) // false console.log(Boolean(undefined)) // false console.log(Boolean(false)) // false 注意: // 两个等号值比较 值 // null 和 undefined 都是空 console.log(null == undefined) // true
五、运算符
5.1 算术运算符
![image-20220624103954490](https://i-blog.csdnimg.cn/blog_migrate/15dbaac19659fc33927213dec8771a53.png)
- ⚠ 注意:
- 取余前面的数比后面的小,余数就是前面的数
5.2 递增递减运算符
5.2.1 前置++
- 先自加,后返回值
- 先自加,后运算(++在前 先加)
let num = 10;
alert(++num + 10); // 21
5.2.2 后置++
- 先原值运算,后自加(++在后 后加)
- 先表达式返回原值,后面变量再自加1
let num = 10;
alert(10 + num++); // 20
- 注意: 前置++ 和 后置++ 单独书写没有差别
5.2.3 前置–
先自减,后运算(先已后人)
let num = 10;
alert(--num + 10); // 19
5.2.4 后置–
先原值运算,后自减(先人后己)
let num = 10;
alert(10 + num--); // 20
let a = 10;
++a; // ++a = 11 a = 11
let b = ++a + 2; // a = 12 ++a = 12
console.log(b); // 14
let c = 10;
c++; // c++ = 11 c = 11
let d = c++ + 2; // c++ = 11 c = 12
console.log(d); // 13
let e = 10;
let f = e++ + ++e;
// e++ = 10 e = 11
// e = 12 ++e = 12
console.log(f); // 22
5.3 比较运算符
![image-20220624104610215](https://i-blog.csdnimg.cn/blog_migrate/e3362664106ad03669944adc6cd386bf.png)
- 注意:
- 比较运算符有隐式转换
-
console.log(2 == '2') // true
- ⚠ 特殊说明:
- 如果是数字和“其他值”的比较,则其他值会自动转换成数字去比较
- 涉及到“NaN”都是false
- 如果是”字符串“和“字符串”比较,则会比较每一个字符的ASCII码
- 如果是布尔值参与比较,布尔值会自动转换成数字0和1
- 数字只有0是假,其余为真
- 字符串只有’'(空字符串)是假,其余都为真
5.4 ❗ 逻辑运算符
![image-20220707185825834](https://i-blog.csdnimg.cn/blog_migrate/176522d0702114ce55f39b13150de264.png)
- 1️⃣ && 与 有 一个 是 false ,得到的 结果 就是 false ;只有 两侧 都是 true 的时候,才可以到的 true
- 2️⃣ || 或 有一个 是 true ,得到的结果就是 true ;只有 两侧 都是 false 的时候,才得到 false
- 3️⃣ ! 非 取反(双取反可以转布尔)
- ⚠ 注意: 逻辑运算符 优先级: ! > && > ||
5.4.1 短路运算(逻辑中断)
- 短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
- 1️⃣ 逻辑与-语法:(一假则假)
-
表达式1 && 表达式2 如果 表达式1的值 为 真,则返回 表达式2 如果 表达式1的值 为 假,则返回 表达式1 (后面的表达式不再执行) 两侧都为真,返回第二个
-
- 2️⃣ 逻辑或-语法: (一真则真)
-
表达式1 || 表达式2 如果 表达式1的值 为 真,则返回 表达式1 (后面的表达式不再执行) 如果 表达式1的值 为 假,则返回 表达式2 两侧都为真返回第一个
-
5.5 赋值运算符
![image-20220624104834906](https://i-blog.csdnimg.cn/blog_migrate/4153a701d017c2ab1a26b87a6f8141bb.png)
5.6 ❗ 运算符优先级
- 一元运算符 里 逻辑非 优先级最高
- 逻辑与 比 逻辑或 优先级 高
-
console.log( 4 >= 6 || '人' != '阿凡达' && !(12 * 2 == 144) && true) // true let num = 10 console.log( 5 == num / 2 && (2 + 2 * num).toString() === ‘22’) // true let a = 3 > 5 && 2 < 7 && 3 == 4 console.log(a) // false let b = 3 <= 4 || 3 > 1 || 3 != 2 console.log(b) // true let c = 2 === "2" console.log(c) // false let d = !c || b && a console.log(d) // true
六、流程控制 - 分支语句
- 表达式和语句的区别:
- 表达式:表达式可被求值,可以写在赋值语句的右侧(运算符和数据组成的式子)
- 语句:不一定有值(可以被执行的代码)
6.1 if 语句
-
条件为 true 的时候,大括号里面的代码才会执行
-
小括号里的结果若不是布尔类型时,会发生隐式转换转为布尔类型
-
⚠ if分支语句,如果前面的条件被满足,后面的代码就不执行了
-
if (条件) { 满足条件要执行的代码 }
-
if (条件) { 满足条件要执行的代码 } else { 条件不满足时要执行的代码 } eg: // 能被4整除但不能被100整除,或者被400整除的年份是闰年,否则都是平年 let year = +prompt('请输入年份:') if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { alert(`&{year}是闰年`) } else { alert(`&{year}是平年`) }
-
if (条件表达式1) { 满足条件1要执行的代码 } else if (条件表达式2) { 满足条件2要执行的代码 } else if (条件表达式n) { 满足条件n要执行的代码 } else { 所有条件都不满足时要执行的代码 }
6.2 三元运算符
- 语法结构:
条件表达式 ? 表达式1 : 表达式2
- 执行思路:
- 如果 条件表达式 结果 为真,则 返回 表达式1 的值,如果 条件表达式 结果 为假,则 返回 表达式2 的值
- 代码展示:
let time = prompt('请您输入一个 0 ~ 59 之间的一个数字') // 三元表达式 表达式 ? 表达式1 :表达式2 let result = time < 10 ? '0' + time : time // 把返回值赋值给一个变量 alert(result) /* 如果输入的数字小于10,就在该数字前面加一个0,否则原样输出该数字 */ let num = prompt('请输入数字:') let result = num < 10 ? '0' + num : num alert(result)
6.3 switch 语句
- 表达式有一个返回值,**返回值 **会和 value 做匹配(必须是 全等 的关系),如果匹配上了就执行对应的语句 ,如果都匹配不上就执行default里的语句
- 语法:
switch ( 表达式 ) { case value1: 满足value1执行的代码 break case value2: 满足value2执行的代码 break default: 所有条件都不满足时要执行的代码 }
- ⚠ 注意:
- 每一个 case 和 表达式 必须是 ===(值 和 数据类型 都相等) 才叫满足
- switch 语句,只能判断一些准确的值,不能判断范围
- 实际开发过程中 表达式 我们经常 写成 变量
- 代码展示:
let num1 = +prompt('请输入第一个数字:') let sp = prompt('请输入 + - / * 其中一个:') let num2 = +prompt('请输入第二个数字:') switch (sp) { case '+': let add = num1 + num2 alert(`${num1} + ${num2} = ${add}`) break case '-': let dif = num1 - num2 alert(`${num1} - ${num2} = ${dif}`) break case '*': let bus = num1 * num2 alert(`${num1} x ${num2} = ${bus}`) break case '/': let pro = num1 / num2 alert(`${num1} ÷ ${num2} = ${pro}`) break default: alert('请输入正确的运算符') break }
七、流程控制 - 循环语句
7.1 循环成立的条件
- 初始值 作为循环的开始
- 条件判断 决定要不要继续循环
- 要重复执行的代码
- 改变初始值 为了让循环有结束
7.2 ❗ for 循环
- 语法结构:
for (初始化变量; 条件表达式; 操作表达式) { 循环体 }
- 初始化变量:通常被用于初始化一个计数器,这个变量帮我们来记录次数。
- 条件表达式:用于确定每一次循环是否能被执行。如果结果是 true 就继续循环,否则退出循环。(终止条件)
- 操作表达式:每次循环的最后都要执行的表达式。通常被用于更新或者递增计数器变量。当然,递减变量也是可以的。(递增或者递减)
- 代码展示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> </body> <script> // 求1-100之间所有数字的和 let sum = 0; let average = 0; for (let i = 1; i<= 100; i++) { sum += i } average = sum / 100; console.log('1-100之间所有数字的和为:' + average); // 求1-100之间所有偶数的和和奇数的和 let even = 0; let odd = 0; for (i = 1; i <= 100; i++) { // 第一种 if (i % 2 == 0) { even = even + i; } else { odd += i; } //第二种 if (i % 2 == 0) { even = even + i; } odd = sum - even; } console.log('1-100之间所有偶数的和为:' + even + '\n' + '1-100之间所有奇数的和为:' + odd); // 求1-100之间所有能被3整除的数字的和 let odd_num = 0; for (let i = 1; i <= 100; i++) { if (i % 3 == 0) { odd_num = odd_num + i; } } console.log('1-100之间所有能被3整除的数字的和为:' + odd_num); //弹出输入框,输入一共有n个学生,然后弹出n个输入框,输入每个学生的成绩,最后输出总成绩和平均成绩 let frequency = prompt('请输入有多少个学生:'); let score = 0; for (let i = 1; i <= frequency; i++) { let a = prompt('请输入第' + i + '个同学的成绩:'); // 从 prompt 获取到的数据是 String 类型的,不能直接和数字进行相加 score = score + parseFloat(a); } alert('该班总成绩是:' + score); alert('该班平均成绩是:' + (score / frequency)); //一行打印五个星星 let str = ' '; for (let i = 1; i <=5; i++) { str = str + '⭐'; } console.log(str); </script> </html>
![image-20220628213008738](https://i-blog.csdnimg.cn/blog_migrate/fbf3b610978bb18f15dc351fb4d1908f.png)
7.3 ❗ 双重for循环
-
//打印n行m列的星星 let rows = +prompt('请输入需要打印几行的星星:'); let cols = +prompt('请输入需要打印几列的星星:'); let str = ''; for (let i = 1; i <=rows; i++) { for (let j = 1; j <= cols; j++) { str += '⭐'; } str += '\n'; } console.log(str);
![image-20220630110759649](https://i-blog.csdnimg.cn/blog_migrate/16d104d8a6dffa67161a06be34ca41b0.png)
- 冒泡排序:
// 外层for循环:控制已经排序好的元素的个数 // 内层for循环:控制每排序好一个元素需要比较几次 const arr = [1, 7, 3, 9, 5, 2, 6, 4, 8]; for (let i = 0; i < arr.length - 1; i++) { for (let j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { let temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } console.log(arr);
7.4 while循环
- 循环三要素:
- 变量初始值
- 终止条件
- 变量变化量
- 语法:
let n = 1 while ( 循环条件 ) { 重复执行的代码 n++ }
7.5 ❗ continue 和 break
- continue:
- 退出本次循环,继续下一次循环
- 一般用于排除或者跳过某一个选项的时候
- continue 在循环节构中用来跳过本次循环中剩余的代码,并且在条件求值为真的时开始下一次循环。
- 不能省略 continue 后面的分号(导致胡乱)
- continue 后面 的 代码 不会 再 执行
- break:
- 退出整个循环(结束循环)
- 一般用于结果已经得到,后续的循环不需要的时候
- 在一些计算机语言中 break 是保留字,其作用大多数情况下是终止上一层循环。
八、❗❗ 数组 - 基础
- 一种 有序 的数据集合
8.1 创建数组
8.1.1 字面量创建
let 数组名 = [数据1, 数据2, …, 数据n]
let arr = ['name', 'Jack', 'age', 20, 'gender', '男']
8.1.2 内置构造函数创建
//没有参数表示空数组
let arr = new Array()
//一个参数表示数组的长度
let arr = new Array(100)
//多个参数表示都是数组里面的数据,没有表示长度的参数
let arr = new Array(10, 20, 30)
arr.length = 2 //删除最后一个
arr.length = 5 //后面的两个用空补齐
console.log(arr[2]) //读取里面的额第三个数据
8.2 ❗❗ 遍历数组
能够获取数组里面的每个元素
8.2.1 for
- 格式:
for (let i = 0; i < 数组名.length; i++) { // 执行的操作 // console.log(数组名[i]) }
8.2.2 forEach
- 取代 for 循环
- 语法:
数组.forEach(function (item, index, arr) { } ) -> item :数组里面的每一项 -> index :数组里面每一项的索引 -> arr : 原始数组
- ❗ 没有 返回值
- forEach中的 return 等同于 for循环的 continue
- 终止forEach循环:try - catch
try { [1, 2, 0, 3].forEach(item => { console.log(item) if (item === 1) { console.log(item) throw Error() } }) } catch (error) { console.log('终止循环') } // 打印结果 // 1 // 1 // z
8.2.3 for of
- 遍历 可迭代 的数据:数组,伪数组,字符串
- 遍历的是数组、伪数组、字符串的值
- 语法:
for (let item of arr) { console.log(item) // item -> 数据里面的每一项 }
8.3 数组的增删查改
8.3.1 增
- 1️⃣✔数组.push() 方法:将 一个或多个元素 追加 到 数组 的 末尾 ,并 返回 追加元素后数组 的 长度
- 语法:数组.push(数据1, 数据2, … ,数据n)
- 返回值: 追加元素后数组的长度
- ⚠改变原始数组
- 2️⃣ 数组.unshift() 方法:将 一个或多个元素 插入 到 数组 的 开头,并 返回 插入元素后数组 的 长度
- 语法:数组.unshift(数据1, 数据2, …, 数据n)
- 返回值: 插入元素后数组的长度
- ⚠改变原始数组
- 见代码展示
8.3.2 删
- 1️⃣ 数组.pop() 方法:从数组中 删除 最后一个 元素
- 语法:数组.pop()
- 返回值: 被删除的元素
- ⚠改变原始数组
- 2️⃣ 数组.shift() 方法:从数组中 删除 第一个元素
- 语法:数组.shift()
- 返回值: 被删除的元素
- ⚠改变原始数组
- 3️⃣ ✔数组.splice(start, deleteCount) 方法:删除 数组 里 指定的元素
- 语法:数组.splice(开始索引,删除几个)
- ⚠🔺 注意:包含开始索引 对应 的 元素
- deleteCount:表示要移除的数组元素的个数(如果 省略 则 默认 从 指定的起始位置 删除到最后)
- 返回值: 新数组(将删除的元素放到这个新数组里面)
- ⚠改变原始数组
- 语法:数组.splice(开始索引,删除几个)
- 见代码展示
8.3.3 查
- 见代码展示
8.3.4 改
- 见代码展示
8.3.5 代码展示
<script>
let arr = ['pink', 'red'];
// 增加
// 方案一:数组.push()方法
语法:arr.push(元素1, 元素2, …, 元素n);
追加数组 的同时 有一个 返回值 是 追加以后 的 数组长度
console.log(arr.push('green', 'hotpink', 'deeppink')); // 5
console.log(arr);
// ['pink', 'red', 'green', 'hotpink', 'deeppink']
// 方案二:数组.unshift()方法
语法:arr.unshift(元素1, 元素2, …, 元素n);
console.log(arr.push('green', 'hotpink', 'deeppink')); // 5
console.log(arr);
// ['green', 'hotpink', 'deeppink', 'pink', 'red']
// 删除
// 方案一:数组.pop()
console.log(arr.pop()); // green
// 方案二:数组.shift()
console.log(arr.shift()); // red
// 方案三:数组.splice(起始位置的索引, 删除几个元素)
// 从索引号0的位置开始,删除两个元素
console.log(arr.splice(0, 2)); // ['hotpink', 'deeppink']
// 查询 --- 利用数组的索引进行查找
console.log(arr[0]); // pink
// 修改 --- 利用 对数组进行遍历,然后和字符串拼接,重新赋值给数组里的元素
// 方案一:
arr[0] = 'blue';
arr[1] = 'purple';
//方案二:
for (let i = 0; i < arr.length; i++) {
arr[i] += '老师';
}
console.log(arr)
</script>
九、❗❗ 函数
- 函数:执行特定任务的代码块
9.1 函数的声明和使用
9.1.1 函数的声明
- 函数命名规范:
- 和变量命名基本一致
- 小驼峰式命名法
- ⚠ 前缀应该为动词
-
can --- 判断是否可执行某个动作 has --- 判断是否含义有某个值 is --- 判断是否为某个值 get --- 获取某个值 set --- 设置某个值 load --- 加载某些数据
-
- 1️⃣ 具名函数
- 语法:
function 函数名() { 函数体 }
- ⚠ 注意:可以 后声明先调用 ,也可以 先声明后调用
- 语法:
- 2️⃣ 匿名函数
- 使用方式:
- ① 函数表达式:
- 语法:
let 函数名 = function () { // 函数体 }
- 语法:
- ② 立即执行函数:
- 语法:
!(function (实参) { 函数体 })(实参); !(function (实参) { 函数体 } (实参));
- ⚠ 注意: 立即执行函数 末尾 必须加 分号
- 语法:
- ① 函数表达式:
- ⚠ 注意:
- 函数名() — 表示调用这个函数
- 函数名 — 表示一个变量,代表这个函数
- 使用方式:
- 代码展示:
function getSum() { let sum = 0 for (let i = 1; i <= 100; i++) { sum += sum } document.write(sum) }
9.1.2 函数的使用
- 函数的调用:
-
函数名()
-
- ⚠ 注意: 声明的函数 必须 调用 才会真正执行,使用 () 调用函数
- 函数 一次声明 可以 多次调用 ,每一次函数调用函数体里面的代码会重新执行一次
- 代码展示:
function getSum() { let sum = 0 for (let i = 1; i <= 100; i++) { sum += sum } document.write(sum) } getSum() // sum = 5050
- 代码展示:
9.1.3 函数传参
- 声明语法:
-
function 函数名(参数列表) { 函数体 }
- 传入数据列表
- 声明这个函数需要传入几个数据
- 多个参数之间用 逗号 隔开
- 代码展示:
function getSum(start, end) { // 形参 - 形式上的参数 let sum = 0 for (let i = start; i <= end; i++) { sum += sum } document.write(sum) }
-
- 调用语法:
-
函数名(传递的参数列表)
- 代码展示:
getSum(10, 20) // sum = 33 // 实参 - 实际的参数
- 形参:
- 形式上的参数 — 写在 函数声明阶段 的 小括号 里
- 本质:就是在函数内部声明的变量(局部变量)
- 作用:接受实参传递的参数
- 如果既没有实参传递,也没有设置默认值,就是 undefined
- 实参:
- 实际上的参数 — 写在 **函数调用阶段 **的 **小括号 **里
- 实参 可以是 变量
- 作用:给形参赋值
-
- 参数默认值:
- 在调用的过程中,如果有参数传递过来,就用传递过来的;如果没有参数传递过来就用默认的
- ⚠ **注意:**若没设置默认值,默认就是 undefined
- 代码展示:
function getSum(x = 0, y = 0) { // 小括号里写了就不用写 // 推荐用逻辑中断 // x = x || 0 // y = y || 0 document.write(x + y) } getSum() // 0 getSum(1, 2) // 3
9.1.4 函数的返回值:
- 语法:返回给调用者(当调用某个函数,这个函数会返回一个结果出来)
return 要返回的数据
- ⚠ 注意:
- 在 函数体 中使用 return 关键字能 将内部的执行结果 交给 函数外部 使用
- 所以 return 后面的数据不要换行写
- ⚠ return 和 要返回的数据不能换行写(模板字符串、函数除外)
- 一个函数只能有一个return(因为第一个return后面的代码就不执行了)
- 如果 函数 没有指定 return,这种情况函数 默认返回值 为 undefined
- 函数如果有 多个返回值 ,用 中括号包裹,中间 用 逗号隔开 (返回的是一个新数组)
- 代码展示:
-
function fn() { return 20 // 把 结果(20) 返回给 fn } fn() // 相当于执行了 fn() = 20 (fn()是函数的调用者) console.log(fn()) // 20 // 求两个数的最大值 function getMax(x = 0, y = 0) { return x > y ? x : y } getMax(65, 99) // 99 let max = getMax(65, 99) console.log(max)
- 求数组里面的最大值和最小值
- 代码展示:
// 声明一个 getArrValue函数 function getArrValue(arr = []) { let max = arr[0] let min = arr[0] //遍历数组 for (let i = 0; i < arr.length; i++) { // 最大值 if (max < arr[i]) { max = arr[i] } // 最小值 if (min > arr[i]) { min = arr[i] } } // return 返回多个值写法 return [max, min] } let newArrr = getArrValue([23, 56, 32, 198, 0, 5, -98]) console.log(`数组中的最大值是:&{newArr[0]}`) // 198 console.log(`数组中的最小值是:&{newArr[1]}`) // -98
- 时间转换 + 补0
- 代码展示:
function getTime(t = 0) { let second = parseInt(t % 60) let minute = parseInt(t / 60 % 60) let hour = parseInt(t / 60 / 60 % 24) // if条件分支语句 /* if (second < 10) { second = '0' + second } if (minute < 10) { minute = '0' + minute } if (hour < 10) { hour = '0' + hour } */ // 三元表达式 second < 10 ? second = '0' + second : second minute < 10 ? minute = '0' + minute : minute hour < 10 ? hour = '0' + hour : hour return `${t}秒 = ${hour}小时${minute}分钟${second}秒` } let str = getTime(+prompt('请输入秒数:')) // 1000 document.write(str) // 1000秒 = 00小时16分钟40秒
-
- ⚠ 函数注意点:
- 两个函数名相同的函数,后面的会覆盖前面的
- 两个函数体相同的匿名函数不是同一个函数
- 传递参数
- 形参过多会自动填上 undefined
- 实参多于形参,剩余的实参不参与运算
- 实参少于形参,多于的形参使用默认值 undefined
- 函数一旦碰到 return 就不会往下执行,函数的结束用 return
- break 和 return 的区别:
- break:结束 的是 循环 和 switch
- return:结束 的是 函数 和 for循环
9.2 作用域基础
作用域: 变量的 可用性范围 就是 作用域 (提高程序逻辑的局部性)
9.2.1 全局作用域
- 全局有效
- 作用与所有代码执行的环境(整个script标签内部)或者一个独立的js文件
9.2.2 局部作用域
- 局部有效
- 作用与函数内的 代码环境,就是局部作用域。因为跟函数有关,所以也称为函数作用域
9.2.3 特殊
- 如果函数内部,变量没有声明,直接赋值。也当全局变量看。不推荐
- 代码展示:
function fn() { num = 10 // 全局变量来看 } fn() console.log(num) // 10
- 代码展示:
- 函数内部的 形参 可以看作是 局部变量
- 代码展示:
function fun(x, y) { // 形参可以看做是函数的局部变量 console.log(x) // 1 } fun(1, 2) console.log(x) // x is not defined (报错)
- 代码展示:
9.3 变量的访问原则
- 只要是代码,就至少有一个作用域
- 写在函数内部的局部作用域
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
- ⚠ 访问原则(就近原则):在能够访问到到的情况下 先局部,局部没有 再找全局 (由内向外)
-
代码展示:
functin f1 () { let num = 123 function f2 () { console.log(num) // 123 } f2() } let num = 456 f1()
function f1() { let num = 123 function f2() { let num = 0 console.log(num) // 0 } f2() } let num = 456 f1()
let a = 1 function fn1() { let a = 2 let b = '22' function fn2() { let a = 3 fn3() function f3() { let a = 4 console.log(a) // a的值 = 4 console.log(b) // b的值 = '22' } } } fn1()
-
9.4 匿名函数
- 没有名字的函数,无法直接使用
- 使用方式: 函数表达式 / 立即执行函数
- 1️⃣ 函数表达式:
- 函数表达式:将匿名函数赋值给一个变量,并且通过变量名称进行调用
- 语法:
let 变量名 = function () { // 函数体 }
- ⚠ 调用:变量名()
- 代码展示:
let fn = function () { console.log('我是函数表达式') } fn() // 我是函数表达式
- ⚠🔺 注意: 函数表达式 必须 先 声明 、后 调用
- 因为变量必须先声明后使用
- 2️⃣ 🔻**立即执行函数:**避免全局变量的污染(防止变量污染(冲突))
- 函数声明后立即执行,并且执行完一次后被释放
- 语法:
// 写法一: (函数)(); // 写法二: (函数 ());
- ⚠ 立即执行函数 必须 加 分号
- 立即执行函数可以传递参数
- 先写两个小括号,前面的小括号写函数
- 可以给匿名函数添加函数名
- ⚠ 最后面的小括号相当于调用函数
- 代码展示:
(function () { console.log('立即执行函数') })(); // 保存之后会在控制台立即打印 '立即执行函数'
// 第一种写法: (function () { console.log('立即执行函数第一种写法'); })(); (function (x, y) { // (x, y) ---> 形参 console.log(x, y); // x = 5; y = 9 })(5, 9); // (5, 9) ---> 实参 // 第二种写法: (function () { console.log('立即执行函数第二种写法'); } ()); (function (x, y) { // (x, y) ---> 形参 console.log(x, y); // x = 5, y = 9 } (5, 9)); // (5, 9) ---> 实参
- 代码展示:
- 1️⃣ 函数表达式:
9.5 具名函数 和 匿名函数 的区别
- 具名函数:
- 可以 先调用 后声明,也可以 先声明 后调用
- 具名函数 的 调用 可以 写在 任意位置
- 匿名函数
- 函数表达式必须 先声明函数表达式 后调用
- 匿名函数 的 调用 必须写在 声明函数 的 后面
9.6 函数中的逻辑中断
- 函数的默认值
- 方案一:(赋值)
function fn(x = 0, y = 0) { x = x y = y console.log(x, y) } fn(1, 2) // x = 1, y = 2 fn() // x = 0, y = 0
- 方案二:(逻辑中断)(推荐)
function fn(x, y) { x = x || 0 y = y || 0 console.log(x, y) } fn(1, 2) // x = 1, y = 2 fn() // x = 0, y = 0
- 方案一:(赋值)
十、❗❗ 对象 - 基础
- 对象 = 属性 + 方法
10.1 对象 - object
- 对象是一种复杂数据类型
- 一种 无序 的数据集合(不可迭代)
10.2 声明对象
- 语法:
- let 对象名 = {}
- let 对象名 = new Object()
let obj = {} // 声明了一个obj的对象 let obj = new Object();
- 组成:属性 + 方法
let 对象名 = { 属性名: 属性值, 方法名: 函数 } eg: let obj = { uname: 'pink老师', age : 18, gender: '男' } console.log(obj) // {uname: 'pink老师', age: 18, gender: '男'}
- 属性都是 成对 出现的,包括 属性名 和 属性值 ,它们之间使用英文 : 分隔
- 对象属性没有顺序
- 多个属性之间使用英文 , 分隔
- 属性就是依附在对象上的变量(外面 是 变量,对象内 是 属性)
- ⚠ 属性名可以使用 " " 或 ’ ’ ,一般情况下省略,除非名称遇到特殊符号如 空格 、 中划线 等
- ⚠ 属性名 不能 使用 反引号
10.3 增删查改
- 1️⃣查
- 语法:
- 对象名.属性名
- 对象名[‘属性名’] (🔺 属性名 必须 加 引号)
- ⚠ 如果属性名存放在一个 变量 里面,只能使用 数组关联语法
- 代码展示:
console.log(obj.uname) // pink老师 console.log(obj['uname']) // pink老师
- 语法:
- 2️⃣改
- 语法:对象名.属性名 = 新值
- 代码展示:
obj.gender = '女' console.log(obj.gender) // 女
- 3️⃣增
- 语法:对象名.新属性名 = 新值
obj.address = '武汉黑马' console.log(obj) // {uname: 'pink老师', age: 18, gender: '女', address: '武汉黑马'} console.log(obj.address) // 武汉黑马
- 语法:对象名.新属性名 = 新值
- 4️⃣删(了解)
- 语法:delete 对象名.属性名
delete obj.address console.log(obj) // {uname: 'pink老师', age: 18, gender: '女'}
- 语法:delete 对象名.属性名
10.4 对象的方法
- 方法 = 方法名 + 函数,它们之间用 : 分隔
- 多个属性 之间 使用英文 , 分隔
- 方法是依附在对象中的函数(外面 是 函数,对象内 是 方法)
- 方法名可以使用 “” 或 ‘’ ,一般情况下省略,除非遇到特殊符号如 空格、中划线 等
- 声明对象,并添加了若干方法后,可以使用,调用 对象 中的 (方法)函数,我们称之为方法调用
- 语法:对象名.方法名()
- 千万别忘了给方法名后面加 小括号
- 代码展示:
let obj = { uname: '刘德华', // 方法 song: function () { console.log('冰雨') }, getSum: function (x, y ) { x = x || 0 y = y || 0 console.log(x + y) } } // 方法调用 对象名.方法名() obj.song() // 冰雨 obj.getSum(2, 5) // 7
10.5 ❗ 遍历对象
- 1️⃣ for in 语法:
- 遍历的是 对象的属性 / 数组的索引 / 伪数组的索引 / 字符串的索引
- 得到的索引都是字符串型
for (let k in obj) { console.log(obj[k]) }
- 结论: k 是获得 对象 的属性名 , 对象名[k] 是获得 对象 的 属性值
- 遍历的是 对象的属性 / 数组的索引 / 伪数组的索引 / 字符串的索引
- 2️⃣ 判断一个成员在不在对象里面
- 语法:
属性/方法 in 对象名
- 返回值: 布尔值 (true / false)
- 代码展示:
let obj = { uname: 'jack', age: 18, gender: '男', score: 100 }; console.log('name' in obj); // true
- 语法:
- 代码展示:
//声明一个 obj 对象 let obj = { uname: 'pink老师', age: 18, gender: '男' } // 用 fou in 循环遍历对象 for (let k in obj) { // k 可以是任何变量,选择 k/key 是因为许多程序员都在使用 // console.log(k) // k 是字符串型的,带有引号 // k => 'uname' 'age' 'gender' // obj 对象里面没有 'uname'、 'age'、 'gender' 的属性名 ------ 有引号 // obj 对象里面的属性名是 uname、 age、 gender ------ 没有引号 // 查询对象里面的属性有两种方法:1)对象名.属性名 // 2)对象名['属性名'] // 原因:obj[k] === obj['uname'] === obj.uname // obj[k] === obj['age'] === obj.age // obj[k] === obj['gender'] === obj.gender // 所以,利用for in循环遍历对象采用第二种查询方法 // 结论:k 是获得对象的属性名 , 对象名[k] 是获得 属性值 console.log(obj[k]) // 'pink老师'(string) 18(number) '男'(string) }
- 渲染学生信息
- 代码展示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> table { width: 600px; text-align: center; } table, th, td { border: 1px solid #ccc; border-collapse: collapse; } caption { font-size: 18px; margin-bottom: 10px; font-weight: 700; } tr { height: 40px; cursor: pointer; } table tr:nth-child(1) { background-color: #ddd; } table tr:not(:first-child):hover { background-color: #eee; } </style> </head> <body> <h2>学生信息</h2> <p>将数据渲染到页面中...</p> <table> <caption>学生列表</caption> <tr> <th>序号</th> <th>姓名</th> <th>年龄</th> <th>性别</th> <th>家乡</th> </tr> <script> // 1.数据准备 let students = [ { name: '小明', age: 18, gender: '男', hometown: '河北省' }, { name: '小红', age: 19, gender: '女', hometown: '河南省' }, { name: '小刚', age: 17, gender: '男', hometown: '山西省' }, { name: '小丽', age: 18, gender: '女', hometown: '山东省' } ] // 2.开始渲染页面 for (let i = 0; i < students.length; i++) { document.write(` <tr> <td>${i + 1}</td> <td>${students[i].name}</td> <td>${students[i].age}</td> <td>${students[i].gender}</td> <td>${students[i].hometown}</td> </tr> `) } </script> </table> </body> </html>
- 代码展示:
十一、内置对象 - Math
11.1 Math.random()
- Math.random():生成0-1之间的随机小数(🔺包含0不包括1);
- 如何生成0-10的随机小数?
let num = Math.floor(Math.random() * (10 + 1))
- 如何生成5-10的随机数?
let num = Math.floor((Math.random() * (5 + 1)) + 5
- 如何生成N~M的随机数?
let num = Math.floor(Math.random() * (M - N + 1)) + N function getRandom (N, M) { // return Math.floor(Math.random() * (M - N + 1)) + N; return parseInt(Math.random() * (M - N + 1)) + N; }
- 数组随机数:
Math.floor(Math.random() * arr.length)
11.2 Math.ceil()
- Math.ceil(数据):向上取整;
- 代码展示:
console.log(Math.ceil(1.1)) // 2 console.log(Math.ceil(1.01)) // 2
11.3 Math.floor()
- Math.floor(数据):向下取整;
- 代码展示:
console.log(Math.floor(1.9)) // 1 console.log(Math.floor(1.99)) // 1
11.4 Math.max()
- Math.max(数据):找最大数;
- 代码展示:
console.log(Math.max(0.1, 1, 65, 23, 88)) // 88
11.5 Math.min()
- Math.min(数据):找最小数;
- 代码展示:
console.log(Math.min(99, 65, 3, 0.1, -99)) // -99
11.6 Math.pow()
- Math.pow(a, b)【a 的 b 次方】;
- 代码展示:
Math.pow(2, 3); // 8 Math.pow(25, 2); // 625
11.7 Math.abs()
- Math.abs(数据):绝对值;
- 代码展示:
console.log(Math.abs(-100)) // 100
11.8 Math.round()
- Math.round(数据):四舍五入(取整数);
- 代码展示:
console.log(Math.round(2.45)) // 2 console.log(Math.round(2.5)) // 3 console.log(Math.round(-20.5)) // -20 console.log(Math.round(-20.51)) // -21