05-函数(下)
函数-下
一、作用域
能起到作用的区域就叫做作用域。定义在不同区域的变量,他的作用域是不一样的。
不在任何一个函数中定义的变量叫全局变量。他的作用域是定义之后的所有文档区域。
例:
1 | <script> |
在函数中定义的变量叫局部变量。他的作用域是当前这个函数中,函数外不能使用。
例:
1 | function fn(){ |
如果全局和局部都有同名的变量,局部输出时如何输出呢?
1 | var a = 10; |
变量在输出时,首先考虑当前作用域,当前作用域中就会输出当前作用域中的变量,如果当前作用域中没有,才会考虑外面的全局。
二、作用域链
1、作用域链规则
函数是写在全局中,也就是说,局部作用域是被嵌套全局作用域中的。函数中也是可以定义函数的,也就是局部作用域中可以再有局部作用域,这样就形成了作用域的嵌套,我们将这个链式结构叫做作用域链。
例:
1 | var a = 10; |
这段代码的作用域链如下:
作用域链有助于我们分析变量的使用以及赋值规则,规则如下:
- 当使用变量(将变量当做值赋值,输出变量,使用变量计算)的时候,先在当前作用域中找是否定义过变量,如果定义过,就使用;如果没有定义过,就去上一级作用域中找是否定义过,定义过就使用,没有定义就继续去上级作用域中找,……直到找到全局,全局中如果定义过,使用的就是全局中的变量;如果全局中没有定义过,报错:XXX is not defined
- 当给一个变量赋值的时候,先在当前作用域中找是否定义过这个变量,如果定义过,就给这个变量赋值;如果没有定义过,就去上级作用域中找是否定义过,找到就赋值,没找到就继续去上级作用域中找,……直到找到全局,全局中定义过,就给这个全局变量赋值,如果全局没有定义过,就在全局定义这个变量并赋值
2、作用域练习
1 | function fn() { |
结论:
- 全局中有预解析,局部中也有预解析,局部的预解析,只能在局部中进行,不会将变量提升到全局
- 使用连等的方式定义变量并赋值,只有第一个有定义过程,其余的都是直接赋值
- 函数定义好以后,函数名就跟变量名一样,可以使用函数名修改这个空间中的值
- 局部的预解析会在形参赋值之后,预解析中的函数会覆盖掉形参赋的值
三、递归函数
递归函数就是在函数中调用自己。
1 | // 求10的阶和,即:10+9+8+...+1 |
四、事件
1、概念
js中的事件指的是用户在网页中的行为,例如:鼠标点击、鼠标移动、。。。。。。
事件通常由3个要素组成:
- 事件源:触发事件的标签元素,例如,点击的是div、还是button 。。。
- 事件类型:行为的类型,是单击还是双击,还是右击。。。
- 事件处理程序:事件触发后要做的事情 - 函数
2、语法
1 | 事件源.on事件类型 = 函数 |
例:
1 | <button id="btn">按钮</button> |
事件类型
事件 | 备注 |
---|---|
onclick | 当鼠标左键单击 |
ondblclick | 当鼠标左键双击 |
onmouseover | 当光标在指定的内容上面 |
onmouseout | 当光标离开指定的内容 |
onkeydown | 当键盘按下的那一刻 |
onkeyup | 当键盘抬起的那一刻 |
onfocus | 当输入框得到焦点 |
onblur | 当输入框失去焦点 |
onchange | 当指定的标签里面内容有变化的时候 |
onsubmit | 提交事件 |
onload | 当整个网页加载完成后 |
事件的其他写法:
1 | // 给事件赋值函数名称 |
注意:如果给事件赋值函数名,千万不能加小括号调用
事件还可以写在行内:
1 | <!-- 直接在行内写js代码 --> |
注意:在行内的事件中调用函数一定要加小括号调用才行
js可以像css一样有3种写法:
行内写法:事件
内联写法:平常写的代码
外联写法:项目中要将js代码放在一个文件中,在html中引入js文件
1
<script src="js文件路径"></script>
五、对象
1、概念
如果我们存储一个人信息的姓名和年龄,需要两个变量:
1 | var name = '张三' |
如果存储另一个人的信息,需要再次定义两个变量,但是变量名不能重复,因为重复会覆盖掉上面的变量:
1 | var name1 = '李四' |
从上面4个变量,可以看出来,每个变量都是独立的,互相之间是没有联系的,如果要将多个变量组合在一起去描述一个人的信息,变量之间没有关系是很容易弄错的。
为了让多个值之间有联系,确保多个值就是用来描述一个人的,就需要对象这种数据来处理。
在学习数据类型的时候,学习过对象这种数据类型,他的表现形式:
1 | var arr = []; |
这三种不同的表现形式指的都是对象。我们让多个不同的值描述一个人,重点看使用{}
定义的对象。
2、定义
1 | var obj = {}; |
这样定义的对象是空数据,其中什么也没有。对象中的值,是由键值对组成。
键值对是指在描述一个事物的时候,需要一个名字,对应一个值,例如:
1 | 姓名:张三 // 姓名是键,张三是值 |
定义有数据的对象,键和值之间使用冒号隔开,键值对之间使用逗号隔开:
1 | var obj = { |
对象有一个特性,第一次打开的时候,只能看到Object,再次刷新页面, 会显示里面的数据:
对象中键值对的数量没有限制,可以有任意多个:
1 | var obj = { |
对象中的键都是字符串,只是正常情况下可以省略引号,但如果键中包含连字符,就不能省略引号了:
1 | var obj = { |
从输出的结果中能看到,书写顺序和显示的顺序是不同的,因为对象中的键值对是没有顺序的。
3、对象的基本操作
访问对象中的值:
1 | 对象.键 # 这种方式的属性名不用加引号 |
例:
1 | var obj = { |
对象的遍历:
遍历的意思就是将每一个值都访问一遍。
js提供了专门用来遍历对象的操作语法:
1 | for(var attr in obj){ |
例:
1 | var obj = { |
注意:遍历对象时,输出对象中的值,必须使用对象[代表键的变量]
这种形式来输出。
因为,如果使用.
来访问的话,是有歧义的:
1 | var obj = { |
如果使用一个变量来代替name
这个键:
1 | var obj = { |
此时,浏览器会将obj.a
识别为:我们正在访问obj中键为a
的值,.
后面的内容,表示对象中的键的名称,所以此时只能使用[]
的形式来访问:
1 | var obj = { |
此时[]
中的a
是一个变量,因为没有加引号,代表['name']
。
给对象添加属性:
1 | var obj = {}; |
打印对象的结果:
访问结果 |
---|
![]() |
如果设置的属性名是对象中已经存在的呢?
1 | var obj = { |
打印结果:
访问结果 |
---|
![]() |
删除对象中的键值对:
1 | delete 对象.键 |
例:
1 | var obj = { |
4、方法概念
对象中值的类型是没有限制的,可以是任意类型。当值不是函数的时候,我们将这个键值对叫做对象的属性,当值是一个函数的时候,我们将这个键值对叫做对象的方法。
1 | var obj2 = { |
name
就是对象obj2
的属性,study
就是对象obj2
方法
方法的访问和属性是一样的:
1 | console.log(obj2.study) |