如果想要弄懂函数下面这些东西你必须要弄懂!
目录:
1 调用时机
2.1 作用域
2.2 作用域的规则
2.3 !来给代码加点料
3.1 形式参数
3.2 来给代码加点料
4 返回值
5 调用栈
6 函数提升
7 立即执行函数
7.1 !来给代码加点料
1 调用时机
一个函数在调用的时机不同,那么它执行出来的结果也不同。
- 来举个栗子
let a = 1
function fn(){
console.log(a)
}
fn()
通过以上代码我们可以很容易的看出来最后执行fn()的时候打印出出1。我们接下里再提升一点难度,请看下方代码。
let a = 1
function fn(){
console.log(a)
}
a = 2
fn()
这回大家猜猜看执行最后一句fn()的时候会打印出多少?肯定是打印出2的,至于为什么呢,当然是在执行到第5句的时候a = 2,在这个时候a已经不再是当初的a了因为a被重新赋值a = 2了。就这么简单。
- 来!难度升级
elt a = 1
function fn (){
setTimeout(()=>{
console.log(a)
},0)
}
fn()
a = 2
细心的小伙伴可能已经看出来了这一切,这里我们多了一句setTimeout,setTimeout的意思就是稍后执行,稍后执行是什么意思呢?稍后,就是当前任务执行完再执行。也就是代码执行完了之后再执行打印,说以最后打印出2。
2 作用域
每个函数都会默认创建一个作用域。
- 老规矩 举个栗子
function fn(){
let a = 1
}
console.log(a)
执行这段代码我们会得到一个‘a’不纯在,就算fn执行了也访问不到作用域里面的‘a’。因为‘a’的作用域在花括号里面。‘let’的作用域非常的好找,往前找一个正的花括号,往后找一个反的花括号,这两个花括号之间就是它的作用域。出了这个空间它就不纯在。
2.1 作用域的规则
- 如果多个作用域有同名变量a
那么查找a的声明时,就就向上取最近的作用域。简称“就近原则”。
查找a的过程与函数无关,但是a的值与函数执行有关。
2.2 !来给代码加点料
上面有讲到作用域(局部变量)现在在来讲讲全局变量
在顶级的作用域声明的变量是全局变量,window的属性是全局变量,其他的都是局部变量
- 全局变量
function f2(){
window.c = 2
let b
}
f2()
function f1(){
console.log(c)
}
f1()
通过以上代码我们可以看出,在f1里面打印f2里面的东西依然可以。这就是因为window是一个全局属性,把c挂到了window上面,c就自动的变成了一个全局变量。这就是为什么Object可以直接用,因为他是window.Object,parseInt也是如此,parseInt是window.parseInt。
3 形式参数
形式参数的意思就是非实际参数。
function add(){
return x+y
}
add(1,2)
3.1 !来给代码加点料
形式参数就只是给代码取一个名字而已,里面的内容可多可少。
4 返回值
每一个参数都有返回值,不存在没有返回值的函数。
- 少废话,举例子!
function hi(){
console.log('hi')
}
hi()
看了以上代码有的小可爱可能就会问了,上面代码不是没有写return嘛。注意!没有写return返回值就是undefined。返回值是在执行之后才会出现的,你不执行就不存在所谓的返回值。
4.1 !来给代码加点料
function hi(){
return console.log('hi')
}
hi()
看看以上代码返回值是多少?返回值为undefined。
看到没返回值是不是undefined,至于那个hi嘛,那个是打印值,返回值是返回值,打印值是打印值。
函数执行完了之后才会有返回值,也自有函数才有返回值。
5 调用栈
JS引擎在调用一个函数之前,需要把函数所在的环境push到一个数组里面去,这个数组就叫做调用栈。等函数执行完,就会把环境弹出(pop)出来,然后return到之前的环境,继续执行代码。
也就是说在调用一个函数的时候,我们需要到另外一个环境去执行它,执行完了之后再返回回来。函数是进到一个函数之后再返回回来,是这么个模型。
这个时候我们要是进入一个函数再进入一个函数再再进入一个函数,这是需要返回的时候函数就懵逼了,它不知道该返回哪里了。所以调用栈的作用就是进入以后函数之后该返回哪里。
当进入一个函数的时候需要把一个函数地址先存进来,存得多了就需要一个数组来保存,保存函数所在的环境就叫调用栈。
6 函数提升
- 什么是函数提升
在使用“function fn(){}” 的时候不管你把具名函数声明在哪里,它都会跑到第一行。
- 什么不是函数提升
在使用“let fn = function(){}”的时候,这是赋值,右边的匿名函数声明不会提升。
7 立即执行函数
在我们需要局部变量的时候,又不想要全局函数的时候就可以用到它。
- 先来举个栗子
function fn(){
var a = 1
}
这里我们通过了一个函数来声明一个局部变量,的确局部变量的目的达到了,但是!又多了一个函数fn全局变量。
聪明的小朋友可能就会想到,我直接创建一个匿名函数,后面直接调用不就可以了嘛,来我们看一下结果。
看到没!报错了,因为JS认为这个语法是错的。
但是如果在这个语法前面加上一个“操作符”就是对的,怎么加?看下面栗子!
+ function (){
var a = 1
console.log(a)
} ()
在语法前面加上一个操作符,问题就解决了。JS会先声明一个匿名函数,再执行这个匿名函数。由于这个匿名函数没有retunr所以返回值是NaN,但是我们并不关心它返回什么,我们只在意局部变量。
7.1 !来给代码加点料
在上个语法当中我们加操作符“+”“-”“1”或者“1*”都可以,但是单独一个“*”就不行,只需要做一个运算就可以。注意!最建议使用“!”
新版JS创建一个局部变量最简单!
{
let a = 1
console.log(1)
}
看到没,新版js创建一个局部函数就这么简单,直接两个花括号就解决了。