day16
一、作用域
1.作用域就是变量访问的范围或区域,分为全局作用域和局部作用域,函数外面就是全局作用域范围,函数内部的属于局部作用域范围。
2.变量分类,分为全局变量和局部变量,全局变量可以在函数外部和函数内部访问的变量称之为全局变量(定义在函数外部的变量);局部变量则只能在函数内部访问的变量称之为局部变量(定义在函数的内部)。但如果函数内部的变量没有使用var关键字来定义,那么他就是全局变量。
3.变量的声明周期 全局变量: => 声明时 --- 出生(在内存里面开辟的小空间里面存储) => 当网页关闭的时 --- 销毁(从内存空间里面销毁)
局部变量: => 声明时 --- 出生(在内存里面开辟的小空间里面存储) => 当函数执行完毕后 --- 销毁(从内存空间里面销毁)
4.作用域链 访问规则:先在当前作用域里面进行查找,如果找到了就使用当前作用域里面的变量,如果没有就继续往上一级继续查找,直到找到0级还是没有就报错
二、预解析
浏览器在解析的代码的时候,会先把代码加工处理后再去逐行解析,把加工处理代码的这个过程称之为预解析(浏览器解析代码要加工处理,并不是之前那么理解的从上而下解析)
=> 先把变量声明和函数声明提升到当前作用域的最顶端 => 在按照原先的书写顺序逐行执行代码
变量声明提升 => var a 变量声明
函数声明提升 => function fn(){} 整个函数体都属于函数声明部分 函数声明
函数声明 例如:function fn(){} 例如:var fn = function(){}
注意点:表达式声明的函数,函数声明不会提升
三、递归
+ 一个函数自己调用自己就是递归函数 + 递归函数的作用和循环作用是类似的 + 递归注意点 => 递归必须要有出口(结束条件)
1.递归练习
// 规则:n * fn(n-1)
// 第一次进入函数:给形参赋值 n = 5,进入函数体里面 // 第二次进入函数:给形参赋值 n = 4,进入函数体里面 // ... // 第五次进入函数:给形参赋值 n = 1,进入函数体里面
function fn(n){
// 第一次进行条件判断:5 == 1 不满足条件,继续执行下面的代码 // 第二次进行条件判断:4 == 1 不满足条件,继续执行下面的代码 // ... // 第五次进行条件判断:1 == 1 满足条件,直接给外界返回1
if(n==1){ return 1 }
// 第一次给外界返回结果:5 * fn(4),所以把这个结果返回给外界 5 * fn(4) // 第二次给外界返回结果:5 * 4 * fn(3),所以把这个结果返回给外界 5 * 4 * fn(3) // ...
return n * fn(n-1) }
// 第一次调用函数:fn(5)调用,并进行实参传递 // 第一次接收返回值:5 * fn(4),这个时候接收到返回值,发现有个fn函数那么会继续调用函数 // 第二次调用函数:fn(4)调用,并进行实参传递 // 第二次接收返回值:5 * 4 * fn(3),这个时候接收到返回值,发现有个fn函数那么会继续调用函数 // 第三次调用函数:fn(3)调用,并进行实参传递 // ... // 第五次调用函数:fn(1)调用,并进行实参传递 // 最终接收到结果:5 * 4 * 3 * 2 * 1 = 120 var result = fn(5) console.log(result)
四、数组
1.是一个引用数据类型 是一组数据的容器,基本数据类型一次只能存储一个数据,而引用数据类型一次可以存储多个数据
2.声明数组 => new Array() 构造函数,所谓的构造函数其实是创建对象的一种方式(使用函数构造了一个对象) => [] 字面量 字面表示的是什么意思就是什么意思。这里中括号表示的就是数组的意思,字母也就是数组的意思
3.下标 => 索引、index => 当创建了数组后,js会默认给每一个数组里面的数据(成员、元素)设置一个编号,这个编号默认是从0开始的,把编号也称之为下标 => 作用:可以用于获取数据、修改数据、删除数据、增加数据等等
4.length => 数组属性 => 表示数组的长度(数组元素的个数)
注意点 => 构造函数方式如果只给一个数据的话并且这个数据类型是数值类型,那么表示的是就是这个数组长度的限定,而字面量方式不适用于这个规则
5.数组类型 => 使用typeof 查看的话返回的是object => object对象是一个大的类型,而数组属于这个对象里面的一种类型分类 => 数组也可以称之为数组对象
6.数组基本操作 => 获取数组元素 -> 语法:数组名称[下标] -> 语法:数组名称[数组名称.length-1] 表示动态的获取最后一个数组元素 => 增加数组元素 -> 语法:数组名称[下标] = '值' 这里的下标是数组里面不存在的,如果是存在的那么就变成修改了 => 修改数组元素 -> 语法:数组名称[下标] = '值' 这里的下标是数组里面存在的 => 删除数组元素 -> delete 数组名称[下标]
7.数组遍历 => 使用for循环 -> 可以指定循环的开始和结束位置 -> 不能遍历对象 -> 下标是数值类型 => 使用for in -> 不能指定循环的开始和结束位置 -> 比for循环更便捷 -> 可以遍历对象 -> 下标是字符串类型(因为对象要求)
五、数组方法
shift():删除数组中第一个元素,并将长度减1. 注意点:shift和pop方法返回值都是被删除的数组元素 console.log(arr.shift()) console.log(arr)
pop():删除数组中最后一个元素,并将长度减1. console.log(arr.pop()) console.log(arr) 注意点:unshift和push方法返回值都是新增后数组的长度
unshift():往数组前面添加一个或多个数组元素,长度要改变。 console.log(arr.unshift('哈哈', '嘿嘿'))
push():往数组结尾添加一个或多个数组元素,长度要改变。 console.log(arr.push('张涛1', '张涛2')) console.log(arr)
concat(): 方法用于连接两个或多个数组, 不改变原数组。返回一个新的数组 var arr2 = ['张涛', '李双江', '陈俊豪'] console.log(arr.concat(arr2))
reverse() 逆向排序, 原数组也被逆向排序了 console.log(arr.reverse()) console.log(arr)
toString() 将数组转成字符串 console.log(arr.toString())
join(“拼接符”)将数组转成字符串,中间以拼接符连接
六、数组截取和组合方法
1.slice() + 截取,把数组里面需要的数据可以截取出来 + 参数 => 参数1表示起始位置 => 参数2表示结束位置(不包含结束位置本身) + 注意 => 如果给了负值,那么会从倒数开始截取
2.splice() + 组合方法 => 删除 => 添加(增加) => 修改(替换) + 参数 => 参数1表示的是从什么位置开始操作(删除、增加、修改) => 参数2表示删除的项数 => 参数3表示添加 + 注意点 => 如果是添加的话,那么参数2必须为0,不然就变成修改
七、arguments
数组分类: 真正的数组 伪(类)数组 => 不是真正的数组,但是可以使用数组相关的某些属性和方法
arguments 是一个伪数组 arguments是函数自带一个对象,可以用来解决形参不确定问题 arguments这个对象里面保存的是实参的数据 arguments.callee() => callee其实表示的就是函数的名称 => 在ES5的标准里面已经废弃了