第一部分
1. JavaScript 介绍
- JavaScript 又简称为
JS
,是一门脚本语言,可以让网页具备“思考”能力 - JavaScript作者: 布兰登·艾奇
- JavaScript 组成
- ECMAScript:
- 简称ES、ES5、ES6
- JavaScript的语法规范
- DOM:
- 文档对象模型
- 操作页面内容
- BOM
- 浏览器对象模型
- 操作浏览器功能
- ECMAScript:
2. JavaScript 基础写法
2.1 JavaScript 的三种书写方式
-
内联:
- script标签
- JS代码写在这个标签理念
- 小规范:script标签写在body结束的位置
-
外联(链)
- js独立出来的文件是以
.js
后缀结尾 script
配合src
属性导入- src里写js文件的路径
- 注意:如果写了外联,那么在
script
标签里,就不要写其他JS代码,因为写了也没用
- js独立出来的文件是以
-
行内(了解)
<button onclick="alert('Vinson')">点我,告诉你最帅的男人</button>
2.2 JavaScript 的注释
- // :
- 单行注释,也就是//后面的一行内容会被浏览器忽略不执行,可以嵌套
- 快捷键:ctrl + /
- /* */: 多行注释,不能嵌套(会报错)
- 快捷键:shift + alt + a
2.3 JavaScript 输入和输出语句
- alert(‘想提示的内容’)
- 弹出一个提示框
- prompt(‘提示用户输入什么’)
- 弹出一个输入框,可以进行输入
- confirm(‘提示用户的内容’)
- 用的极少
- 弹出的是一个确认框,只能点确定或取消
2.4 JavaScript 结束符说明
- 结束符的符号是:
;
- 英文分号
- 可以写也可以不写
- 除非你需要把它们都写在同一行,那么就要加
分号
, 也可以逗号
,空格不可以,要报错 - 建议如果你要写,就每句都写,如果你不写,就每句都不写,这样可以保证你的编码风格是统一的
- 我这里是:不写分号,因为后面vue的标准语法规范不推荐加分号
3. 变量声明、赋值、使用
-
什么是变量?
- 可以理解为一个容器
- 装数据的容器
-
变量的声明
let 变量名 // 例 let name // 创建了一个叫name的变量(盒子)
-
变量的赋值
变量名 = 数据 // 例 name = 'Vinson'
-
变量的使用(取值)
// 直接写变量名 name alert(name) // 取出name的值再提示出来 alert('name') // 就是提示name
- 注意:写变量的时候不要打引号,打引号就不是取出变量的值了,就只是提示这个东西
-
注意:
- 声明变量时我们用
let
,也可以用var
- 目前而言没区别,区别在JS高级的时候会讲
- let是ES6出来的(更推荐使用的),var是ES5就有的(不推荐了)
- 声明变量时我们用
-
变量的初始化:
-
在声明变量时就赋值
let name = 'Vinson' // 或者也可以让用户输入 let name = prompt('请输入姓名')
-
-
变量的本质:就是在内存中开辟一个空间,在空间里放数据
4. 变量的细节补充
-
同时声明多个变量并赋值
- 用逗号隔开
let name = 'jack',age = 16
-
如果变量只声明不赋值,那么值是undefined
let name alert(name) // undefined let name, age = 16 // 相当于写的是 let name let age = 16 alert(name) // undefined alert(age) // 16
-
变量的值也可以重新赋值
let name = '刘德华' alert(name) // 刘德华 name = '周星驰' alert(name) // 周星驰
-
如果一个变量不声明也不赋值,不能用,会报错
// 变量没声明没赋值不能用,会报错 alert(age)
-
如果一个变量不声明,但是直接复制了,可以用,但是不推荐
// 变量没声明,但是直接赋值,可以用,不推荐这样写 age = 30 alert(age)
5. 变量案例: 交换两个变量的值
-
使用一个第三方变量来保存
let name1 = '枸杞' let name2 = '水蜜桃' let temp = name1 name1 = name2 name2 = temp
6. 变量命名规则与规范
-
规则:
- 必须要遵守,不遵守就会报错,导致程序无法往下执行
- 相当于是现实中的法律,不遵守就没自由无法正常生活
-
规范:
- 建议遵守的行为,不遵守也不会报错,会显得不专业
-
规则:
- 不能用关键字
- 关键字:在js中又特殊含义的字符,例如:let、var
- 关键字不用特意去记,写着写着就知道有哪些了
- 变量名只能是由字母、数字、下划线、美元符号($) 组成,而且数字不能开头
- 不能用关键字
-
规范:
- 起名要有意义,变量的名字跟保存的数据有关
- 例:要保存名字,建议变量名叫name 要保存年龄,建议变量名叫 age,要保存金额用money等
- 而且尽量是英文单词,不会的单词查词典
- 不好的例子:mmd、bbd,尽量不要用拼音缩写
- 要用驼峰命名法
- 如果一个变量名由多个单词组成吗,那么第一个单词首字母小写,后面每个单词首字母大写
- 例:userName、 userLoginName
- 起名要有意义,变量的名字跟保存的数据有关
7. 数据类型
对数据进行分类
7.1 数据类型介绍
-
Number:
- 数值型(数字型),参与数学运算做数字的标识
- 写法:直接写数字,例如:10,11,12, 10.32, 11.2, -0.3
-
String:
-
字符串型,用来表示文字的
-
写法:
-
用单引号或双引号或反引号包起来的都是字符串
-
建议用单引号(1.敲出来轻松 2.可以跟html做区分 3.因为标准语法规范建议用单引号)
-
例:
'hello'、 "hello"、 `hello` (1左边的那个键)
-
-
-
Boolean:
- 布尔类型,用来表示两种对立的状态:真与假、对与错、开与关
- 这种类型只有两个数据: true 与 false
- 如果是直接写 true 、false都是布尔类型
-
undefined:
- 代表未定义
- 只有一个值就叫undefined
-
如果写了一段字符,不符合任意数据类型的写法, 他就找变量,如果找到取出变量的值,找不到就报错
-
JS是弱类型的语言:变量的类型没有限制死,可以随时改成别的类型
-
是根据赋值时,右边的值是什么就确定是什么类型
-
所以如果一个变量只声明没赋值是undefined,因为没法确定是什么类型,所以就未定义
7.2 console.log 以及不同数据类型输出特征
-
它主要是给程序员自己调试数据用的
-
在浏览器的f12 -> Console 来显示
console.log(直接写数据) 或者 console.log(变量名)
-
在控制台中,如果数据是字符串,则颜色为黑色
7.3 typeof 检测数据类型
-
作用:检测数据类型是什么
-
用法:
typeof 数据 typeof 变量名
8. 算术运算符
- +:
- 一般情况下都是把两个数字相加
- 如果+两边有一个是字符串,那么都是拼接产生一个新的字符串
-
- 相减
-
- 相乘
- /
- 相除
- %
- 取余数
- 优先级:先乘除后加减,有括号的先算括号里面的,同级就从左往右依次运算
9. 拼接字符串
- 用 + 号可以对两边有任意一个是字符串的数据进行拼接得到新字符串
- 如果要拼接的内容很多,可以先写一个字符串,发现有些内容不能写死,则删掉这个内容,打’’ 再++,再++中间写变量名
- 口诀:引引++
10. document.write
-
给 body 内增加内容
-
如果内容带标签,会解析成html元素
document.write('<h3>哈哈哈,我出现了</h3>')
11. 转义符
- 符号:\ 可以把右边的符号转换原来的意义
- 有:
\n
: 换行\'
: 输出单引号\"
: 输出双引号\\
: 输出\- …
12. 模板字符串
- 符号:`` (反引号)
- 好处:
- 内容怎么写的,它就是怎么展示的
- 如果想输出变量的值,不用再拼接字符串,写${变量名} 自动填充在里面
第二部分
1. 类型转换
把一种数据类型转换为另外一种数据类型
1.2 隐式转换
- 不用额外写代码、程序自己根据一定的规则来转换成某种类型
+
两边如果有一个是字符串,会把另外一个非字符串的也自动转换成字符串- 除了
+
以外的所有算术运算符(-、*、/、%) 都会把别的类型转换成数字类型,如果无法得到数字的,会得到NaN - NaN:Not a Number 代表非数字,它也是number类型(数字类型)
- 它做任意数学运算得到的结果也一定是NaN
- 只要是数学运算都是转换成数字,但是如果是拼接就是转换成字符串
- 缺点:需要记住这些规则,不太明显,增加了代码阅读难度
1.2 显式转换
-
自己写代码强制告诉数据转成什么类型
-
转换成字符串:
- String(数据)
- 数据.toString()
- toString最好用在变量,否则可能会报错
-
转换成数字类型
-
Number(数据)
- 只要有一个是非数字,得到的都是NaN,两边有空格无所谓,中间有就不行
- 整数小数都能转换
-
parseInt(数据)
- 转换成整数,只会得到整数部分
- 从左往右依次转换,遇到非数字就立刻停止,有几个数字就转换几个,一个没有得到NaN
-
parseFloat(数据)
- 转换成整数或小数(数字是什么就得到什么)
- 原理效果跟parseInt一样的,也是从左往右依次转换
-
快速转:
- 直接在数据前面写+
-
利用隐式转换快速砖
- 数据 - 0 或 数据 * 1 或者 数据 / 1
-
补充:
- 0不能作为除数,就是 / 右边的数,其他语言里会报错,JS里得到Infinity
- Infinity代表无穷大,-Infinity代表无穷小
-
2. 自增和自减
-
自增:
- 符号:++
- 就是让自己 +1
-
自减:
- 符号:–
- 就是让自己-1
-
如果不参与运算,++(–)写在前或者写在后都一样
-
如果参与运算前缀和后缀就有区别:
- 前缀:先自增(自减),再用自增(自减)后的值参与运算
- 后缀:先用原值参与运算,再自增(自减)
3. 比较运算符
>
:判断左边是否大于右边
<
:判断左边是否小于右边
>=
:判断左边是否大于或等于右边
<=
:判断左边是否小于或等于右边
==
:判断左右两边是否相等,只判断值相等,不判断类型
===
:判断左右两边是否全等,既要值相等,也要类型相等
!=
:判断左右两边是否不等
- 得到的结果是布尔类型,也就是得到true或false
- 一定要区分:赋值就是一个
=
不要写成==
,除非你要判断值是否相等才写成==
4. 逻辑运算符
- &&:逻辑与
- 左右两边都是true,结果才是true,有一个是false结果就是false
- 口诀:一假则假
- ||:逻辑或
- 左右两边有一个是true结果就是true,两个是false结果才是false
- 口诀:一真则真
- !:逻辑非
- true变false,false变true
- 真变假,假变真
- 它还有把别的数据类型转成布尔类型的特点
- 转换成布尔类型
- Boolean(数据)
- 只有0、空字符串、NaN、undefined、null转成false,其他都是true
- 逻辑运算符中的短路:
- 指的不执行右边的式子
- 只存在于 && 和 || 中有短路
- 当左边能确定整个式子结果,就没必要看右边了,所以发生了短路的现象(不执行右边的式子)
- &&什么时候短路:在左边式子为false时短路
- || 什么时候短路: 在左边式子为true的时候短路
- 逻辑运算式的运算结果
- 如果有短路,则运算结果就是左边式子的结果
- 如果无短路,则运算结果就是右边式子的结果
5. 赋值运算符
- 符号:
=
- 代表把右边的值赋值给左边变量
- 他不是判断相等,判断相等是
==
+=
- 在自己值的基础上再+一个值
-=
- 在自己值的基础上再-一个值
*=
- 在自己值的基础上再*一个值
/=
- 在自己值的基础上再/一个值
%=
- 在自己值的基础上再%一个值
6. 运算符优先级
let a = 3 > 5 && 2 < 7 && 3 == 4
console.log(a)
let b = 3 <= 4 || 3 > 1 || 3 != 2
console.log(b)
let c = 2 === "2";
console.log(c)
let d = !c || b && a ;
console.log(d)
7. 程序的三种结构
- 顺序结构:
- 程序从上往下依次执行
- 程序默认就是顺序结构
- 分支结构
- 循环结构:
8. 分支语句之if
-
语法
if (条件) { 代码 }
- 当 if 小括号里的 条件 为 true 时,则执行大括号里的代码,如果为false就不执行大括号里的代码
if (true) { alert('我被执行了') }
-
例
// 模拟进网吧 alert('我要去网吧了~咿呀咿呀哟') // 网管要问你多大了 let age = prompt('你今年多大了?') // 判断是否大于或等于18 if (age >= 18) { // 如果 年龄 大于或等于 18 // 就上网 alert('我要去浪漫的网吧偷耳机') } alert('回家了')
9.分支语句之if-else
-
语法
if (条件) { 代码1 } else { 代码2 }
- 如果条件满足,执行代码1,不满足就执行代码2
- 所以也就是说代码1和代码2,只会选择一个来执行
-
这也可以称之为
双分支
语句
10. 三元表达式
-
由三元运算符组成的式子叫三元表达式
-
三元运算符符号:?:
-
语法:
条件 ? 代码1 : 代码2
- 条件为true执行代码1,拿到代码1的结果
- 条件为false执行代码2,拿到代码2的结果
11. 分支语句之if - else if - else
-
语法
if (条件1) { 代码1 }else if (条件2) { 代码2 }else if (条件3) { 代码3 } ....... (可以写n多个else if) else { 代码n }
- 先判断条件1,如果为true则执行代码1,如果为false则继续往下判断条件2,为true则执行代码2,为false则继续往下判断条件3,为true执行代码3,以此类推,如果上面条件都不满足就只执行else里的代码n
/* 花花有多少钱 如果是1万以上,全体去大保健 如果是5000 - 1万,那么去洗个脚 如果是2000 - 5000,那么就请大家去吃个饭 如果是1000 - 2000,那么就一人一杯奶茶 如果是1000以下,那么就暴打花花一顿,然后叫他回去再拿钱 */ let money = 800 if (money >= 10000) { alert('花花说:学习累了,大伙去按个摩我请客') }else if (money >= 5000) { alert('花花说:读万卷书,行万里路,所以我们先去洗个脚,我请客') }else if (money >= 2000) { alert('花花说:肚子饿了,大家去吃个饭,我请客') }else if (money >= 1000) { alert('花花说:我给大家点了奶茶,大家来拿一下') }else { alert('大伙说:你大爷的!!(噼里啪啦一顿打),快回去拿钱!') }
12. 分支语句之switch
-
switch也是多分支语句
-
语法
switch (数据) { case 值1: 代码1 break; case 值2: 代码2 break; case 值3: 代码3 break; case 值4: 代码4 break; default: 代码n break; }
- 看某个case的值是否有跟小括号里的数据
全等
的,如果有,就执行这个全等的case里的代码,如果没有全等的,就执行default里面的代码n
- 看某个case的值是否有跟小括号里的数据
多分支 if 和 switch的比较
- 能用if做的switch也能做,能用switch做的if也能做
- 如果以后是范围判断,那么就用if会好一些
- 如果是一些少量具体的值,就用switch会好一些
13. 相等的一些细节
- undefined == null 得到true
- undefined === null 得到false
- NaN 不等于任何数据,包括它自己
- NaN == NaN 永远都是false
- 那么如何判断是否为NaN?
- isNaN(数据)
- 如果是NaN得到true
- 否则得到false
- isNaN(数据)
第三部分
1.循环结构
重复执行某段代码
- 因为有的时候一段代码需要重复执行,而用复制会比较傻也不利于维护,所以用循环结构会方便很多
2.while循环
-
语法:
while (循环条件) { 循环体 }
-
循环体:就是要重复执行的代码
-
语义: 判断循环条件是否为true,如果为true则执行循环体,否则跳出while循环
- 如果为true时执行完循环体,会又回到while的循环条件的位置,继续判断是否为true,以此类推
-
一般情况下,我们需要一个变量来控制循环的次数,这个变量叫循环增量,所以我们一般会这样写
let i = 0 while (i < 次数) { 循环体 i++ }
- 想执行几次,就在次数那写几
- 切记:一定要写i++,因为如果不写会导致无限循环,这种我们称之为死循环
-
3.do-while 循环
do {
循环体
}while(循环条件)
- 先执行循环体,然后再判断循环条件,如果条件为true,回来继续执行循环体,那么如果为false,就跳出循环
- do-while循环的循环体至少会执行1次
- 如果某个循环体,至少要执行1次的,那么就用do-while
4.for 循环
-
实际开发用的最多的循环
-
之前用while循环也能做限制次数的循环,但是容易忘记写i++,而且我们的循环增量跟循环有点割裂
-
for可以解决上面的问题
-
语法
for (声明循环变量;循环条件;变量++ ) { 循环体 } 后面的代码
- 执行过程:
- 先执行声明循环变量,再判断循环条件是否为true,为true就执行循环体,为false就直接跳出循环
- 为true执行完循环体,会回到变量++的位置来做变量自增,自增完了再来判断循环条件,依次类推
- 执行过程:
5.break和continue
- break:
- 结束所在的switch语句
- 结束所在的循环
- continue:
- 只能用在循环
- 结束当次循环,继续下次循环
6.循环嵌套
- 循环里面再写一个循环就叫循环的嵌套
7.循环嵌套案例 - 九九乘法表
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
table {
margin:60px auto;
/* 合并单元格缝隙 */
border-collapse: collapse;
}
/* 边框,宽高、居中 */
td{
border: 1px solid #000;
width:100px;
height:35px;
text-align: center;
}
</style>
</head>
<body>
<script>
document.write('<table>')
// 里面的tr和td,没必要一个一个自己写,而是可以循环生成
for (let i = 1; i <= 9; i++) {
document.write('<tr>')
// 内层循环
for (let j = 1; j <= i; j++) {
document.write('<td>')
// document.write('列 X 行 = 它们相乘的结果')
document.write(`${j} x ${i} = ${j * i}`)
document.write('</td>')
}
document.write('</tr>')
}
document.write('</table>')
</script>
</body>
</html>
第四部分
1.数组介绍
- 数组作用:保存多个数据
- 它在内存中的本质相当于是开了一个大空间里面分成了n多个小空间来保存每个数据
- 数据可以保存任意类型的数据
2.数组的语法
-
数组的初始化
let 数组名 = [ 数据列表 ]
- 数组名可以随便写,但是要符合变量的命名规则和规范
- 数据列表可以写任意个数据,如果多个数据用逗号隔开
-
名词:
- 元素:数组里保存的每个数据都叫数组元素
- 下标/索引:每个数据的编号,从0开始
- 长度:数组中数据的个数
-
单独取出某个数组里的元素,该怎么取?
-
用下标取
-
语法是:
数组名[下标] // 例 nums[0] // 取出下标为0的元素,其实就是第一个元素
-
-
数组元素的重新赋值
-
也是通过下标重新赋值
-
语法是:
数组名[下标] = 数据 nums[0] = 999 // 把下标为0的元素,修改为999
-
-
数组的最大下标 = 长度 - 1
3.获取数组长度
数组名.length 可以得到长度
nums.length // 获取nums的长度
4.遍历数组
-
把数组中每个元素给取出来
-
语法
for (let i = 0; i < 数组.length; i++){ 数组[i] } // 例 let nums = [10, 20, 30, 40, 50] for (let i = 0; i < nums.length; i++) { console.log(nums[i]) }
5.数组长度
- 数组的长度可以改
- 数组长度++,则是在最后多一个元素,用undefined补齐
- 数组长度--,则相当于删除数组最后一个元素
- 数组长度直接赋值,如果赋的值比原来的长度要大,相当于增加,增加部分用undefined补齐
- 数组长度直接复制,如果赋的值比原来的长度要小,相当于删除,减少几个就删除后面几个
6.数组动态添加元素
- 可以对数组原本不存在的下标进行赋值,那么它就会在这个下标位置增加数据
- 如果这个下标跟原本存数据的下标存在一段距离,那么这段距离会用undefined补齐
- 例:一个数组为let nums = [10,20, 30] 下标只到2, 但是如果我 nums[8] = 999 ,那么在下标8会多一个999,然后在下标3到下标7用undefined补齐
7.那如何保证我们是按顺序添加元素
- 按顺序添加数组语法
数组名[数组名.length] = 数据
例:
nums[nums.length] = 60
- 案例:让用户输入5个成绩依次存到数组,并得到最高分、最低分、总分、平均分
- 参考代码
// 请用户输入一共有多少人
let cont = +prompt('请输入班级人数')
let arry = []
let sum = 0
let max = 0
let mix = 100
for (let i = 0; i < cont; i++) {
arry[i] = +prompt(`请输入第${i + 1}个数`)
sum += arry[i]
if (arry[i] > max) {
max = arry[i]
}
if (arry[i] < mix) {
mix = arry[i]
}
}
alert(`班级总分:${sum},平均分:${sum / arry.length},最高分:${max},最低分:${mix}`)
8.数组综合案例
- 数组去重
- 参考代码
/* 数组去重:去除数组里的重复项 假设有一个数组: [ 10, 15, 29, 10, 29, 30 ] 去重后变 [10, 15, 29, 30] */ let arr = [10, 15, 29, 10, 29, 30] let newArr = [] // 第一个元素绝对不可能重复,所以直接扔到新数组 newArr[0] = arr[0] for (let i = 1; i < arr.length; i++) { // arr[i] 旧数组的当前元素 // 遍历新数组 // 我立一个flag,我假设这个元素可以添加到新数组 // 所以我这个值先立为true let flag = true for (let j = 0; j < newArr.length; j++) { // 判断 旧数组的当前元素 是否跟 新数组的每个元素是否相等 // newArr[j] 新数组的每个元素 if (arr[i] == newArr[j]) { flag = false // 相等没必要往后判断,直接break break } } // 新数组遍历完才能决定扔不扔到新数组里 if (flag) { // 只有小括号里为true才会执行下面代码。为false不执行下面代码就不会加 // 只有当新数组有相同数据的时候才会为false,只要新数组没相同的flag还是为true // 为true就执行代码往后面加 // 加到新数组 newArr[newArr.length] = arr[i] } } console.log(newArr)
- 斐波那契数列
- 参考代码
/* 1 1 2 3 5 8 13 21 34 55 89 ........... 特点:前两列是1,从第三列开始,每一列的值都是它前两列的和 求出第n列的斐波那契数列上的值是几 如果,我写5,那么就要得到第五列,就是5 如果我写8,就得到第八列,就得到21 首先斐波那契确定的值只有前面两列为1, 从第三列开始都是要计算出来 所以我们可以准备一个数组,先只装1,1 假设我要求第3列,那么就是求下标2的位置 下标2位置的值 = 下标2-1 + 下标2-2 下标3位置的值 = 下标3-1 + 下标3-2 。。。。。。 下标n位置的值 = 下标n-1 + 下标n-2 例如:我要算下标5位置的值, 就用 下标5-1 + 下标5-2 就能得到结果 问题是,我在算下标5之前,要不要先把下标2,下标3,下标4算出来?要 所以,这里就有一个循环 例如:要算下标5 那么就从下标2开始循环,依次计算出下标2、下标3、下标4、直到下标5的值 */ let fib = [1, 1] // 我就要算下标5 // fib[2] = fib[2 - 1] + fib[2 - 2] // fib[3] = fib[3 - 1] + fib[3 - 2] // fib[4] = fib[4 - 1] + fib[4 - 2] // fib[5] = fib[5 - 1] + fib[5 - 2] // 请输入要查询第几列 let col = prompt('请输入要查询第几列') // 从第三列(也就是下标2开始)一直算到要查询的列 for (let i = 2; i < col; i++) { // 当前这列等于前两列之和 fib[i] = fib[i - 1] + fib[i - 2] } // 输出最后一列的结果 alert(fib[fib.length - 1])
第五部分
1.函数介绍
- 函数:就是一种把代码封装起来的语法
- 作用:提高代码复用,便于维护与解决代码冗余
2.函数的基本使用
-
声明语法
function 函数名 () { 函数体 }
-
调用语法
函数名()
-
注:函数只声明不调用,里面代码不会被执行
3.有参数的函数
-
有的时候函数完成某个功能需要外界传入数据,这时候就需要有参数的函数
-
语法
function 函数名 (参数列表) { 函数体 }
-
参数列表,就是定义需要几个数据,多个之间用逗号隔开
4.形参和实参
- 形参:
- 声明函数时写在小括号里的叫形参
- 实参:
- 调用函数时写在小括号里的叫实参
5.有返回值的函数
-
为什么需要?
- 因为调用函数时会得到一个结果,而这个结果是调用者想要得到的,所以应该把这个结果返回给调用者
-
语法
function 函数名 (参数列表) { 函数体 return 数据 // 代表把数据返回出去 }
-
例:
function f1 () { return 'hello' // 返回hello } let res = f1() // 把f1返回的hello赋值给res
-
可以返回变量值,也可以直接返回数据
6.return 关键字
- return后面可以直接写数据,也可以写变量(代表取出变量的值返回),也可以写表达式(算出表达式的结果再返回)
- return有立即结束函数的作用,所以return后面的代码不会被执行
- return后面也可以不加任何数据,也有返回值,只不过返回值是undefined
- 函数内也可以不写return,只不过这个时候函数的返回值就是undefined
7.注意
- 函数要想被调用,必须加小括号:函数名()
- 换句话说,只要加了小括号,都代表调用了这个函数
- 如果只是写函数名,不加小括号,不是调用,它只是代表找到这个函数里保存的代码
8.函数的另一声明
-
表达式声明
let 变量 = function () { 函数体 }
-
如果用这种方式声明的函数,不能再它声明之前调用
-
但是用
function
声明的函数,可以在声明之前调用
第六部分
1.对象
如何保存一个人的姓名、年龄、性别等特征以及吃饭的行为?
let p = {
name: 'jack',
sex: '男',
age: 16,
eat: function () {
console.log('吃啊吃,我肚子大大大')
}
}
console.log(p)
console.log(p.name)
console.log(p.age)
console.log(p.sex)
p.eat()
- 对象也可以保存多个数据,并且取值时能很清晰的知道取的是什么
- 对象跟顺序无关,所以我们一般称对象是无序存储,而数组叫有序存储
2.对象的初始化
let 对象名 = {
属性名: 属性值,
}
-
例:
let p = { name: 'jack', sex: '男', age: 16, eat: function () { console.log('吃啊吃,我肚子大大大') } }
3.跟对象有关的名词
-
对象这种数据类型一般是用来用代码描述现实中的某个具体事物
-
属性:对象拥有的特征
-
方法:对象
-
例:要用代码去表示一只猫
- 特征:昵称、年龄、品种…
- 行为:抓沙发
4.方法的说明
- 方法就是对象的行为
- 在代码中其本质是函数
- 所以函数可以有参数和返回值,方法也有,写法跟函数一样
5.内置对象
-
JS已经提供好的对象
-
Math对象:
-
这个对象表示的是一个数学高手
-
它可以做一些数学运算
-
Math.pow(): 幂运算(基本不用,了解)
-
Math.abs():取绝对值
-
取整的方法:
- Math.round(): 四舍五入取整,本质是找离自己最近的整数,.5会取更大的整数
- Math.floor(): 向下取整,得到的整数一定比原来的值要小
- Math.ceil():向上取整,得到的整数一定比原来的值要大
- parseInt() : 直接取整
-
生成随机数:
-
Math.random() : 生成 0 - 1之间的随机数,包括0,不包括1
-
如果要生成任意整数之间的随机数,公式:
Math.floor(Math.random() * ( 大 - 小 + 1)) + 小
-
-
6.对象赋值的细节
- 对象如果对一个已经存在的属性赋值,就是修改
- 如果对一个不存在的属性进行赋值,就是增加
7.对象取值的另外一种方法
-
对象如果访问一个不存在的属性,得到undefined
-
对象.属性名 这种形式叫点语法
- 永远不会找变量,就是找这个对象里的这个属性
-
对象[字符串]
- 也是代表找字符串对应的整个属性
-
对象[变量名]
-
代表先取出变量的值,变量值是什么就找什么属性
-
例
let p = {name:'jack',age:16} let attr = 'name' p['attr'] // 就代表找attr属性 p[attr] // 代表取出attr的值,也就是'name',所以相当于找的就是name属性
-
一定要注意,加引号就不是找变量而是就找这个属性,不加引号才是找变量取出变量的值
-
8.遍历对象
-
遍历对象:就是把对象中每个数据取出来
-
语法
for (let key in 对象名) { // 不一定要叫key,也可以叫别的,但是建议叫key或者k // key就是属性名,所以可以通过属性名访问属性值 对象名[key] } // 例: for (let key in p) { p[key] }
9.构造函数
-
工厂模式:
- 本质就是封装代码
- 封装创建对象的代码,因为我们发现每次创建同一种类型的对象代码都一样,所以可以封装成函数
- 那么这种函数就叫工厂函数
- 特点:函数内自己创建对象,自己返回对象,调用时不用写new
function factory(name, age, sex) { // 现在我要创建2个对象,都有name、age、sex属性,和吃饭的行为 let p = {} // 左边是属性名,右边是变量名,到时候会取出变量名的值作为属性值 p.name = name p.age = age p.sex = sex p.eat = function () { console.log('吃啊吃啊,我骄傲放纵') } return p }
-
构造函数:
- 实际上构造函数就是对工厂函数的升级
- 升级在:不用我们自己创建对象,也不用我们自己返回对象,利用this关键字访问到构造函数帮我们创建的对
- 注意:构造函数的函数名首字母大写,尽量用名词
function Person(name, age, sex) { // 现在这个对象是构造函数帮我们创建的,所以不叫p了 // 访问创建的对象用this this.name = name this.age = age this.sex = sex this.eat = function () { console.log('吃啊吃啊,我骄傲放纵') } } let p1 = new Person('jack',16,'男')
-
new关键字做的三件事:
- 创建了一个新的空对象
- 把函数内的this指向到这个新的空对象
- 在函数结束的时候返回这个新的对象
10.new调用函数内return的细节
- 数据类型也分为两大类
- 基本数据类型
- string、number、boolean、undefined、null
- 复杂数据类型
- 数组、函数、对象
- 基本数据类型
- 如果使用new关键字调用的函数内部写return不跟值,还是new帮我们创建的对象
- 如果写return,后面接基本数据类型,还是new帮我们创建的对象
- 如果写return,后面接复杂数据类型,那么就是返回这个复杂数据类型
11.使用构造函数创建数组和对象
let arr = new Array()
let obj = new Object()
let f1 = new Function() //函数
12.字面量概念
- 就是通过字面意思就能知道是什么数据类型
- {}字面就是对象,[]字面就是数组
13.数组内置的方法
- 数组本质也是一种对象
- 所有它也有属性和方法
- 属性:
- 数组.length
- 方法:
- reverse() : 反转数组
- push():
- 在数组末尾添加元素
- 也可以一次性添加多个,用逗号隔开
- 返回值是新长度
- pop()
- 删除数组末尾的元素(一次只能删一个)
- 返回值就是被删除的元素
- unshift()
- 在数组第一个位置添加元素
- 也可以一次性添加多个,用逗号隔开
- 返回值是新长度
- shift()
- 删除数组的第一个元素
- 返回值是被删除的元素
- join()
- 把数组中每个元素用一个符号连接起来
- 如果什么都不传,默认是逗号隔开
- 如果传空字符串,那么每月任何隔开符,如果传空格字符串,用空格隔开
- 返回一个字符串
14.数组的排序方法
-
sort()
- 默认是先比较第一位,再比较第二位,依次类推
- 如果比较字符,它会先把字符根据ASCII码转整数,小的前面,大的后面
- ascii就是计算机中把英文字母(英文符号)都有对应的整数值,A是65 小a是97
-
如果我希望就是按数字大小从小到大排列就传入函数
数组.sort( function (a,b) { return a - b } )
-
如果我希望就是按数字大小从大到小排列就传入函数
数组.sort( function (a,b) { return b - a } )
15.数组splice
- 删除
- splice(从哪个下标开始,删除几个)
- splice(2,3) 代表下标2开始删,删除3个
- splice(从哪个下标开始,删除几个)
- 替换
- splice(从哪个下标开始,找几个,替换成什么)
- splice(2,3,300) 下标2开始一共找3个,都只替换成一个300
- 替换多个,也是逗号隔开
- splice(从哪个下标开始,找几个,替换成什么)
- 新增
- splice(新增到哪个下标,0, 新增的内容)
- splice(1,0, 999) 下标1的位置新增999
- 如果要新增多个,则逗号隔开
- splice(新增到哪个下标,0, 新增的内容)
16.数组indexOf和lastIndexOf
- indexOf(数据)
- 从前往后找匹配的数据,返回找到的第一个的下标
- 如果不存在得到-1
- laseIndexOf(数据)
- 从后往前找匹配的数据
- 不存在也得到-1
- 主要作用:判断数据在不在数组里面,如果不在得到-1,在就不等于-1
17.字符串内置的方法
-
indexOf和lastIndexOf
- 跟数组一样的效果
- 但是如果传入空字符串,则永远得到0
-
字符串不可改!
-
所谓的不可改是它的内容不可改,不是说变量不能重新赋值
let str = 'hello' str = '你好' // 这个可以,因为不算改字符串的内容,只是相当于指向一个新的字符串 str[0] = 'z' // 无效,因为字符串内容不可改
-
-
split
-
把字符串按照某个符号切割为数组
let str = '刘德华|张学友|郭富城|黎明' // 我需要把字符串转成数组 let arr = str.split('|') // 按竖线分割字符串变成数组 console.log(arr)
-
如果传入不存在的字符,或者没传任何参数,那么会把字符串当做一个整体元素
-
如果传入空字符串,会把字符串的每个内容都当做一个元素
-
-
replace
- 替换字符串
- 参数1:被替换的内容
- 参数2:替换的新内容
- 只会得到新的结果,不会直接改变原来的值
-
toUpperCase()
- 转大写
-
toLowerCase()
- 转小写
-
trim()
- 取出两边空格
18.日期对象
- 表示日期的对象
- 方法:
- getFullYear()
- 获得年
- getMonth()
- 获得月,但是月从0开始,所以要+1才能转成现实生活中的月份
- getDate()
- 获得日期的日
- getDay()
- 获得星期几,星期天获得0,其他都是获得对应的数字
- getHours()
- 获得时
- getMinutes()
- 获得分
- getSeconds()
- 获得秒
- getFullYear()
第七部分
1.this 关键字
- 普通函数里的this,一般是window对象
- 构造函数里的this,一般是new关键字刚刚出来的新对象
- 方法里的this,谁调用这个方法,方法里的this就是谁
2.日期对象创建时指定时间
-
默认 new Date()什么都不传就获取当前时间
-
new Date() 如果依次传入年、月、日、时、分、秒,就是得到对应的时间,但是要注意传入0得到1月,传入1得到2月
let time1 = new Date(1990, 0, 1, 12, 32, 45) console.log(time1.getFullYear(), time1.getMonth(), time1.getDate()) console.log(time1)
-
new Date() 如果传入一个字符串时间,就是得到字符串内容的时间,更加精确
let time2 = new Date('1990-2-1 12:32:45') console.log(time2)
3.时间戳
- 时间戳获取的是自 1970年1月1日0点0分0秒 到现在过了多少毫秒
- 怎么获取?
- 构造函数获取
- Date.now()
- 使用实例化的日期对象来获取
- 对象.getTime()
- 把 对象 转成 number 类型就能获取
- 构造函数获取
- 通过时间戳可以得到指定日期
4.利用时间戳计算倒计时
公式总结如下:
天 = parseInt (总毫秒 / (1000 * 60 * 60 * 24)) 总毫秒 = 总毫秒 % (1000 * 60 * 60 * 24) // 得到剩余毫秒 时 = parseInt ( 总毫秒 / (1000 * 60 * 60) ) 总毫秒 = 总毫秒 % (1000 * 60 * 60 ) // 得到剩余毫秒 分 = parseInt ( 总毫秒 / (1000 * 60) ) 总毫秒 = 总毫秒 % (1000 * 60 * 60 ) // 得到剩余毫秒 秒 = parseInt ( 总毫秒 / 1000 )
-
代码如下:
// 获取当前时间 let now = new Date() // 再获取目标时间 let distTime = new Date('2020-11-11 0:0:0') // 把两个日期转成时间戳再相减,就能得到两段时间间隔多少毫秒 // 再把毫秒转成天、时、分、秒就行了 let milSec = distTime - now let day = parseInt(milSec / (1000 * 60 * 60 * 24)) // 得到算了天后剩余的毫秒 milSec = milSec % (1000 * 60 * 60 * 24) // 算出时 let hour = parseInt(milSec / (1000 * 60 * 60)) milSec = milSec % (1000 * 60 * 60) // 算出分 let min = parseInt(milSec / (1000 * 60)) // 算出剩余毫秒 milSec = milSec % (1000 * 60) let sec = parseInt(milSec / 1000) document.write(` <h3>双11距离现在还有:</h3> <div>${day}天${hour}时${min}分${sec}秒</div> `)
5.全局作用域、局部作用域、块级作用域
- 全局作用域
- 从
script
开头到script
结尾的区域
- 从
- 局部作用域
- 只有函数会开辟局部作用域,函数内的就叫局部作用域
- 块作用域
- 任何 {} 都叫 块作用域,但是只有 let 声明的变量才区分块作用域,var只有全局和局部
- 全局变量
- 在全局作用域里声明的变量叫全局变量
- 任意范围可以访问
- 局部变量
- 在函数内声明的变量叫局部变量
- 只有这个函数内可以访问
- 块变量
- 在
{}
里用let声明的变量叫块变量,只能在这个大括号里访问 - var不存在块作用域,只有let存在
- 在
{
var a = 10
console.log(a) // 10
}
console.log(a) // 10 因为var不存在块作用域,所以还能访问
{
let b = 10
console.log(b) // 10
}
console.log(b) // 报错,因为b是块变量,只能在大括号里访问
6.作用域链
- 只有函数可以开辟作用域
- 默认也有作用域叫
全局作用域
,我们也称之为0级作用域 - 如果在0级作用域里声明一个函数,那么这个函数开辟的作用域就叫1级作用域
- 如果在1级作用域里又声明一个函数,那么这个函数开辟的作用域就叫2级作用域
-
练习
<script> var num = 10; if(num > 0){ var sum = 20; } console.log ( sum ); // 20 for(var i = 0;i<5;i++){ } console.log ( i ); // 5 var name = '张三'; function fn ( ) { name = '李四'; } fn(); console.log ( name ); // 李四 </script>
7.预解析以及声明的提升
console.log ( num ); // undefined
var num = 10;
console.log ( num ); // 10
fn();
function fn ( ) {
console.log ( num ); // undefined
console.log ( "哈哈哈" );
var num = 10;
console.log ( num ); // 10
}
console.log ( a ) ;
var a = "我是变量";
function a(){
console.log ( "我是函数" );
};
console.log ( a );
</script>
8.let 与 var 的异同总结
- 相同点:都是声明变量
- 不同点:
- let只认块,也就是
{}
,在哪个大括号里声明,就只能在这个大括号里使用 - var认作用域,所以var里会分0级、1级、2级,还要注意,只有function才可以开辟作用域
- var参与预解析时的变量提升,而let不参与
- let在同一个块里不能声明同名变量,var无所谓
- let只认块,也就是
9.回调函数、自执行函数
-
回调函数:
- 函数A当做参数传递给另外一个函数B,那么函数A就叫回调函数
-
自执行函数
-
写法
;( function () { }) () // 常用的 ;( function () { }()) // 不太常用的
- 记住:自执行函数前面记得加分号,不加可能报错
-
作用:开辟新的作用域,避免变量冲突
-
10.arguments
- arguments是一个伪数组,它里面保存了调用函数时传递过来的所有实参
- arguments只能用在函数里
- arguments作用:就是可以让函数的扩展性更强,因为可以让它传入任意个参数,我们都可以拿到并处理
11.instanceof
-
可以判断一个数据是复杂数据类型的哪种
-
它用来判断复杂数据类型,基本数据类型用typeof
-
用法:
数据 instanceof 构造函数 数据 instanceof Array // 判断是否为数组 数据 instanceof Function // 判断是否为函数 数据 instanceof Date // 判断是否为日期对象 数据 instanceof Object // 判断是否为对象(所有复杂数据类型本质都是对象)
-
如果是这个类型得到true,不是得到false
12.案例:统计一个字符串中每个字符出现的次数
// 我们准备一个字符串
let str = 'abasfggghjjkkgfddsssss3444343'
// 统计每个字符出现的次数
let obj = {} // 准备一个空对象
for (let i = 0; i < str.length; i++) {
let ch = str[i]
// 判断这个ch字符在不在对象的属性里
if (obj[ch]) {
// 代表在里面,已经有了
obj[ch]++
} else {
// 不在里面,还没有
obj[ch] = 1
}
}
let max = 0
let maxCh = ''
// 全部打印出来
for (let key in obj) {
if (obj[key] > max) {
max = obj[key] // 次数
maxCh = key // 字符
}
}
console.log(`${maxCh}出现的次数最多,它的次数是${max}`)