1.认识函数:
函数是js中的一种数据类型,是一个复杂(引用)数据类型,单词是function
曾经给一个变量可以赋值的有:字符串类型、布尔类型、数值类型等,那既然函数是一个数据类型,自然也是可以赋值给变量。
要想理解函数,你可以这样理解:
我们可以把函数看作是一个盒子,在这个盒子中可以写很多很多的代码,当你需要用到这段代码的时候我们只需要找到这个盒子即可。
2.封装:
1. 把一段代码放到一个盒子中,这种行为我们一般就叫做封装,装到盒子中其实装到函数中,所以把代码放到函数中这种行为我们一般叫做封装函数
2.在程序中使用函数必须要做的2件事情
1).如何把一段代码放到盒子中(函数中)========定义函数
2).如何找到这个盒子(找到这个函数),找函数的目的是为了执行盒子中的代码====调用函数
3.如何定义函数?
方式一:声明式函数
语法:function 函数名(){代码段}
function=====这个单词是定义函数的关键字,告诉浏览器我这里要写一个函数了
函数名====你自己随便去起(符合命名规则和规范即可)
()====必须写
{}====在{}中就是你存放到这个函数中的代码片段
方式二:赋值式函数(函数表达式)
语法:var 变量名 = function(){代码段}
注意点:赋值式function后面不要跟名字,这种有些语言中也叫做匿名函数
4.如何调用函数?
调用函数的主要目的:是为了执行函数中的代码
语法:函数名()
注意:无论是声明式还是赋值式,他们的调用语法都是一样的
声明式函数调用在前面还是后面都可以
赋值式函数调用在前面会报错
<script>
// 定义函数 声明式函数
function fn1() {
console.log('====================');
console.log('我是fn1函数');
console.log('====================');
}
// 调用函数
fn1()
fn1()
// 赋值式函数
var fn2 = function () {
console.log('我是赋值是函数');
}
fn2()
fn2()
// fn1()
// // 声明式函数
// function fn1(){
// console.log('这是声明式函数fn1');
// }
// fn1()
// fn2()
// // 赋值式函数
// var fn2 = function(){
// console.log('这是赋值式函数fn2');
// }
// fn2()
</script>
5.参数:
形参:在定义函数的小括号中写的变量,这个变量仅限于函数内部使用
实参:在调用函数的时候小括号中写的真实的数据
实参是给形参赋值的
注意: 参数可以写很多个,中间通过逗号隔开。
实参给形参赋值的时候是按照从左到右的顺序依次赋值。
当实参个数和形参个数一致的时候:我们可以保证每个形参都有值
当实参个数比形参个数少的时候:从左到右依次赋值,后面多余的形参值执行结果为 undefined
当实参个数比形参多个时候,后面多出来的数据是无用的,是无意义的
尽量保证实参个数和形参个数一致,这样一定不会出问题。
<script>
function chengfabiao(x) {
for (var i = 1; i <= x; i++) {
for (var j = 1; j <= i; j++) {
document.write(i + '*' + j + '=' + (i * j) + ' ')
}
document.write('<br>')
}
}
// 调用阶段 小括号中9就是实参,实参会赋值给形参
chengfabiao(9)
document.write('==========================<br>')
chengfabiao(3)
document.write('==========================<br>')
chengfabiao(5)
</script>
例子:
封装一个函数,这个函数是用来输出任意2个数之间的所有的偶数的
设计函数:
1.先明确函数的功能(得到2个数之间所有的偶数)
2.思考是否需要参数(是否有未知的可变的数据)需要参数的,而且需要2个
<script>
// 得到的是x-y之间所有的偶数
function fn2(x, y) {
for (var i = x; i <= y; i++) {
if (i % 2 === 0) {
console.log(i);
}
}
}
//这里输出100~200之间的所有偶数
fn2(100,200)
</script>
5.函数的返回值
返回值的语法:return 要返回的数据
注意:返回值就是函数的结果
return有2个作用:
1.给调用者产出(返回)一个结果
2.可以起到中断函数的作用(在函数执行过程中只要碰到return,那么函数就会立即停止,return后面代码不会执行)
注意:如果不需要刻意中断,return单词最好写在函数代码块的最后面。
<script>
function fn(x, y) {
var sum = x + y
// 将求和的结果返回出去,给到调用者,将来调用者想怎么用就怎么用
return sum
}
// 调用了fn函数,并把fn函数的返回值(结果)保存到了res变量中,此时res中其实保存的就是return之后的数据
var res1 = fn(1, 2)
alert(res1)
//打印到控制台
var res2 = fn(2, 3)
console.log(res2);
//打印到页面
var res3 = fn(2, 3)
document.write(res3)
</script>
6.预解析
js是一门解释型语言(H5是一种标签语言),在真正执行代码之前,会先对代码进行通读并作解释,读过一遍之后才会放到浏览器中去执行
预解析只解析2个东西
1.var声明的变量(会对var声明的变量进行提前声明,但是暂时不赋值,只有到了执行阶段才会进行赋值操作)
2.声明式函数
var声明:
1)给出以下代码:
var num = 10
console.log(num);
以上代码的执行的过程:
1.先预解析(先通读代码)
读第一行:是否需要预解析(需要)
因为发现有var关键字,所以需要预解析,
这里就会告诉浏览器,这里定义了一个变量,叫做num,但是目前不赋值
读第二行:不需要
2.再执行代码
执行第一行:num = 10,直接对num变量进行赋值操作,赋值为10
执行第二行:直接输出num的值即可。
其实上面代码的执行过程如下:
var num
num = 10
console.log(num);
2)给出以下代码:
console.log(num);
var num = 10
console.log(num);
以上代码执行的过程:
1.先预解析:
读第一行:不用预解析
读第二行:发现有var关键字,所以需要预解析
告诉浏览器这里创建了一个名字叫做num的变量,但是不赋值
读第三行:不用预解析
2.再执行代码
执行第一行:console.log(num);
因为在预解析阶段一定创建好了num这个变量了,但是并没有进行赋值操作,所以此时会打印出undefined
执行第二行:num = 10
执行第三行:console.log(num);======第二行已经赋值完成,所以输出10
其实上面代码的执行过程可以演变成如下代码:
var num
console.log(num);
num = 10
console.log(num);
注意:如果没有预解析的话,第一句代码一定是会报错的。
预解析这种行为我们也可以叫做变量提升(声明提前)
声明式函数:
声明式函数的预解析(对函数名进行提前声明,并且赋值为一个函数)
声明式函数无论是在定义前调用还是在定义后调用都不会保存:是因为声明式函数会提前预解析的。
1)给出以下代码:
fn()
function fn() {
console.log('fn函数');
}
fn()
以上代码的运行过程:
1.预解析
读第一行:不用预解析
读第二行:是一个声明式函数,所以需要预解析
告诉浏览器我这里创建一个名字叫做fn的变量,并且赋值为一个函数
读第三行:不用预解析
2.执行
执行第一行:fn(),因为在预解析阶段已经创造好这个函数了,所以就可以正常执行函数里边的语句
执行第二行:在预解析阶段已经执行过了,所以直接跳过
执行第三行:fn()=====正常调用函数,执行即可
以上代码可以演变成如下:
function fn(){
console.log('fn函数');
}
fn()
fn()
2)给出以下代码:
fn()
var fn = function () {
console.log('我是fn函数');
}
fn()
以上代码的运行过程:
1.预解析阶段:
读第一行:不需要预解析
读第二行:因为碰到了var所以需要预解析,
告诉浏览器这里创造了一个名字叫做fn的变量,但是不赋值
所以此时:fn = undefined
读第三行:不需要预解析
2.执行阶段:
执行第一行:fn()
因为在预解析阶段已经提前创建好了fn变量了,但是fn的值为undefined
所以这里fn()=undefined()
7.函数的默认值
写默认值的目的是为了让调用的时候对这个形参赋值和不赋值都可
如果形参中有些变量有默认值有些变量没有默认值,那么我们一般建议有默认值的形参放到最后。
//此时定义一个变量名为fn的函数,默认定义形参a,b的值分别为10和20
function fn(a=10,b=20,c,d){
console.log(a,b,c,d);
}
//此时调用fn,输出的a为10,b为 20
fn()
//给变量a,b传递实参100,200,调用结果后发现结果为传递的值,说明函数的默认值是可以被修改的
fn(100,200,300,400)
8.模板字符串
符号:反引号``
特点:
模板字符串支持换行
可以识别变量,${变量}
9.解构赋值
解构:
主要作用:为了快速从数组或者对象中获取数据的一种方式
语法:let 解构 = arr
语法:let [变量1,变量2。。。。。] = arr
注意:等号左边的叫做解构,右边的叫数组
按照索引顺序,依次给解构中的变量挨个赋值。
//定义一个数组名为arr的数组
let arr=[100,200,300,400]
//进行解构
let a=arr[0]
let b=arr[1]
console.log(a);
console.log(b);
数组怎么写,解构就怎么写,把数据换成变量即可
对于多维数组也是一样的
//定义一个数组名为arr的多维数组
let arr = [1, 2, [3, 4, [5, 6, [7, 8]]]]
//假设要输出2,4,6,8的值,分别赋值为a,b,c,d;使用解构
let a = arr[1]
let b = arr[2][1]
let c = arr[2][2][1]
let d = arr[2][2][2][1]
console.log(a);
console.log(b);
console.log(c);
console.log(d);
解构对象:
等号右边叫对象,等号左边叫解构
语法:let { } = 你要解构的目标
语法:let {key1,key2,key3.....} = obj
解构对象的时候{}中写的是键名,有时候我们可能想给键重新起一个名字
要想给键重新起一个名字
语法:let {key1:新名字,key2,key3.....} = obj
//创建一个对象
let obj={
name:'钟离',
age:'6400',
height:'182',
weight:'120',
}
//进行解构
let rename =obj.name
//得到名字钟离
console.log(rename);
//解构也可以将原本的键名进行修改
let{name:wukalaka,age:reage}=obj
//从打印结果来看,成功将其键名进行修改
console.log(wukalaka,reage);
10. 扩展运算符
符号:(三个点...)
在不同的场合之下,有时候是展开功能,有时候就是合并功能
主要作用就是为了展开或者合并数据,一般用在有数据集合或者函数的参数的地方
数据集合:可以存储很多条数据的。(数组、对象)
//定义一个新数组arr
var arr1 = [100, 200, 300, 400]
var arr2 = ['hello', 'world']
var arr3 = [...arr1, ...arr2]
console.log(arr3);
console.log(...arr2);
注意:扩展运算符号在函数中,用在形参叫做合并,收集,会收集所有的实参的,所以一般建议写在形参的最后
用在实参:叫展开
//在函数的形参中;...表示合并将其整合成一个数组进行输出
function fn(...a){
console.log(a);
}
fn(10,20,30,40)
11.作用域
作用域:其实就是一个东西可以起作用、可以生效的范围,代码中谈作用域一般谈的都是变量的作用域,也就是研究一个变量可以使用的范围。
作用域的分类:
1.全局作用域
你打开一个html文件,整个页面就是一个全局作用作用域,全局的单词叫做window
定义在全局当中的变量他的生命周期:就是整个页面,只要页面不关闭。变量就会一直存在
2.局部作用域(私有作用域)
目前对于我们而言:只有函数才可以生成私有作用域。也就是说定义在函数内部的变量就仅限于函数内部使用。变量定义在哪个地方;作用域就在哪个区域,全局作用域最大。
变量的3个行为:
1.变量的定义(定义变量):带有var关键字的我们就叫做定义变量
var num;==================算定义(只是为赋值)
var num = 10;===========算定义(定义并赋值)
num = 20;===============不算定义(因为没有带var关键字)
2.访问变量:当你需要拿到这个变量的值的时候我们就叫做访问
console.log(num);=========算访问
num = num+10;============算访问(num+10这句话中涉及了访问)
num++==================算访问(因为需要拿到num的值然后才行+1操作)
3.变量的赋值:当你需要给一个变量赋值的时候
num = num+10;=========算(将num+10的结果又重新给到了num)
num = 200 =============算(把200这个数据给到了num)
变量在作用域中的三个机制:
1.变量在作用域中的定义机制
定义在哪个作用域中的变量他就属于哪一个作用域,那么该变量就只能在该作用域和后代作用域中使用,不能在父级父级作用域或者其他作用域中使用。
2.变量在作用域中的访问机制
当我们需要访问一个变量的值的时候,首先会现在自己的作用域查看,如果有就使用,就停止查找,如果没有就会去'父级'作用域查看,如果有就使用,就停止查找,如果还没有,就会一直一层一层'往上'查找,直到查找到全局作用域为止,如果全局依然没有,代码就报错。
3.变量在作用域中的赋值机制
当我们需要给一个变量赋值的时候,首先会现在自己的作用域查看有没有这个变量,如果有就赋值,停止,如果没有就去'父级'作用域查找,如果父级有变量,就赋值,停止
如果父级依然没有,就会一直一层一层'往上'找,直到找到全局为止,如果全局依然没有这个变量,那么他会自动的把这个变量给我们创造成一个全局变量