JavaScript的函数
和数学的函数没有关系,就是一个JavaScript里面的数据类型,是复杂数据类型的一种。
函数就相当于一个盒子用来承载一段代码,当你需要执行一段代码的时候只要互换这个盒子就可以对一段代码得封装
一个完整的函数包括两部分:
- 把代码装在盒子里
定义函数 - 使用盒子里的代码
调用函数
函数的分类
声明式函数
function 函数名() {}
function : 声明函数的关键字
空格 : 必须有,分隔关键字和函数名的
函数名 :这个函数的名字(遵循变量命名规则和规范)
(): 参数
{} : 代码段
赋值式函数
var 函数名 = function () {}
var : 声明变量
函数名 :这个函数的名字(遵循变量命名规则和规范)
function : 声明函数的关键字
空格 : 必须有,分隔关键字和函数名的
(): 参数
{} : 代码段
声明式函数和赋值式函数的区别
- 书写不同
- 调用时有差异
- 打印时,声明式会带上函数名;赋值式没有
函数的调用
两种声明方式,调用的方式是一样的,区别在于调用的时机不一样
声明式函数,可以在声明之前调用,也可以在声明之后调用
fn1() //111
function fn1(){
console.log('111')
}
fn1() //111
赋值式函数,只能在声明后调用,声明之前会报错
fn() //报错
var fn=function()(){
console.log('111')
}
fn() //111
函数的特点
- 代码复用
一次书写,多次使用 - 时机把握
我想什么时候用,就什么时候使用 - 代码简洁
把一类代码放在一起
函数的参数
参数的分类
形参
写在函数定义阶段的()里面就相当于一个只能在函数内部使用的变量起名遵循变量命名规则和规范值由函数的实参来决定
实参
写在函数调用阶段的()里面就是一个准确的值,是为了给函数的形参进行赋值的
function fn(a,b){//形参
console.log(a,b)
}
//实参
fn(1,2) //打印1 2
fn(2,3) //打印2 3
形参和实参,都可以写很多个
多个的时候,中间用( , )分隔,按照从左到右的顺序一一对应
函数参数对的个数关系
一样多
按照从左到右的顺序一一对应
实参多
前面的按照顺序一一对应
function fn(a){
console.log(a)
}
fn(1) //1
fn(2,3)//2
多出来的实参,在函数内部没有形参的值所以不能直接使用
形参多
前面的按照顺序一一对应
function fn(a,b,c){
console.log(a,b,c)
}
fn(1) //1 undefined undefined
fn(2,3) //2 3 undefined
多出来的形参因为没有实参赋值所以使用的时候就是undefined
函数的返回值
return 需要返回的内容
function add(a,b){
return a+b;
}
var sum=add(1,2)
console.log(sum) //3
函数默认返回值
我们可以不写 return 函数会默认在代码段的最后一行 写上 return undefined
函数的预解析
函数的预解析,可能会遇上同名变量提升(变量的预解析) 直接以函数为主
JS编程时应该尽量避免变量名和函数名同名,否则会发生相互覆盖的问题.从实际测试效果来看,这种覆盖可以分为两种情况:
- 定义变量时只使用var定义变量,不分配变量初始值,此时函数的优先级更高,函数会覆盖变量
- 定义变量时为变量指定了初始值,此时变量的优先级更高,变量会覆盖函数
var fn='hhh' //有提升
console.log(fn) //没有
fn() //没有
function fn(){ //有
console.log(1)
}
fn() //没有
function fn(){ //第一行
console.log(1)
}
var fn //第二行 没意义
fn='hhh' //这行很重要,直接将变量保存的函数,更改为了 'hhh'
console.log(fn) //按照分析,此处应该打印 'hhh'
fn() //按照分析,此处fn 的应该为'hhh' 所以会报错 fn is not a function
fn() //按照分析 此处fn 的值还是'hhh',所以还会报错 fn is not a function
递归函数
在函数内部调用自己,调用自身
要想写一个正确 的递归函数,需要在递归内部,写上,返回点(到某个条件,停止递归)
function fn(){
if(满足条件){
fn()
}
if(不能满足条件1,满足条件2){
//结束递归函数
}
}
作用域
作用是有使用区间的,变量不是说明之后在哪里都可以用,他有一个使用的范围,我们把这个范围叫做 作用域
作用域的分类
全局作用域
JS给我们提供了一个叫做window的全局作用域,可以理解为整个script标签内的作用域就是,全局作用域
全局变量都会挂载到 window 对象上
局部作用域
在JS中,有且只有函数能够创建,局部作用域(函数作用域),局部作用域开始和结束位置,就是函数代码段开始和结束的位置
在局部作用域(函数作用域)内,声明的变量叫做局部变量
局部变量,不会挂载到window对象上
作用域链
变量的访问规则
变量访问会,现在当前作用域内查找,找到拿来直接用,如果过没有找到会去上层作用域查找
如果上层作用域没找到,会继续上层作用域 的上层作用域内查找
var num=100
function fn(){
function fn1(){
console.log(num)
}
fn1()
}
fn()
/*
首先在fn1 这个作用域内 访问变量
会在当前作用内查找num变量,如果访问不到,则返回上一层作用域查找
在fn 这个作用域内 访问变量 如果有则直接使用,没有返回上一层作用域
最后,在全局变量中,访问变量,查找变量num 找到了 num=100
故此,打印100
*/
变量的赋值规则
变量赋值会先在当前作用域内查找,找到了直接拿来的赋值,如果没有,会去上层作用域内查找,找到了直接赋值
如果上层作用域也没有找到,会继续去上层作用域 的高层作用域内找,找到了直接赋值,没找到继续往上寻找
如果找到了全局变量内,还是没有找到变量,那么会直接将变量定义为在当前作用域内(全局作用域),然后赋值
function fn() {
function fn1() {
num = 1000;
}
fn1()
}
fn()
console.log(num)
/*
首先访问 fn1这个作用域,给变量num赋值
那么会在当前的作用域查宅
*/