函数就是功能、方法的封装

定义函数的四种方式

具名函数

  1. function 函数名(形式参数1, 形式参数2){
  2. 语句
  3. return 返回值
  4. }

匿名函数

  • =具名函数 - function ```javascript 函数名 (形式参数1, 形式参数2){ 语句
    return 返回值 }

or

let a = function(x, y){ return x+y }

  1. - 也叫函数表达式
  2. <a name="OfTeD"></a>
  3. ## 箭头函数
  4. ```javascript
  5. let f1 = x => x*x //只有一个参数时,圆括号是可选的
  6. let f2 = (x,y) => x+y // 参数大于 2 时,圆括号不能省
  7. let f3 = (x,y) => {return x+y} // 返回的语句大于 2 时,花括号不能省
  8. let f4 = (x,y) => ({name:x, age: y}) //加圆括弧表示整体

语法:
let f1 = () => {}
箭头右边输入参数,左边输出参数
注意入参与出参的书写规范
同样需要调用函数才能执行函数

构造函数

少用
所有函数都是Function构造出来的,包括Object、Array、Function

函数的要素

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

调用时机

区别:
函数自身 V.S. 函数调用
fn V.S. fn()

作用域

每个函数都会默认创建一个作用域
作用域的重点就是:就近原则
和函数执行无关的作用域叫做静态作用域,也叫做词法作用域(了解即可)
作用域通过画图可知

image.png
如上图,调用函数时 向上选取最接近函数调用的作用域,故f1()的值为a=3

全局变量 & 局部变量

  • 全局变量:
    • 声明在所有函数之外的变量
    • 函数内外均可访问全局变量
  • 局部变量:
    • 声明在函数内部
    • 函数外部不能访问函数内部的局部变量
  • window属性都是全局变量,其他都是局部变量

闭包

闭包=函数+自由变量
自由变量是指除了 全局变量和当前函数内部变量 之外的 变量
闭包是一种语言特性
有些语言不支持闭包,所以它的函数不能访问自由变量

如果一个函数用到了外部的变量,那么 这个函数加这个变量 就叫做闭包

image.png
如上图,函数f3打印了变量a(不在函数内部的变量),形成闭包

形式参数

形参可以变式地认为是变量声明

返回值

每个函数都有返回值;没写return,返回值是undefined
只有函数有返回值 ( 区分打印值和返回值)
返回值是函数执行之后才会被调用的 ;

调用栈

image.png

  • JS引擎在调用一个函数前
  • 需要把函数所在的环境推push到一个数组里
  • 这个数组叫做调用栈
  • 等函数执行完了,就会把环境弹(pop)出来
  • 然后return到之前的环境,继续执行后续代码

函数提升

针对具名函数即function开头的函数

  • function fn(){}
  • 不管你把具名函数声明在哪里,它都会跑到第一行
  • 注意:
    • let fn = function(){}
    • 这是赋值语句,右边的匿名函数声明不会提升,什么时候赋值fn什么时候才会声明

arguments(除了箭头函数)

是包含所有参数的伪数组

如何传 arguments

  • 调用 fn 即可传 arguments
  • fn(1,2,3) 那么 arguments 就是 [1,2,3] 伪数组
  • Array.from() 可以把任何非数组变为数组

this(除了箭头函数)

面对问题:
写一个函数时,需要获得对象,但不知道对象的变量名,因为该对象可能还未声明,那如何在不知道对象变量名的情况下拿到对象的引用?

土办法1:
利用参数;
因为参数可以代表一些东西,比如形参x和y,传入实参1和2 ,1和2是后来才传进去的;那用形参来代表这个对象可否?
image.png

JS方法:
通过额外的this做到;
person.sayHi()会把person自动传给sayHi,sayHi可以通过this引用person;即 person.sayHi() //this = person
image.png

隐晦理解:this其实就是个参数,但是个隐藏参数(call才能让它现身,小白只能隐身),而arguments是普通参数

如何传 this

  • 用 fn.call(xxx, 1,2,3) 传 this 和 arguments,默认第一个参数xxx是this,后面均为arguments
  • 如果不给任何的条件,this 默认指向 window
  • 如果传的 this 不是对象 ,JS 会自动封装成对象
  • 添加 ‘use strict’ 就不会有上述问题
  • 而且 xxx 会被自动转化成对象
  • this 是隐藏参数 arguments 是普通参数

用call写法的好处:
调用call的时候必须传入第一个参数作为this,所以能看清this是什么,但小白调用法看不到this是什么
用call调用的话第一个参数传什么对象,this就是什么对象
image.png
image.png

立即执行函数

  1. ! function (){//前面的操作符可以是:+ - !等运算符;永远推荐 '!'
  2. var a = 1
  3. console.log(a)
  4. }()

具备条件:

  • 匿名函数
  • 函数后面加 ‘(参数)’ 直接调用
  • 函数前面加 ‘!’