1、JS的组成(面试题)
ECMAScript 和 DOM 和 BOM 三者 共同组成
1.ES:定义了JS的语法规范,描述了语言的基本语法和数据类型
简单来说: Js怎么写,需要根据ES的规定
2.DOM(文档对象模型)
*有一套成熟的操作DOM节点的API,通过DOM可以操作页面中的元素(其实就是标签)
比如:增加一个 Drv
删除一个span
修改h1标签的内容
3.BON(浏览器对象模型)
* 有一套成熟的操作BOM的API
比如:弹出框
浏览器跳转
获取浏览器相关信息
获取浏览器尺寸
2、JS的变量
JS的变量是什么?
变量是计算机中存储数据的一个标识符,通过这个标识符可以找到内存中存储的数据
大白话版:我有一个东西需要暂时存储起来,比如说一个数字100 存储到某一个变量中,
当我后续需要使用的时候可以通过这个变量找到这个数字100
变量就相当于是一个容器,内部可以存储任意类型的值,使用变量的时候,用的是内部存储的数据
使用变量需要用两步
1.定义变量
语法:var 变量名
2.赋值变量
变量名 = 值
备注:JS中一个等号,叫做赋值号
打印数据:console.log(要打印的值);可以将我们想要打印的值打印在浏览器的控制面板
var a
var b
var c
a = 100
b = 200
c = 500
console.log(a)
console.log(b)
console.log(c)
var q = 666;
var w = 888;
console.log(q);
console.log(w);
案例:交换两个变量的值
var a = 100;
var b = 200;
console.log(a);
console.log(b);
var c = a;
var a = b;
var b = c;
console.log(a);
console.log(b);
3、变量的命名规则和规范(面试题)
1.规则(必须遵守的,如果不遵守会报错)
* 在书写变量名的时候,必须由数字字母下划线$符号(英文的)并且不能以数字开头
* 书写时 区分大小写
* 书写变量名时。不能使用关键字或者保留字作为变量名
* * 关键字:在js中县有特殊含义的字母组合
* var if for function
* * 保留字:在js中目前没有特殊含义,但在将来的某个版本可能会用到,所以此时也不能使用
* 在ES6还没出现之前具有的保留字
* let const promise
2.规范(建议遵守,如果不遵守也不会报错)
* 变量名具有含义,符合见名知意
尽量不要用字母作为变量名,除非是练习
* 多个单词的组合命名时,使用驼峰命名法(多个单词拼接时,后一个单词的首字母大写)
eg:bigbox -> bigBox
var a = 100
var a1 = 100
var a1_ = 100
var a1_$ = 100
var A = 100;
var a = 200;
console.log(A);
console.log(a);
4、JS的数据类型
JS 中变量可以存储 任意类型的值
JS 中数据类型的分类(基本数据类型)
①.Number 类型
* 数字类型, 不区分 整数浮点数
* 100 200 1.1 0 -6 -999都是数字
```js
var a = 100
```
②.String 类型
* 字符串类型:只要是引号包裹的内容,就是字符串类型(引号不区分单双)
```js
var str1 = '你好'
var str2 = "你好"
var str3 = 'qwer'
var str4 = '123' //String 类型
var str5 = 123 //Number 类型
```
③.undefined 类型
* undefined 类型:他是一个数据,表明未定义
* 变量只定义,不赋值的时候,默认的值就是undefined 表明未定义
```js
var un = undefined
var z
console.log(un)//定义一个变量,变量名为un,并给它赋值为undefined
console.log(z)//定义一个变量,变量名为z,没有赋值操作,所以变量默认的值为undefined
```
④.Boolean 类型 (后期更多的 用在判断上)
* 只有两个值 一个是true 一个是false
* * true:代表真,正确的
* * false:代表假,错误的
```js
var boo1 = true;
var boo3 = false;
var boo3 = 'true'
```
⑤.null 类型
* 代表空
* * 本身是一种数据类型,只不过代表的是空(啥也没有)
* * null 和 undefined 不同!!
* * 使用场景:在创建对象的时候,如果开始不知道对象内部有什么,可以给一个null
* 类似于在创建变量的时候,只定义,不赋值默认是一个 undefined
```js
var nu = null; //定义一个变量,名为nu,值为null类型,代表空
console.log(nu);
```
* *延申:一道面试题
JS 中数据类型有哪些?
5、JS 的数据类型检测
通过一个方法检测 数据类型的值是什么
* 语法:typeof(要检测的数据类型的值)
* typeof 的问题,不能正确检测出null 这个类型的实际类型,检测nuLl 的时候打印结果为object
* null代表的含义是空,也就是空对象,所以 typeof会把他当成一个对象去输出
var str1 = '100'
var str2 = 100
var str3
var str4 = true
var str5 = false
var str6 = null
console.log(typeof(str1))
console.log(typeof(str2))
console.log(typeof(str3))
console.log(typeof(str4))
console.log(typeof(str5))
console.log(typeof(str6))
* 面试题:typeof 能正确检测所有数据类型的值吗?
* 不能。因为他没有办法准确的检测出null的类型是什么
* JS如何正确检测null的类型呢? 欠着,以后会有专门的方法讲解
6、JS的数据类型转换
(1).转换为数字类型
* ①.number(数据)
* 可以用于任何数据类型,将其转换为数字类型
* + 字符串转数字
* 如果转换的字符串是纯数字组成的。那么直接转换为数字
* 如果转换的字符串是空字符串或者空白字符串,那么直接转换为数字0
* 其他类型的字符串(不是空---空自---纯数字字符串)会转换为NaN
* NAN:表示的是一个number的数字,但是没有办法通过常规的数字表明它,所以只能使用NaN来代替(坏掉的数字)
```js
console.log(typeof(Number('100')),Number('100'));
console.log(typeof(Number('')),Number(''));
console.log(typeof(Number(' ')),Number(' '));
console.log(typeof(Number('abc')),Number('abc'));
```
* + 布尔值转数字
* true转换为1
* false转换为0
```js
console.log(typeof(Number(true)),Number(true));
console.log(typeof(Number(false)),Number(false));
```
* + undefined转数字
* 会直接转换为NaN
```js
console.log(typeof(Number(undefined)),Number(undefined));
```
* + null转数字
* 会直接转换为0
```js
console.log(typeof(Number(null)),Number(null))
```
* ②.parseInt(数据) 转换为整数
* 会将数据转换为number类型,并且值是整数(直接忽略掉小数点以后的值,并不是四舍五入)
* 在转换的时候,如果数据是绒数字字符串或者是数字开头的字符串,那么会转换为数字,否则就是转换为NaN
```js
console.log(typeof(parseInt('100')),parseInt('100'))
console.log(typeof(parseInt('100.123456789')),parseInt('100.123456789'))
console.log(typeof(Number('100.123456789')),Number('100.123456789'))
console.log(typeof(parseInt('abc')),parseInt('abc'))
console.log(typeof(parseInt('100abc')),parseInt('100abc'))
console.log(typeof(parseInt('999abc')),parseInt('999abc'))
console.log(typeof(parseInt('abc666')),parseInt('abc666'))
console.log(typeof(parseInt('')),parseInt(''))
console.log(typeof(parseInt(' ')),parseInt(' '))
console.log(typeof(parseInt(true)),parseInt(true))
console.log(typeof(parseInt(false)),parseInt(false))
console.log(typeof(parseInt(undefined)),parseInt(undefined))
console.log(typeof(parseInt(null)),parseInt(null))
```
* ③.parseFloat(数据) 转换为小数
* 转换结果与parseInt类似,但是在转换小数的时候会保留小数点后的数字
```js
console.log(typeof(parseFloat('100.123456789')),parseFloat('100.123456789'))
console.log(typeof(parseFloat('100')),parseFloat('100'))
console.log(typeof(parseFloat('100abc')),parseFloat('100abc'))
console.log(typeof(parseFloat('999abc')),parseFloat('999abc'))
console.log(typeof(parseFloat('abc')),parseFloat('abc'))
console.log(typeof(parseFloat('abc666')),parseFloat('abc666'))
console.log(typeof(parseFloat('')),parseFloat(''))
console.log(typeof(parseFloat(' ')),parseFloat(' '))
console.log(typeof(parseFloat(true)),parseFloat(true))
console.log(typeof(parseFloat(false)),parseFloat(false))
console.log(typeof(parseFloat(undefined)),parseFloat(undefined))
console.log(typeof(parseFloat(null)),parseFloat(null))
```
* ④.扩展:在实际开发中 我个人常用 数据 - 0 (暂时先不考虑原理)
```js
console.log(typeof('100'),'100')
console.log(typeof('100' - 0),'100' - 0)
console.log(typeof('100abc' - 0),'100abc' - 0)
console.log(typeof('abc100' - 0),'abc100' - 0)
```
(2).转换为字符串类型
转换为字符串类型
* +. 变量.toString()方法
* 注意:undefined 类型和 null不能使用toString方法(因为JS没有给我们提供,或者说Js不允许)
```js
var str1 = 100
console.log(typeof(str1.toString()),str1.toString())
var str2 = true
console.log(typeof(str2.toString()),str2.toString())
var str3 = false
console.log(typeof(str3.toString()),str3.toString())
var str4 = undefined
console.log(typeof(str4.toString()),str4.toString())
var str5 = null
console.log(typeof(str5.toString()),str5.toString())
```
* +. String(变量)
* 什么类型都可以转换为字符串类型的,包括undefined 和 null类型
```js
var str1 = 100
console.log(typeof(String(str1)),String(str1))
var str2 = true
console.log(typeof(String(str2)),String(str2))
var str3 = false
console.log(typeof(String(str3)),String(str3))
var str4 = undefined
console.log(typeof(String(str4)),String(str4))
var str5 = null
console.log(typeof(String(str5)),String(str5))
```
* +.扩展:开发时常用的一个方法
* 变量 + '' (暂时不考虑原理)
* 转换结果与string类似,写法上更简单一些,所以推荐使用
```js
var str1 = 100
console.log(typeof(str1 + ''),str1 + '')
var str2 = true
console.log(typeof(str2 + ''),str2 + '')
var str3 = false
console.log(typeof(str3 + ''),str3 + '')
var str4 = undefined
console.log(typeof(str4 + ''),str4 + '')
var str5 = null
console.log(typeof(str5 + ''),str5 + '')
```
(3).转换为布尔类型
BooLean(变量) 将其他数据类型,转换为布尔值(也就是转换为 true 或者 false)
①.数字转换布尔值,只有0会转换为false 其他的数字都会转换为true(非0即为真)
```js
var num1 = 100
var num2 = 0
var num3 = -1
console.log(num1,'---->',Boolean(num1))//100
console.log(typeof(Boolean(num1)),Boolean(num1))//BooLean true
console.log(num2,'---->',Boolean(num2))//0
console.log(num3,'---->',Boolean(num3))//-1
```
②.字符串转换布尔值,只有空字符串会转换为 false其他的字符串都会转换为 true
```js
var str1 = ''
var str2 = ' '
var str3 = 'abc'
var str4 = '0'
console.log(str1,'---->',Boolean(str1))//''
console.log(str2,'---->',Boolean(str2))//' '
console.log(str3,'---->',Boolean(str3))//'abc'
console.log(str4,'---->',Boolean(str4))//'0'
```
③.undefined 和 null 转换为布尔值的时候就是false(重点,以后会常用!!!)
```js
var und = undefined
var nul = null
console.log(und,'---->',Boolean(und))
console.log(nul,'---->',Boolean(nul))
```
#### **7、JS的运算符**
①.算术运算符
* 加减乘除 取余(求余数)
* + - * / %
* 注意:+ 运算符,相加时如果两边都是数字,那么会运算数字的相加操作
* 相加时如果两边有一个不是数字的,比如出现一个字符串,那么运行的 不是在相加,而是拼接操作
* 拼接操作只有+运算时会出现,其他符号不出现
* 其他运算符在遇到两边有非数字类型时,会将其转换为数字(这一步就叫做隐式操作),然后在运算
```js
console.log(1 + 1)
console.log(3 + 4)
console.log(5 + 0)
console.log(5 + '0')
console.log(1 - 1)
console.log(9 - 4)
console.log(5 - '0')
console.log(1 * 1)
console.log(3 * 4)
console.log(5 * '0')
console.log(5 / 1)
console.log(8 / 2)
console.log(6 / '2')
console.log(5 % 1)
console.log(10 % 3)
console.log(5 / 0)
console.log(5 % 0)
```
②.赋值运算符
* = 一个赋值号
* += 相当于是“我自身”加上一个新值。就可以用这个 += 来优化,例子:a = a + 10 优化后:a += 10
* -= *= /= %= 运算逻辑与+=是完全相同的
```js
var a = 1
a = a + 10
console.log(a)
var a = 1
a += 10
console.log(a)
var a = 5
a -= 5
console.log(a)
var a = 2
a *= 2
console.log(a)
var a = 4
a /= 4
console.log(a)
var a = 10
a %= 3
console.log(a)
```
③.比较运算符
比较运算符 比较运算符两边的值之后,返回一个布尔值,也就是返回一个true或者false
* 判断
* > < >= <=
* 判断相等
* == === 在js中等号出现两次或者三次时代表等于的意思
*
* 判断不相等
* != !==
* 共同点:判断符号两边的值是否不相等,不相等时返回true 相等时返回false
* 不同点
* != 不会对比数据类型
* !-= 会对比数据类型
* */
```js
console.log(3 > 4)
console.log(3 < 4)
console.log(5 < 6)
console.log(6 < 5)
console.log(1 > 1)
console.log(1>=1)
console.log(1<1)
console.log(1<=1)
console.log(1 == 1)
console.log(99 === 99)
console.log(1 == '1')
console.log(1 === '1')
console.log(3 != 4)
console.log(9 !== 10)
console.log(3 != '3')
console.log(3 !== '3')
```
* 两个等号和三个等号的区别(面试题)
* == 在的js中判断时会做隐式转换,也就是说只会对比值是否相等,不会对比数据类型
* === 在JS中也叫做全等,在判断的时候不会做隐式转换,也就是说,
在对比时除了会对比值是否相等,还会判断数据类型是否相同
④.逻辑运算符
* && 逻辑与(相当于并且的意思)
* || 逻辑或(相当于或者的意思)
* ! 逻辑非(取反,反义词)
*
* !逻辑与运算符(&&)的特性!!!
* 符号左边的值 如果为真(也就是转为布尔值后为true),那么会返回符号右边的值
* 如果为假(也就是转为布尔值后为false),那么会将自身返回出去
* !逻辑或运算符的特性!!!
* 符号左边的值 如果为真,那么会将自身返回出去
如果为假。那么会将符号右的值返回出去
* !逻辑非运算符的特性!!!
语法:!值
返回值:将值转换为布尔值之后,做一个取反的操作。也就是true改变false,false改变为 true
* */
```js
console.log(1 && 100)
console.log(0 && 99)
console.log(true && 'qwer')
console.log(false && 'qwer')
console.log(1 || 100)
console.log(0 || 99)
console.log(!99)
console.log(!0)
console.log(!true)
```
⑤.自增自减运算符
++ --
* 语法:(自增自减都是相同的语法,这里就拿自增为例)
* 1.++值
* 2.值++
*
* 自增运算符的能力就是将自身的值+1
* 自减运算符的能力就是将自身的值-1
*
* 自增自减运算符写法不同,运行结果也不同
* 1. ++值(++在前)
* 如果++在前,那么会先将自身的值+1 然后参与其他的
* 2. 值++(++在后)
* 如果++在后,那么会先参与周围的运算,然后将自身的值+1
*
* 自减运算符在前与在后的作用与自增运算符完全相同,只不过是-1
```js
var a = 1
var b = 1
console.log(++a)
//如果++在前,那么会先将自身的值+1 然后打印到控制台
console.log(b++)
//如果++在后,那么会先将目前的值打印到控制台(也就是1),然后将自身的值+1 也就是说这行运行完华后,变量b的值变为2了
console.log(a,b) //2,2
```
8、JS的优先级
* 运算符优先级从高到低
* 自增自减运算符++ -- !
* 算术运算符 先* / % 后+ -
* 比较运算符中的 > >= < <=
* 比较运算符中的 == != === !==
* 逻辑运算符 先&& 后||
* 赋值运算符
9、课后练习
```js
//1. `var a = 3; var b = a++; a + b + a++`该代码输出的值为11
var a = 3;
var b = a++; //a++先赋值后自增 所以b=3 a=4
console.log(a + b + a++)// a + b + a++ = 4 + 3 + 4 =11
//2. `console.log(parseInt(1 * 100 / 3 + ""))`该代码输出的值为33
//100 / 3 + "" = "33.33333" = 33
//3. `var a = 3; a++; a++; var b = a+2; ++a; console.log(a)` 该代码输出的值为6
//b = 7 a = 6
//4. `3 - "36" % 5 + "2" - 2`该代码输出的值为20
//36 % 5 = 1 3 - 1 + "2" - 2 = 22 - 2 = 20
// 5. `var a = 4; var num = 1 * (2 + 3) && a++ || 5 > 6 && 7 < 8 || !9;` num的值是 4
// num = 4 || false || false = 4
//6. 在不考虑四舍五入的情况下对一个数字进行保留两位小数(提醒: 使用 parseInt)
```JS
var orign = 123.456789
// code run here ...
// 输出结果: 123.45
var orign1 = 987.654321
// code run here ...
// 输出结果: 987.65
```
var orign = 123.456789
console.log(typeof (parseInt(orign)), parseInt(orign * 100) / 100)
```
10、JS的分支语句
分支语句:
* 根据我们设置好的条件!!! 然后来决定执行那些代码
*
①.if 分支语句
语法:
* if(条件) {满足条件的时候执行的代码,如果不满足,这里边的代码永远不执行}
* 条件最终会返回一个布尔值,如果为真,那么会执行对应的代码
* 如果为假,那么不会执行
```js
var a = 1
if (a === 1) {
console.log(1)
}
if (a === 2) {
console.log(1)
}
var a = 100
if(a === 1) {
console.log(1)
} else if(a === 2) {
console.log(2)
} else {
console.log('a 不等于 1或者2')
}
```
if分支的课堂练习
var num = 12
if(num % 2 === 0) {
console.log('偶数')
}else {
console.log('不是偶数')
}
var a = 12
if (10 <= a && a <= 20) {
console.log('数字在10~20之间')
} else {
console.log('数字不在10~20之间')
}
console.log(10<=9<=20)
console.log(10<=9)
console.log(false<=20)
console.log(true);
var num = 62
if(num >= 90) {
console.log('优秀');
}else if (num >= 80) {
console.log('中等')
}else if (num >= 70) {
console.log('及格')
}else if (num >= 60) {
console.log('要努力')
}else {
console.log('你危险了')
}
var num = 2023
if (num % 4 === 0 && num % 100 !== 0 || num % 400 === 0) {
console.log('是闰年')
} else {
console.log('不是闰年')
}
②.switch 分支语句
和if 相同 ,也属于条件分支语句
* if(要判断的变量) {
* 想要执行的代码
* }
*
* switch (要判断的变量) {
* case 情况1:
* 情况1要执行的代码
* break;
* case 情况2:
* 情况2要执行的代码
* break;
* }
*
* 判断逻辑:判断的变量 是否 ===case上说明的情况
*
* 注意:switch...case 在判断时,执行时全等,也就是 === 所以数据类型不同时,也不会正确执行
```js
var a = 100
switch (a) {
case 1:
console.log('如果我执行,说明 a === 1')
break;
case 10:
console.log('如果我执行,说明 a === 10')
break;
case 100:
console.log('如果我执行,说明 a === 100')
break;
default:
console.log('上述情况都不满足的时候,我会执行')
}
```
③.switch穿透语法
switch 在书写的时候 如果不写break 会出现穿透现象
*
* 穿透现象:
* 找到第一个满足的case的时候,开始执行这个代码
* 执行完毕如果没有break 会继续执行下一个case
* 直到 遇到一个break 或者 分支语句全部执行完毕
```js
var a = 100
switch (a) {
case 1:
console.log('case 1 执行')
case 10:
console.log('case 10 执行')
case 20:
console.log('case 20 执行')
case 30:
console.log('case 30 执行')
case 40:
console.log('case 40 执行')
case 100:
console.log('case 100 执行')
break;
default:
console.log('上述情况都不满足的时候,我会执行')
}
```
```js
var month = 11
switch (month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
console.log('有31天')
break
case 4:
case 6:
case 9:
case 11:
console.log('有30天')
break
case 2:
console.log('2月有28天')
break
}
```
switch课堂练习
var num = 67
switch (parseInt(num/10)) {
case 10:
console.log('完美')
break
case 9:
console.log('优秀')
break
case 8:
console.log('中等')
break
case 7:
console.log('及格')
break
case 6:
console.log('要努力')
break
case 5:
console.log('你危险了')
break
}
11、三元表达式
```js
var a = 100
a > 1 ? console.log('如果我输出了,说明 a 的值 大于 1'):console.log('如果我输出了,说明 a 的值小于 1')
var num = 1
var gender = num === 1 ?'男':'女'
console.log(gender)
```
12、while循环语句
①.while循环语句
意义:帮助我们去执行 重复的代码
*
* 什么是循环语句
* 根据给出的某些条件,重复执行一段代码
*
* 循环语句
* 1.初始化
* 2.条件判断
* 3.要执行的代码
* 4.改变自身(改变初始化的内容)
*
* while 循环
* 语法: while (条件) {满足条件时执行的代码}
```js
var num = 0
while (num < 1000) {
console.log(1)
num++
}
```
②.while循环的课堂练习
```js
var num = 1
var sum = 0
while (num <= 100) {
sum = sum + num
num++
}
console.log(sum)
```
13、循环语句练习
```js
var year = prompt('请输入年份') - 0
var month = prompt('请输入月份') - 0
switch (month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
console.log('有31天')
break;
case 4:
case 6:
case 9:
case 11:
console.log('有30天')
break;
case 2:
year % 4 === 0 && year % 100 !== 0 || year % 400 === 0?console.log('因为',year,'是闰年,所以2月有29天'):console.log('因为',year,'不是闰年,所以2月有28天')
break;
}
```
```js
var num = 1
var sum = 0
while(num <= 100) {
if(num % 3 === 0) {
sum = sum + num
}
num++
}
console.log('所有3的倍数的和为:'+sum)
```
14、do...while循环
①.do...while循环
是一个类似 while 的循环语句
*
* while循环在开始的时候,会先判断条件是否成立 然后决定是否执行
* do..while 循环在开始第一次的时候,不会判断条件,也就是说,不管条件成功与失败,第一次都会执行
var num = 10
do{
console.log(num)
num--
}while(num < 5)
②.do...while循环练习
```js
var password;
do {
password = prompt('请输入您的密码')
}while(password !== '12345')
```
15、for 循环
for 循环
* 也是 循环语句的一种,但是 语法上和另外两个不同!
* 语法:for (1.初始化 2.条件 3.改变自身){4.循环要执行的代码}
* 目前for循环的使用场景来看,要稍微多一点,但不代表可以完全替代 while 循环或者do...while循环
```js
for(var n = 0; n < 3; n++) {
console.log(n)
}
```
②.for循环练习
```js
var sum = 0
for (var i = 1; i <= 100; i++) {
sum += i
}
console.log(sum)
var sum = 0
for (var i = 1; i <= 100; i++) {
if(i % 2 ===0 ){
sum += i
}
}
console.log(sum)
for (var year = 1000; year <= 2022; year++){
if(year % 4 === 0 || year % 100 === 0 || year % 400 ===0){
console.log(year,'是闰年')
}
}
for(var i = 100; i <= 999; i++){
var baiW = parseInt(i / 100)
var shiW = parseInt(i / 10 % 10)
var geW = i % 10
var sum = Math.pow(baiW,3)+Math.pow(shiW,3)+Math.pow(geW,3);
if(sum === i){
console.log(i,'是一个水仙花数')
}
}
```
16、流程控制语句
* 通过两个关键字,可以起到控制循环的一个作用,这就是流程控制
*
* 1. break(结束掉整个循环,不管循环后边还有几轮)
* 今天早上我买了五个包子,然后呢我吃了3包子,这个时候我吃饱了,我吃不下去了 此时我就结束掉了吃包子这件事,也就是说第四个和第五个包子我就不吃了
```js
for(var i = 1; i <= 5; i++) {
console.log('我吃了一个包子')
if(i === 3) {
break
}
}
```
* 2.continue(跳出当前这一轮循环,直接开始下一轮循环)
* 今天早上我买了五个包子,然后呢我在吃第三个包子的时候,这个时候,第三个包子掉地上了,所以这个包子我不吃了 此时我开始吃第四个包子与第五个包子
```js
for (var i = 1; i <= 5; i++) {
if(i === 3) {
console.log('第三个包子掉地上了,我不吃这个包子了')
continue
}
console.log('我吃了一个包子')
}
```
17、循环嵌套
* 注意:外层循环的变量与内层循环的变量不要相同
```js
for (var j = 0; j < 3; j++) {
for (var i = 0; i < 3; i++) {
console.log(i)
}
console.log('j的值为',j)
}
```
for循环课堂案例
* 需求:在页面上打印9个*
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('<br>')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
document.write('*')
for(var j = 0; j < 9; j++) {
for (var i = 0; i < 9; i++){
document.write('*')
}
document.write('<br>')
}
for(var j = 0; j < 9; j++) {
for (var i = 0; i < j; i++){
document.write('*')
}
document.write('<br>')
}
for(var j = 1; j <= 9; j++) {
for (var i = 1; i <= j; i++){
sum = i * j
document.write(i , '*' , j , '=' , sum,' ')
}
document.write('<br>')
}
18、课后练习
```js
//1. 用户输入一个整数 n,计算 n 的阶乘。即`n*(n-1)*(n-2)*……*3*2*1`
var sum = 1 //初始化
for (var n = parseInt(prompt('请输入n的值'))
// 计算这个数字的阶乘
sum = sum * n //执行代码
}
console.log(sum)
/* var num = prompt('请输入一个数字') - 0
var sum = 1
for(var i = 1
sum *= i
}
console.log(sum)
//2. 苹果 3 元一个, 鸭梨 2 元一个, 桃子 1 元一个。现在想用 200 元正好买 100 个水果, 用 JS 列出所有购买方案
/**
* 核心内容
* 条件:
* 1.买三种水果一共花200元 3*苹果+2*鸭梨+1*桃子=200
* 2.买三种水果一共买100个 苹果+鸭梨+桃子=100
* */
for(var a = 0
for(var b = 0
for(var c = 0
if(a + b + c === 100 && 3*a + 2*b + c === 200){
console.log('购买方案为','苹果',a,'鸭梨',b,'桃子',c)
}
}
}
}
```
首先一定要明确,和数学中的函数完全是两回事
*
* 在JS 中,函数可以理解为一段在程序(页面)中多次出现的代码段 封装起来的盒子
*
* 简单来说,JS 的函数就是一个盒子,盒子里边装的是﹑在当前页面中多次出现的较为复杂的代码段
20、函数的使用
* 如果函数只定义不调用,那么没有任何意义
1. 函数的定义(创建一个盒子)
分为两种方式定义
* 1.1 声明式定义
* 语法:function fn (){}
* function: 关键字 -> 表明后续的是一段函数
* fn: 函数的名字 -> 将来函数调用的的候需要用到,函数名自定义
* (): 内部填写参数 -> 欠着,后续详细讲解
* {}:内部填写函数调用时要执行的代码段
```js
function fn1(){
console.log('我是fn1函数')
}
fn1()
```
* 1.2 赋值式定义
* 语法:var fn = function () {}
```js
var fn2 = function () {
console.log('我是fn1函数')
}
fn2()
```
2.函数的使用(使用盒子内的代码)
* 不管是声明式还是赋值式定义的函数,调用方式都是一样的
* 调用语法:函数名() / 变量名()
21、声明式与赋值式的区别
* 1.写法不同
* 2.调用上略有不同
* 声明式定义的函数,可以在 函数定义前 去调用
```js
fn1()
console.log('我是fn1函数定义前的 输出~~~')
function fn1(){
console.log('我是fn1函数')
}
fn1()
```
* 赋值式定义函数,不能在函数定义前 去调用
```js
console.log(fn2)
console.log('我是fn2函数定义前的 输出~~~')
var fn2 = function () {
console.log('我是fn2函数')
}
console.log(fn2)
console.log(fn2())
```
*
* 赋值式定义函数不能在函数定义前调用的原因
* 赋值式定义,其实就是声明一个变量,然后给他赋值为一个函数
*
* 再JS中,如果再定义变量之前使用变量的话。那么变量的值为undefined (变量提升 面试可能会问)
*
* 函数的执行结果,一般默认都是undefined,除非手动更改
22、函数的参数
①.函数的参数
* 函数的参数如何书写?
* 书写在function后的小括号内
* 参数的作用
* 如果一个函数没有书写参数,那么这个函数的功能相对来说比较单一
* 如果书写了参数,能够使我们这个函数的使用更加灵活
* 参数的书写,分为两个
* 1.function 后的小括号内 书写的参数我们叫做"形参"
!!! 形参的作用:书写之后,相当于在函数内部创建了一个变量,变量实际的值由"实参”传递
* 2.函数名后的小括号内 书写的参数我们叫做“实参”
!!! 实参的作用:将自身的值,按照一一对应的关系,传递给形参
```js
// 一个需求,需要封装一个函数,这个函数内需要计算出1+2的值,并输出在页面上
function fn() {
var sum = 1 + 2
console.log(sum)
}
fn()
// 新需求:封装一个函数,这个函数内需要计算5 + 8 的值,并输出在页面上
function fn1() {
var sum = 5 + 8
console.log(sum)
}
fn1()
function fn2(a, b) {
var sum = a + b
console.log(sum)
}
fn2(100,200)
fn2(300,400)
fn2(365,1)
```
②.函数参数的注意事项
函数的参数
* 形参 和 实参 两个的数量,要一一对应
* 1. 形参的数量如果大于实参
* 如果形参的数量大于实参的数量,那么会将实参按照顺序一一传递给 对应的形参 多出来的形参,相当于变量只定义没赋值,所以他们的值﹑是undefined
* 2. 实参的数量如果大于形参
* 如果实参的数量大于形参的数量,那么会将实参按照顺序一一传递给 对应的形参多出来的实参,无法在函数内部通过参数的方式调用
```js
function fn(a , b , c , d) {
console.log(a , b , c , d)
}
fn(1,2)
function fn(a , b) {
console.log(a , b)
}
fn(100,200,300,400)
function fn(a = 100 , b = '我是形参b' , c) {
console.log(a , b , c)
}
fn()
```
23、函数的返回值
* 函数的返回值(函数的执行结果)
*
* 在函数内部创建(定义)的变量,只能在函数内部使用,后续学习作用域的时候会详细讲解
*
* 我们如果想在函数外部得到函数内部的某一个值,或者运算结果,我们可以通过return这个关键字来帮我们完成
```js
function fn(a , b) {
return a + b
}
var num = fn(100,200)
console.log('num的值',num)
function test() {
return 50 - 10
}
var sum = test()
console.log(sum)
```
24、课堂练习
```js
function fn(start, end) {
var sum = 0
for(var i = start; i <= end; i++) {
sum += i
}
return sum
}
var num = fn(1, 100)
console.log('num的值',num)
```
```js
function fn(i) {
var baiW = parseInt(i / 100)
var shiW = parseInt(i / 10 % 10)
var geW = i % 10
var sum = Math.pow(baiW,3)+Math.pow(shiW,3)+Math.pow(geW,3);
if(sum === i){
return true
}else {
return false
}
}
var boo = fn(153)
console.log(boo)
```
25、return的注意事项
return 的注意事项
* return 具有中断函数的能力
* 所以一般来说我们将它放在函数的尾部
26、函数的课后练习
```js
function fn(i) {
var qianW = parseInt(i/1000)
var baiW = parseInt(i/100)%10
var shiW = parseInt(i/10)%10
var geW = i%10
var sum = Math.pow(qianW,4)+Math.pow(baiW,4)+Math.pow(shiW,4)+Math.pow(geW,4)
if(sum === i){
return (i+'是一个水仙花数')
}else {
return (i+'不是一个水仙花数')
}
}
var bool = fn(8569)
console.log(bool)
function fn2(i) {
if(i >= 1000 && i <= 9999){
var qianW = parseInt(i/1000)
var baiW = parseInt(i/100)%10
var shiW = parseInt(i/10)%10
var geW = i%10
qianW = (qianW+5)%10
baiW = (baiW+5)%10
shiW = (shiW+5)%10
geW = (geW+5)%10
return ''+ shiW + geW + qianW + baiW
}else {
console.log('传入的数字,不是四位数字')
}
}
var sum = fn2(5655)
console.log('加密后的数字为:',sum)
function fn3(a,b) {
var min = a > b ? b : a //如果a>b条件成立,说b的值小,所以返回b,否则,说明a的值小。那么返回a
// 2.找约数
for (var i = min; i >= 1; i--) {
if(a % i === 0 && b % i === 0){
return i
}
}
}
var sum = fn3(8,12)
console.log('a和b的最大公约数是:',sum)
function fn4(a,b){
return a * b / fn3(a,b)
}
var zx = fn4(8,12)
console.log('a和b的最小公倍数是:',zx)
```
27、函数的预解析
预解析的一个表现就是 声明式函数再定义前可以被调用
*
* 预解析是什么?
* JS 在执行代码的时候, 会有一个 所谓的 解析阶段
* 解析阶段, 做了一件事, 就是 函数提升, 就是将 声明式 函数的定义, 提升到当前 作用域的最顶端
*
* 作用域的最顶端:
* 暂时理解为 当前页面的最开始的位置
```js
fn()
function fn() {
console.log('我是 fn 函数, 我被调用了')
}
```
一道面试题: 函数的预解析是什么?
正常书写的 代码
* fn()
* function fn() {
* console.log('我是 fn 函数, 我被调用了')
* }
*
* 浏览器会对我们的 JS 代码, 做一个 预解析, 预解析的时候, 会将函数提升到 当前作用域的最顶端, (暂时理解为 当前页面最开始的位置)
*
* fn() -> 这行代码是函数调用, 所以不需要提升
* function fn() { -> 这是一个声明式定义的函数, 所以需要提升
* console.log('我是 fn 函数, 我被调用了')
* }
*
* 预解析之后的代码长什么样(执行顺序)?
* function fn() {
* console.log('我是 fn 函数, 我被调用了')
* }
*
* fn() // 所以此时调用的时候, 因为 fn 函数已经定义完成了, 所以这里能够正常执行函数
28、作用域
什么是 作用域? (这是一道面试题)
* 就是变量可以起作用的范围
*
* 作用域分为两个 (这是一道面试题)
* 1. 全局作用域(直接在 script 内书写的代码)
* 再此作用域创建的变量, 我们叫做全局变量, 在当前 script 标签内的哪里都能使用
* 在 JS 中, 全局作用域中有一个 提前给我们准备好的 对象(一种数据格式, 后续会详细的讲解)
* 这个 对象叫做 window
* 我们创建的全局变量, 会被自动添加到 window 对象中
*
* 2. 局部作用域(在 JS 中, 只有函数能够创建局部作用域)
* 在此作用域创建的变量, 只能在当前作用域使用, 超出这个作用域(也就是在函数外边)去使用, 就会找不到变量
```js
var num = 100
console.log(num)
function fn() {
var sum = '我是在函数 fn 内部创建的变量, 我是局部变量, 所以我只能在当前函数内使用'
var abc123 = '我是在 fn 函数内部创建的局部变量'
console.log(sum)
}
fn()
var abc = '我是一个全局变量 abc'
console.log(window)
```
29、作用域链
* 作用域链 (这是一个纯概念性的东西, 面试也可能会问)
* 作用域链就是在访问一个变量的时候, 如果当前作用域内没有
*
* 会去自己的父级作用域, 也就是上一层作用域内查找, 如果找到就直接使用, 如果没有找到继续向上层查找
*
* 直到查找到 最顶层的全局作用域, 如果找到了直接使用, 如果没找到 报错提示变量不存在(未定义)
*
* 我们将这个一层一层向上查找的规律, 叫做作用域链
```js
var num = 999
function fn1() {
var num = 100
function fn2() {
console.log(num)
}
fn2()
}
fn1()
var num = 999
function fn1() {
function fn2() {
console.log(num)
}
fn2()
}
fn1()
function fn1() {
function fn2() {
console.log(num)
function fn3() {
var num = 666
}
fn3()
}
fn2()
}
fn1()
```
* 作用域链的赋值规则
* 在给变量赋值的时候, 首先会去当前作用域查找, 如果有直接赋值, 并停止查找
*
* 如果没有, 会去自己的父级查找, 在父级找到直接修改值然后停止查找, 如果没有继续向自己的父级查找, 直到找到全局作用域
*
* 在全局作用域内, 找到直接赋值修改他的值, 如果没有找到, 那么会在全局作用域创建一个变量, 并赋值
```js
function fn1() {
function fn2() {
num = 100
}
fn2()
}
fn1()
console.log(num)
function fn1() {
var num = 999
function fn2() {
num = 100
}
fn2()
console.log(num)
}
fn1()
console.log(num)
var num = 666
function fn1() {
var num = 999
function fn2() {
num = 100
}
fn2()
}
fn1()
console.log(num)
var num = 666
function fn1() {
function fn2() {
num = 100
}
fn2()
}
fn1()
console.log(num)
```
30、递归函数
递归函数
*
* 本质上还是一个函数
*
* 当一个函数在函数的内部, 调用了自身, 那么就算是一个 所谓的 递归函数(只不过有点小缺陷)
```js
function fn(n) {
return n * fn(n - 1)
}
var sum = fn(4)
console.log(sum)
function fn(n) {
if (n === 1) {
return 1
}
return n * fn(n - 1)
}
var sum = fn(4)
console.log(sum)
var sum1 = fn(10)
console.log(sum1)
```
19、函数的概念
首先一定要明确,和数学中的函数完全是两回事
*
* 在JS 中,函数可以理解为一段在程序(页面)中多次出现的代码段 封装起来的盒子
*
* 简单来说,JS 的函数就是一个盒子,盒子里边装的是﹑在当前页面中多次出现的较为复杂的代码段
20、函数的使用
* 如果函数只定义不调用,那么没有任何意义
1. 函数的定义(创建一个盒子)
分为两种方式定义
* 1.1 声明式定义
* 语法:function fn (){}
* function: 关键字 -> 表明后续的是一段函数
* fn: 函数的名字 -> 将来函数调用的的候需要用到,函数名自定义
* (): 内部填写参数 -> 欠着,后续详细讲解
* {}:内部填写函数调用时要执行的代码段
```js
function fn1(){
console.log('我是fn1函数')
}
fn1()
```
* 1.2 赋值式定义
* 语法:var fn = function () {}
```js
var fn2 = function () {
console.log('我是fn1函数')
}
fn2()
```
2.函数的使用(使用盒子内的代码)
* 不管是声明式还是赋值式定义的函数,调用方式都是一样的
* 调用语法:函数名() / 变量名()
21、声明式与赋值式的区别
* 1.写法不同
* 2.调用上略有不同
* 声明式定义的函数,可以在 函数定义前 去调用
```js
fn1()
console.log('我是fn1函数定义前的 输出~~~')
function fn1(){
console.log('我是fn1函数')
}
fn1()
```
* 赋值式定义函数,不能在函数定义前 去调用
```js
console.log(fn2)
console.log('我是fn2函数定义前的 输出~~~')
var fn2 = function () {
console.log('我是fn2函数')
}
console.log(fn2)
console.log(fn2())
```
*
* 赋值式定义函数不能在函数定义前调用的原因
* 赋值式定义,其实就是声明一个变量,然后给他赋值为一个函数
*
* 再JS中,如果再定义变量之前使用变量的话。那么变量的值为undefined (变量提升 面试可能会问)
*
* 函数的执行结果,一般默认都是undefined,除非手动更改
22、函数的参数
①.函数的参数
* 函数的参数如何书写?
* 书写在function后的小括号内
* 参数的作用
* 如果一个函数没有书写参数,那么这个函数的功能相对来说比较单一
* 如果书写了参数,能够使我们这个函数的使用更加灵活
* 参数的书写,分为两个
* 1.function 后的小括号内 书写的参数我们叫做"形参"
!!! 形参的作用:书写之后,相当于在函数内部创建了一个变量,变量实际的值由"实参”传递
* 2.函数名后的小括号内 书写的参数我们叫做“实参”
!!! 实参的作用:将自身的值,按照一一对应的关系,传递给形参
```js
// 一个需求,需要封装一个函数,这个函数内需要计算出1+2的值,并输出在页面上
function fn() {
var sum = 1 + 2
console.log(sum)
}
fn()
// 新需求:封装一个函数,这个函数内需要计算5 + 8 的值,并输出在页面上
function fn1() {
var sum = 5 + 8
console.log(sum)
}
fn1()
function fn2(a, b) {
var sum = a + b
console.log(sum)
}
fn2(100,200)
fn2(300,400)
fn2(365,1)
```
②.函数参数的注意事项
函数的参数
* 形参 和 实参 两个的数量,要一一对应
* 1. 形参的数量如果大于实参
* 如果形参的数量大于实参的数量,那么会将实参按照顺序一一传递给 对应的形参 多出来的形参,相当于变量只定义没赋值,所以他们的值﹑是undefined
* 2. 实参的数量如果大于形参
* 如果实参的数量大于形参的数量,那么会将实参按照顺序一一传递给 对应的形参多出来的实参,无法在函数内部通过参数的方式调用
```js
function fn(a , b , c , d) {
console.log(a , b , c , d)
}
fn(1,2)
function fn(a , b) {
console.log(a , b)
}
fn(100,200,300,400)
function fn(a = 100 , b = '我是形参b' , c) {
console.log(a , b , c)
}
fn()
```
23、函数的返回值
* 函数的返回值(函数的执行结果)
*
* 在函数内部创建(定义)的变量,只能在函数内部使用,后续学习作用域的时候会详细讲解
*
* 我们如果想在函数外部得到函数内部的某一个值,或者运算结果,我们可以通过return这个关键字来帮我们完成
```js
function fn(a , b) {
return a + b
}
var num = fn(100,200)
console.log('num的值',num)
function test() {
return 50 - 10
}
var sum = test()
console.log(sum)
```
24、课堂练习
```js
function fn(start, end) {
var sum = 0
for(var i = start; i <= end; i++) {
sum += i
}
return sum
}
var num = fn(1, 100)
console.log('num的值',num)
```
```js
function fn(i) {
var baiW = parseInt(i / 100)
var shiW = parseInt(i / 10 % 10)
var geW = i % 10
var sum = Math.pow(baiW,3)+Math.pow(shiW,3)+Math.pow(geW,3);
if(sum === i){
return true
}else {
return false
}
}
var boo = fn(153)
console.log(boo)
```
25、return的注意事项
return 的注意事项
* return 具有中断函数的能力
* 所以一般来说我们将它放在函数的尾部
26、函数的课后练习
```js
function fn(i) {
var qianW = parseInt(i/1000)
var baiW = parseInt(i/100)%10
var shiW = parseInt(i/10)%10
var geW = i%10
var sum = Math.pow(qianW,4)+Math.pow(baiW,4)+Math.pow(shiW,4)+Math.pow(geW,4)
if(sum === i){
return (i+'是一个水仙花数')
}else {
return (i+'不是一个水仙花数')
}
}
var bool = fn(8569)
console.log(bool)
function fn2(i) {
if(i >= 1000 && i <= 9999){
var qianW = parseInt(i/1000)
var baiW = parseInt(i/100)%10
var shiW = parseInt(i/10)%10
var geW = i%10
qianW = (qianW+5)%10
baiW = (baiW+5)%10
shiW = (shiW+5)%10
geW = (geW+5)%10
return ''+ shiW + geW + qianW + baiW
}else {
console.log('传入的数字,不是四位数字')
}
}
var sum = fn2(5655)
console.log('加密后的数字为:',sum)
function fn3(a,b) {
var min = a > b ? b : a //如果a>b条件成立,说b的值小,所以返回b,否则,说明a的值小。那么返回a
// 2.找约数
for (var i = min; i >= 1; i--) {
if(a % i === 0 && b % i === 0){
return i
}
}
}
var sum = fn3(8,12)
console.log('a和b的最大公约数是:',sum)
function fn4(a,b){
return a * b / fn3(a,b)
}
var zx = fn4(8,12)
console.log('a和b的最小公倍数是:',zx)
```
27、函数的预解析
预解析的一个表现就是 声明式函数再定义前可以被调用
*
* 预解析是什么?
* JS 在执行代码的时候, 会有一个 所谓的 解析阶段
* 解析阶段, 做了一件事, 就是 函数提升, 就是将 声明式 函数的定义, 提升到当前 作用域的最顶端
*
* 作用域的最顶端:
* 暂时理解为 当前页面的最开始的位置
```js
fn()
function fn() {
console.log('我是 fn 函数, 我被调用了')
}
```
一道面试题: 函数的预解析是什么?
正常书写的 代码
* fn()
* function fn() {
* console.log('我是 fn 函数, 我被调用了')
* }
*
* 浏览器会对我们的 JS 代码, 做一个 预解析, 预解析的时候, 会将函数提升到 当前作用域的最顶端, (暂时理解为 当前页面最开始的位置)
*
* fn() -> 这行代码是函数调用, 所以不需要提升
* function fn() { -> 这是一个声明式定义的函数, 所以需要提升
* console.log('我是 fn 函数, 我被调用了')
* }
*
* 预解析之后的代码长什么样(执行顺序)?
* function fn() {
* console.log('我是 fn 函数, 我被调用了')
* }
*
* fn() // 所以此时调用的时候, 因为 fn 函数已经定义完成了, 所以这里能够正常执行函数
28、作用域
什么是 作用域? (这是一道面试题)
* 就是变量可以起作用的范围
*
* 作用域分为两个 (这是一道面试题)
* 1. 全局作用域(直接在 script 内书写的代码)
* 再此作用域创建的变量, 我们叫做全局变量, 在当前 script 标签内的哪里都能使用
* 在 JS 中, 全局作用域中有一个 提前给我们准备好的 对象(一种数据格式, 后续会详细的讲解)
* 这个 对象叫做 window
* 我们创建的全局变量, 会被自动添加到 window 对象中
*
* 2. 局部作用域(在 JS 中, 只有函数能够创建局部作用域)
* 在此作用域创建的变量, 只能在当前作用域使用, 超出这个作用域(也就是在函数外边)去使用, 就会找不到变量
```js
var num = 100
console.log(num)
function fn() {
var sum = '我是在函数 fn 内部创建的变量, 我是局部变量, 所以我只能在当前函数内使用'
var abc123 = '我是在 fn 函数内部创建的局部变量'
console.log(sum)
}
fn()
var abc = '我是一个全局变量 abc'
console.log(window)
```
29、作用域链
* 作用域链 (这是一个纯概念性的东西, 面试也可能会问)
* 作用域链就是在访问一个变量的时候, 如果当前作用域内没有
*
* 会去自己的父级作用域, 也就是上一层作用域内查找, 如果找到就直接使用, 如果没有找到继续向上层查找
*
* 直到查找到 最顶层的全局作用域, 如果找到了直接使用, 如果没找到 报错提示变量不存在(未定义)
*
* 我们将这个一层一层向上查找的规律, 叫做作用域链
```js
var num = 999
function fn1() {
var num = 100
function fn2() {
console.log(num)
}
fn2()
}
fn1()
var num = 999
function fn1() {
function fn2() {
console.log(num)
}
fn2()
}
fn1()
function fn1() {
function fn2() {
console.log(num)
function fn3() {
var num = 666
}
fn3()
}
fn2()
}
fn1()
```
* 作用域链的赋值规则
* 在给变量赋值的时候, 首先会去当前作用域查找, 如果有直接赋值, 并停止查找
*
* 如果没有, 会去自己的父级查找, 在父级找到直接修改值然后停止查找, 如果没有继续向自己的父级查找, 直到找到全局作用域
*
* 在全局作用域内, 找到直接赋值修改他的值, 如果没有找到, 那么会在全局作用域创建一个变量, 并赋值
```js
function fn1() {
function fn2() {
num = 100
}
fn2()
}
fn1()
console.log(num)
function fn1() {
var num = 999
function fn2() {
num = 100
}
fn2()
console.log(num)
}
fn1()
console.log(num)
var num = 666
function fn1() {
var num = 999
function fn2() {
num = 100
}
fn2()
}
fn1()
console.log(num)
var num = 666
function fn1() {
function fn2() {
num = 100
}
fn2()
}
fn1()
console.log(num)
```
30、递归函数
递归函数
*
* 本质上还是一个函数
*
* 当一个函数在函数的内部, 调用了自身, 那么就算是一个 所谓的 递归函数(只不过有点小缺陷)
```js
function fn(n) {
return n * fn(n - 1)
}
var sum = fn(4)
console.log(sum)
function fn(n) {
if (n === 1) {
return 1
}
return n * fn(n - 1)
}
var sum = fn(4)
console.log(sum)
var sum1 = fn(10)
console.log(sum1)
```
31、认识对象
①什么是对象
Js中的一种数据格式 对象在JS中的数据类型数据为:引用数据类型(也有喜欢叫复杂数类型)
②如何向变量中存储一个叫做对象的数据呢?
语法1:var obj = {键值对}
键值对 -> key:value
如果对象内部有多个键值对,那么需要使用逗号隔开
```js
var obj = { a:100, b:200, c:300, q:999}
console.log(obj)
```
③什么是键值对(拿对象obj 为例子)
在这个对象中,a 为key,100为对应value
另外一种叫法:a为键,100为对应的值
另外一种叫法:a为属性名,100为对应的属性值
b为key,200为对应的value
b为键,200为对应的值
b为属性名,200为对应的属性值
32、建对象
创建对象 分为两种方式:
*1.字面量的形式(使用频率比较高)
语法:var obj = {键值对}
*2.内置构造函数的创建
语法1:var obj1 = new Object()
语法2:var obj1 = new Object({a: 1, b: 2})
注意: new Object 的О是大写的,不是小写
*面试官:JS创建对象的方式有哪些?
目前暂时是 两种
1.字面量的方式
```js
var obj = {
a:1,
b:2,
c:0,
d:'abc',
e:true,
q:undefined,
w:null,
r:function () {console.log('我是 obj对象内r这个属性的属性值,我是一个函数')}
}
console.log(obj)
```
2.内置构造函数的方式
```js
var obj1 = new Object({ a: 1, q: 777, w: 666, e:'qwer'})
console.log(obj1)
```
33、象的操作(增删改查)
换句话说,就是对内部的属性的操作
分为两种方式
1.点语法
2.中括号语法(数组语法)
*一般来说,大部分场景使用点语法更简单,有一些特殊场景只能使用中括号语法
一般大部分情况下,点语法与中括号语法,作用相同,怎么选择都可以
特殊情况下我们需要使用中括号语法
1,对象的属性名,有纯数字或者特殊符号,这个时候,就只能使用中括号语法
2.如果涉及变量相关的时候,也需要使用中括号
```js
var obj = {
100: '我的属性名 是纯数字100',
'!': '我的属性名是特殊符号 !',
'@': '我的属性名是特殊符号 @'
}
console.log(obj.100)
console.log(obj[100])
console.log(obj['!'])
console.log(obj['@'])
var obj = {a: 1, b: 2, name: 'QF001'}
var myName = 'name'
console.log(obj.myName)
原因:obj.myName
我们猜想他这个myName是一个变量,所以实际的应该是 obj.'name',
所以应该打印 obj 的name属性,但实际的输出结果是undefined
因为对象的点语法,会将点后边的字符当成一个字符串去使用,而不会当成变量
拿obj.myName举例
他会将 myName 当成一个字符串去对象中查找,有没有一个叫做myName 的属性名
找完之后发现对象中没有这个属性名,所以打印的值为undefined
console.log(obj[myName])
原因:中括号语法,内部书写的字符,如果不加引号,会把它当成变量去使用,所以找到实际的值之后。myName这个变量对应的值为name
所以obj[myName]相当于写了obj['name']
所以会去对象obj中找一个叫做name的属性名,找到之后打印在页面
```
34、for...in遍历对象
for...in 一个循环语句
对象:一种数据格式
遍历:一般我们会说'遍历对象'/'遍历数组'
'遍历对象'想办法拿到对象内部所有的属性名与属性值
for (var i in 要遍历的对象) { 循环要执行的代码}
*对象关于key的要求 或者说对于属性名的要求 或者说对于键值对的键的要求
1.推荐使用符合变量命名规则与规范的名字
2.对象的 key 也可以使用 纯数字 来当作键名(属性名/key)
3.可以使用任何特殊符号(但是需要使用引号包裹)
!注意:一般只推荐使用第一种,二三了解即可
var obj = {a: 1, q: 'qwe', t: true, u: undefined}
for (var i in obj) {
console.log(obj[i])
}
35、认识数组数据类型
数组 是一种数据类型,他也是属于引用数据类型(复杂数据类型)
根据字面意思来说,存放数字的一个组合,但这样说有点片面了
更完善的说法:数组是存放一些数据的集合
换句话说:我们把数据放在一个盒子中,这个盒子就叫做数组,注意!数组内的数据是有顺序的
var arr = [1, 2, 3, 'q', 'w', 'e', true, false, undefined]
console.log(arr)
36、创建数组
创建数组
分为两种方式
1.字面量的方式
语法:var arr = [1, 2, 3, 'q', 'w', 'e']
```js
var arr = [1, 2, 3, 'q', 'w', 'e']
console.log(arr)
```
2.内置构造函数的方式
语法1:var arr = new Array()
```js
var arr1 = new Array()
console.log(arr1)
```
语法2:var arr = new Array(5)
```js
var arr2 = new Array(5)
console.log(arr2)
```
语法3: var arr = new Array(1, 2, 3)
```js
var arr3 = new Array(1, 2, 3)
console.log(arr3)
```
37、数组的length
数组的 length 属性
* length 翻译过来就是 长度的意思
* 代表 这个数组内,有多少个成员
* 语法 数组名.length
var arr1 = [1, 2, 3, 4, 5]
var arr2 = ['q', 'w', 'e', 'r']
var arr3 = new Array(1, 2, 3, 4, 5)
console.log(arr1.length)
console.log(arr2.length)
console.log(arr3.length)
38、数据的索引
索引 也有人叫做 下标
就是指一个数据,在这个数组内排列在第几个位置上
注意:在JS中,索引(下标) 是从0开始计算的
如果想要获取到数组指定位置的值,可以通过下标来获取
语法:数组名[下标] -> 能够获取到这个数组中对应下标的成员具体的值
var arr = ['b', 'a', 'c', 1, 2, 3]
console.log(arr[0])
console.log(arr[3])
39、遍历数组
遍历数组
想办法 拿到 数组的每一个成员
想拿到数组的所有成员,需要先想办法拿到数组的所有下标
规律:所有数组的下标都是从0开始的,然后到 数组.length - 1结束
var arr = ['b', 'a', 'c', 1, 2, 3]
var arr1 = ['b', 'a', 'c', 1, 2]
for (var i = 0; i < arr.length; i++) {
console.log(arr[i])
}
40、课堂案例
var arr = [9, 5, 6, 11, 8, 4, 3]
var sum = 0
for(var i = 0; i < arr.length; i++) {
sum += arr[i]
}
console.log('数组内所有成员的和为',sum)
var arr = [9, 5, 6, 11, 8, 4, 3]
var max = arr[0]
for(var i = 0; i < arr.length; i++) {
if(max < arr[i]) {
max = arr[i]
}
}
console.log('数组内最大的数字',max)
41、课后练习
1. 封装函数, 把数组进行放大十倍的操作
```javascript
function map(arr) {
// code run here ...
}
// 将来使用的时候
var arr = [100, 200, 300]
var res = map(arr)
// res: [ 1000, 2000, 3000 ]
```
- 要求: 函数的返回值需要是一个新数组
/**
* 核心内容
* 1.封装一个函数
* 2.需要参数吗?需要
* 3.需要几个参数? 1个数组
* 4.需要返回值吗? 需要,返回一个放大十倍后的新数组
* */
```js
var arr = [100, 200, 300]
function fn(fnArr) { //fnArr是形参,arr是实参
var newFnArr = [] //声明一个新数组newFnArr,将放大十倍的数组放进去
for(var i = 0
// console.log(fnArr[i])
newFnArr.push(fnArr[i] * 10)
}
return newFnArr
}
var newArr = fn(arr) //接收fn返回的值
console.log(newArr)
```
2. 使用 JS 生成一个数组
- 要求: 数组内存储的数据是从 2 开始 的所有 偶数, 要求数组的长度为 30
```js
var arr = [100, 200, 300]
arr.push(500)
```
```js
//方式一
var arr = []
for (var i = 2
// console.log(arr[i])
if (i % 2 === 0) {
arr.push(i)
}
}
console.log(arr)
//方式2
var arr2 = new Array(30)
for (var i = 0
arr2[i] = (i + 1) * 2
}
console.log(arr2)
```
3、 利用作业 2 生成的数组, 每 5 个数字求一个平均值, 放在新数组内
*例子: [2, 4, 6, 8, 10, ..., 60] -> [6, 16, 26, 36, 46, 56]
```js
var arr2 = []
var sum = 0
var ciShu = 0
var avg = 0
for (var j = 0
// console.log(arr[j])
ciShu++ //1 2 3 4 5每累加一次,那么计数器自增1,用来记录累加的次数
sum += arr[j] //2+4+6+8+10累加器每次去和数组的值相加
if (ciShu === 0) {
var avg = sum / ciShu
arr2.push(avg)
sum = 0 //累加器清0
ciShu = 0 //计时器清0
}
}
console.log(arr2)
```
42、冒泡排序
属于数组排序的算法之一
* 其实就是通过一种算法,将一个乱序的数组,调整为指定顺序的数组(从大到小/从小到大)
*
* 什么是算法?
* 解决某一个问题最简单的方式/最高效的方式
*
* 从1-10万,这组数字中,少了一个数字,要求我们找出来
* 常规写法:后一位 - 前一位 如果差值 === 2 那么就找出来了
*
* 将1-10万分为两组 1~5万 5万零一~10万 然后去找这两组数字中那一组的数量不够万,找到之后将这组再次一分为二
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7]
console.log('原始数组:', arr)
for(var k = arr.length - 2; k >= 0; k--) {
console.log('k的值为', k)
for (var i = 0; i <= k; i++) {
console.log(arr[i] , arr[i+1])
if(arr[i] > arr[i+1]) {
var temp = arr[i+1]
arr[i+1] = arr[i]
arr[i] = temp
}
}
}
console.log('冒泡排序后的数组:', arr)
43、选择排序
var arr = [9, 3, 6, 2, 4, 1, 8, 5, 7]
console.log('原始数组:', arr)
for(var k = 0; k < arr.length; k++) {
var minIndex = k
for (var i = k + 1; i <= arr.length; i++){
if (arr[minIndex] > arr[i]) {
minIndex = i
}
}
var temp = arr[k]
arr[k] = arr[minIndex]
arr[minIndex] = temp
}
console.log('选择排序后的数组' ,arr)
44、数据类型之间的区别
数据类型分为两种
1.基本数据类型(简单数据类型)
2.引用数据类型(复杂数据类型)
!1.存储
变量的数据存储的地方是 内存中,内存分为两个 栈内存,堆内存
** 基本数据类型存储在 栈内存中,比如:string number undefined null boolean
** 复杂数据类型,将数据本体存放在堆内存中,比如对象或者数组或者函数,然后将指向该内存的地址,
存放在数组名或者对象名或者函数名中,数组/对象/函数 名 存放在 栈内存中
```js
var num = 100
var str = 'abc'
var obj = {
a: 1,
b: 2
}
var arr = [1, 2, 3, 4]
```
面试官:数据类型之间有什么区别?
基本数据类型有哪些(string number undefined null boolean),然后他们存储的地方是栈内存中
引用数据类型有哪些(对象或者数组或者函数)。然后他们数据本体存放的地方是堆内存中。然后变量名在储的位置是栈内存中
**!!!基本数据类型内部存储的是值;引用数据类型内部存储的是地址**
!2.赋值
* 基本数据类型:赋值之后,两个变量之间没有任何关系,相当于将我自己的某一个东西,复制一份给你,然后你的就是你的,我的就是我的
* 例子:我有一张考试卷,然后我复制一份给你,然后你在卷子上书写答案,并不会影响到我自己原本的这张卷子
* 复杂数据类型:赋值以后,因为变量内部存储的是指向堆内存的地址 所以在赋值的时候,其实是将这个地址给到了另外一个变量 那么相当于这两个变量存储的是同一个钥匙 所以操作其中一个变量的时候,会影响另外一个变量
* 例子:我房间有一个开门的钥匙,我将我的钥匙复制一份,给到你,那么此时我们两个共同拥有了一个房间的钥匙
* 此时如果我对房间的布局做了修改,那么你进入房间的时候你能看到布局的修改
* 此时如果你将房间的所有东西全都偷走,那么我进入房间的时候能看到房间所有东西都被偷走了
```js
var num1 = 100
var num2 = num1
var num2 = 666
console.log(num1)
console.log(num2)
var obj1 = {
name: 'QF001',
age: 18
}
var obj2 = obj1;
console.log(obj2)
obj2.name = 'QF666'
console.log(obj2)
console.log(obj1)
```
!3.比较
基本数据类型:就是值的比较
引用数据类型:比较的时候 比较的是 存储地址
```js
var obj1 = {name: 'QF001', age: 18}
var obj2 = {name: 'QF001', age: 18}
obj2.name = 'QF666'
console.log(obj1.name) // QF001
console.log(obj1 === obj2) //false
/**
*引用数据类型在对比的时候,对比的是地址,而这两个对象的地址完全不同,所以返回的结果是false
* */
var num1 = 100
var num2 = 200
console.log(num1 === num2) //false
var arr1 = [1, 2, 3]
var arr2 = arr1
console.log(arr1 === arr2) //true
//引用数据类型在对比的时候,对比的是地址 因为他们两个的地址完全相同,所以返回的结果是true
```
!4.传参
基本数据类型:将值拷贝一份传递给形参,在函数内修改不会影响外界
引用数据类型:将存储地址赋值给形参,在函数内修改会影响外界
```js
function fn(num) {num = 'QF001'}
var str = 'abc'
fn(str)
console.log(str) //abc
function fn1(o) {o.name = 'qwer'}
var obj = {name: 'ABC'}
fn1(obj)
console.log(obj.name)
```
一道面试题:
var obj = {name: 'Jack'}
function fn() {
obj.name = 'Rose'
obj = {}
obj.name = 'Jerry'
console.log(obj.name)
}
fn()
console.log(obj.name)
45、数组的常用方法
⑴.push
* 语法:数组.push(数据)
* 作用:向数组末尾添加数据
* 返回值:追加数据后,数组最新的长度(length)
```js
var arr = [1, 2, 3]
console.log('原始数组:', arr)
var len = arr.push(500)
console.log(len)
console.log(arr)
```
⑵.pop
* 语法:数组.pop()
* 作用:删除数组最后一条数据
* 返回值:被删除的数据(被删除的数组中的数据)
```js
var arr = [1, 2, 3]
console.log('原始数组:', arr)
var po = arr.pop()
console.log(po)
console.log(arr)
```
⑶.unshift
* 语法:数组.unshift(数据)
* 作用:向数组开头添加数据
* 返回值:添加数据后,数组最新的长度(length)
```js
var arr = [1, 2, 3]
console.log('原始数组:', arr)
var len = arr.unshift(666)
console.log(len)
console.log(arr)
```
⑷.shift
* 语法:数组.shift()
* 作用:删除数组第一条数据
* 返回值:被删除的数据(被删除的数组中的数据)
```js
var arr = [1, 2, 3]
console.log('原始数组:', arr)
var st = arr.shift()
console.log(st)
console.log(arr)
```
⑸.reverse
* 语法:数组.reverse()
* 作用:反转数组
* 返回值:反转后的数组
```js
var arr = [1, 2, 3]
console.log('原始数组:', arr)
var newArr = arr.reverse()
console.log('newArr', newArr)
console.log('arr', arr)
```
⑹.sort
* 语法1:数组.sort()
* * 作用:会将数据转化为字符串后,一位一位的对比
* 语法2:数组.sort(function(a, b) {return a - b})
* * 作用:会按照数字大小的升序排列
* 语法3:数组.sort(function(a, b) {return b - a})
* * 作用:会按照数字大小的降序排列
* 返回值:排序后的数组
```js
var arr = [100, 101, 200, 10001, 100002, 1000003, 10]
console.log('原始数组:', arr)
var newArr = arr.sort()
console.log('newArr', newArr)//[10, 100, 1000003, 100002, 10001, 101, 200]
console.log('arr', arr)//[10, 100, 1000003, 100002, 10001, 101, 200]
var newArr = arr.sort(function (a, b) {return a - b})
console.log('newArr', newArr)//[10, 100, 101, 200, 10001, 100002, 1000003]
console.log('arr', arr)//[10, 100, 101, 200, 10001, 100002, 1000003]
var arr = [100, 101, 200, 10, '999', '123abc', 'qwe']
console.log('原始数组:', arr)
var newArr = arr.sort(function (a, b) {return b - a})
console.log('newArr', newArr)//['999', 200, 101, 100, 10, '123abc', 'qwe']
console.log('arr', arr) //['999', 200, 101, 100, 10, '123abc', 'qwe']
```
⑺.splice
* 语法1:数组.splice(开始索引(下标),多少个(数组中的数据))
* * 作用:截取数组部分内容
* 语法2:数组.splice(开始索引,多少个,插入的数据1,插入的数据2,插入的数据3...)
* * 作用:截取数组部分内容,并插入新的数据
* 返回值:截取出来的部分内容 组成的数组
```js
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log('原始数组:', arr)
var newArr = arr.splice(3, 4)
console.log('newArr', newArr)
console.log('arr', arr)
var newArr = arr.splice(3, 4, '我是新插入进来的数据1', '我是新插入进来的数据2')
console.log('newArr', newArr)
console.log('arr', arr)
```
* 数组的方法能够改变原数组的就只有上边说的7个
⑻.slice
* 语法:数组.slice(开始索引(下标), 结束索引(下标))
* 参数:
* + 包前不包后:包含开始索引位置的数据,不包含结束索引位置的数据
* (包含前边下标截取的数据,不包含后边下标截取的数据)
* + 不写开始索引,默认是0;不写结束索引,默认是数组的length (数组下标个数的和)
* + 参数支持写负数,表示倒数第几个,其实就是length + 负数
* 作用:截取数组部份内容
* 返回值:截取出来的部分内容组成的新数组
```js
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log('原始数组:', arr)
var newArr = arr.slice(3, 4)
console.log('newArr', newArr)
console.log('arr', arr)
var newArr = arr.slice(5)
console.log('newArr', newArr)
console.log('arr', arr)
var newArr = arr.slice()
console.log('newArr', newArr)
console.log('arr', arr)
var newArr = arr.slice(3, -2)
console.log('newArr', newArr)
console.log('arr', arr)
```
* *面试题:数组中有两个方法,splice 与slice,你能描述一下他们两个的区别吗?
* 1.参数含义不同,然后介绍一下 参数哪里不同
* 参数不同: 数组.splice(开始索引(下标),多少个(数组中的数据))
* 数组.slice(开始索引(下标), 结束索引(下标))
* 2.splice 会改变原数组,而slice不会
⑼.concat
* 语法:原始数组.concat(数组1,数组2..., 数据1, 数据2, 数据3...)
* 作用:进行数据拼接,把数组...数据之类的小括号里的内容,拼接在原始数组里
* 返回值:拼接好的数组
```js
var arr= [1, 2, 3]
console.log('原始数组:', arr)
var newArr = arr.concat([4, 5, 6], [20, 30], ['a', 'b', 'c'], 'qwer')
console.log('newArr',newArr)// [1, 2, 3, 4, 5, 6, 20, 30, 'a', 'b', 'c', 'qwer']
console.log('arr', arr)
```
⑽.join
* 语法:数组.join('连接符')
* 作用:使用"连接符",把数组内的每一个数据连接成一个字符串(不写连接符,默认使用的是逗号)
* 返回值:连接好的字符串
```js
var arr= [1, 2, 3]
console.log('原始数组:', arr)
var newArr = arr.join()
console.log(newArr)
var newArr = arr.join('!')
console.log(newArr)
```
⑾.indexOf
* 语法1:数组.indexOf(要检查的数据)
* * 作用:从前到后(从左到右)检查该数据第一次在该数组内出现的索引(下标)
* 语法2:数组.indexOf(要检查的数据,开始索引)
* * 作用:在开始索引的位置按照从左到右的顺序,检查该数据第一次在该数组内出现的索引
* 返回值:找到数据的情况下,会将数据第一次出现的下标(索引)返回
* 没找到的情况下,会直接返回一个 -1
*
* 备注:开始索引不写的时候 默认为0
```js
var arr = [1, 1, 2, 2, 3, 3, 0, 4, 0]
var num = arr.indexOf(100)
console.log(num)
var num = arr.indexOf(0)
console.log(num)
var num = arr.indexOf(1)
console.log(num)
var num = arr.indexOf(1, 3)
console.log(num)
```
⑿.lastIndexOf
* 语法:数组.lastIndexOf(要检查的数据)
* * 作用:从后向前(从右向左)检查该数据第一次在该数组内出现的索引(下标)
* 语法2:数组.lastIndexOf(要检查的数据,开始索引)
* * 作用:在开始索引的位置按照从右到左的顺序,检查该数据第一次在该数组内出现的索引
* 返回值:找到数据的情况下,返回第一次出现的下标(索引)
* 没找到的情况下,会直接返回一个 -1
```js
var arr = [1, 1, 2, 2, 3, 3, 0, 4, 0]
var num = arr.lastIndexOf(3)
console.log(num)
var num = arr.lastIndexOf(3, 2)
console.log(num)
```