定义函数的四种方式
具名函数
function 函数名(形式参数1, 形式参数2){
语句
return 返回值
}
匿名函数
- =具名函数 - function
```javascript
函数名 (形式参数1, 形式参数2){
语句
return 返回值 }
or
let a = function(x, y){ return x+y }
- 也叫函数表达式
<a name="OfTeD"></a>
## 箭头函数
```javascript
let f1 = x => x*x //只有一个参数时,圆括号是可选的
let f2 = (x,y) => x+y // 参数大于 2 时,圆括号不能省
let f3 = (x,y) => {return x+y} // 返回的语句大于 2 时,花括号不能省
let f4 = (x,y) => ({name:x, age: y}) //加圆括弧表示整体
语法:let f1 = () => {}
箭头右边输入参数,左边输出参数
注意入参与出参的书写规范
同样需要调用函数才能执行函数
构造函数
少用
所有函数都是Function构造出来的,包括Object、Array、Function
函数的要素
- 调用时机
- 作用域
- 闭包
- 形式参数
- 返回值
- 调用栈
- 函数提升
- arguments(除了箭头函数)
- this(除了箭头函数)
调用时机
区别:
函数自身 V.S. 函数调用
fn V.S. fn()
作用域
每个函数都会默认创建一个作用域
作用域的重点就是:就近原则
和函数执行无关的作用域叫做静态作用域,也叫做词法作用域(了解即可)
作用域通过画图可知
如上图,调用函数时 向上选取最接近函数调用的作用域,故f1()的值为a=3
全局变量 & 局部变量
- 全局变量:
- 声明在所有函数之外的变量
- 函数内外均可访问全局变量
- 局部变量:
- 声明在函数内部
- 函数外部不能访问函数内部的局部变量
- window属性都是全局变量,其他都是局部变量
闭包
闭包=函数+自由变量
自由变量是指除了 全局变量和当前函数内部变量 之外的 变量
闭包是一种语言特性
有些语言不支持闭包,所以它的函数不能访问自由变量
如果一个函数用到了外部的变量,那么 这个函数加这个变量 就叫做闭包
如上图,函数f3打印了变量a(不在函数内部的变量),形成闭包
形式参数
形参可以变式地认为是变量声明
返回值
每个函数都有返回值;没写return,返回值是undefined
只有函数有返回值 ( 区分打印值和返回值)
返回值是函数执行之后才会被调用的 ;
调用栈
- 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是后来才传进去的;那用形参来代表这个对象可否?
JS方法:
通过额外的this做到;
person.sayHi()会把person自动传给sayHi,sayHi可以通过this引用person;即 person.sayHi() //this = person
隐晦理解: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就是什么对象
立即执行函数
! function (){//前面的操作符可以是:+ - !等运算符;永远推荐 '!'
var a = 1
console.log(a)
}()
具备条件:
- 匿名函数
- 函数后面加 ‘(参数)’ 直接调用
- 函数前面加 ‘!’