《函数的要素》

103 阅读4分钟

函数的要素

每个函数都有这些东西

  • 调用时机
  • 作用域
  • 闭包
  • 形式参数
  • 返回值
  • 调用栈
  • 函数提升
  • arguments(除了箭头函数)
  • this(除了箭头函数)

一、调用时机

看到函数先直接跳过,一定要看到调用语句才会执行函数。

例1

  • 以下代码打印出什么?

image.png

  • 答:2,先a=2,再调用fn

例2

  • 以下代码打印出什么?

image.png

  • 答案:2
  • setTimeout是等一会执行
  • 比喻:一个人在打游戏,妈妈喊他吃饭,他说等一下去吃饭,意思是吃饭之前要把游戏打完。
  • 因此:这里setTimeout中的0表示执行完了马上做等一会做的事情

例3

  • 以下代码打印出什么?

image.png

  • 答案:6个6
  • 等一会执行,则是要for循环结束后马上执行,一共执行了6次,当for循环结束后i=6,因为只有一个i,所以是6个6

例4

  • 以下代码打印出什么?

image.png

  • 答: 0,1,2,3,4,5
  • 因为JS在 forlet一起用的时候会加东西
  • 每次循环就会复制一个ii=0、i=1....,6次循环一共生成除了6个新的i
  • setTimeout会打印出当时的值

作用域

每个函数都会默认创建一个作用域
作用域的重点就是:就近原则
例5

image.png

  • a不存在
  • fn执行了,也访问不到作用域里面的a,因为a的作用域就在{}
  • let的作用域:往前找到一个{,往后找到一个},出了{}就不存在

1.全局变量 V.S. 局部变量

  • 顶级作用域里声明的变量是全局变量
  • window的属性是全局变量 (如果是在window上面,则不需要写在顶级作用域,可以写在任何地方)
  • 其他都是局部变量

2.函数可嵌套
作用域也可嵌套,局部作用于套局部作用域\

2.1作用域规则

如果多个作用域有同名变量a

  • 那么查找a声明时,就向上取最近的作用域
  • 简称[就近原则]
  • 查找a的过程与函数执行无关
    和函数执行无关的作用域叫做静态作用域,也叫做词法作用域(了解即可)
  • 但a的值和函数执行有关
    在确定a的值时,才需要注意执行函数和a的先后顺序

image.png

闭包

定义:如果一个作用域用到了他外面的变量,就叫闭包

image.png

形式参数

1.形式参数的意思就是非实际参数

image.png

  • 其中 x 和 y 就是形式参数(xy并不代表任何实际的值,只代表参数的顺序和位置),因为并不是实际的参数

  • 调用 add 时, 1 和 2 是实际参数,会被赋值给 x y

  • 赋值:
    1.传统说法 JS传参分为 值传递 和 地址传递
    2.新的理解:不需要区分值和地址,所有都是根据内存图全部复制,值的复制和地址的复制
    3.也就是:根据内存图,Stack记的什么,就是什么

  • 形参可以认为是变量声明

image.png

形参可多可少
形参只是给参数取名字
没必要把形参全部声明完

image.png

返回值

1.每个函数都有返回值
返回值是执行之后才使用的

  • 没写return,返回值是undefined

image.png

  • console.log('hi')的返回值是undefined
    注意:只是打印了一个hi,返回值还是 undefined(区分打印值和返回值)
    因此下面hi()的值是undefined
  • 函数执行完了才会返回
  • 只有函数有返回值

调用栈

定义:

  • 在调用一个函数的时候,需要进入另外一个环境(函数)去执行它,执行完了再返回来
    调用栈实际就是记录进入一个函数后,回去应该回到什么地方
    就类似于打游戏存档读档
  • JS引擎在调用一个函数前
  • 需要把函数所在的环境推push到一个数组里
  • 这个数组叫做调用栈
  • 等函数执行完了,就会把环境弹(pop)出来
  • 然后return到之前的环境,继续执行后续代码

image.png

  • 由于每次进入一个函数都要记下来等会回到哪里
  • 所以把回到的地址写到栈里面
  • 如果进入一个函数还要进入一个函数,又把地址放到栈里面
  • 函数执行完了就弹栈,把地址弹出去,让函数执行结果根据地址回到相应位置

爆栈

如果调用栈压入的帧过多,程序就会崩溃

1.递归函数

1.1如果使用递归函数,那么很有可能把栈压满

image.png

理解递归:先层层递进计算,得到值后一层一层回归

函数提升

1.什么是函数提升

  • 如果函数声明是:function fn(){}
  • 不管你把具名函数声明在哪里,它都会跑到第一行
    一般是先声明在使用,但函数的声明会默认到第一行,因此可以先写调用后面跟声明

image.png

  • let不允许在已经有一个函数的情况下再声明addlet的特性是如果变量已经存在则不允许再声明)