返回值
每个函数都有返回值
function hi(){ console.log('hi') }
hi()
//没写 return,所以返回值是 undefined
function hi(){ return console.log('hi') }
hi()
//返回值为 console.log('hi') 的值,即 undefined(console.log是打印值)
- 函数执行完了后才会返回
- 只有函数有返回值
- 1+2 返回值为 3 (错)
- 1+2 值为 3 (对)
调用栈
什么是调用栈
- JS 引擎在调用一个函数前
- 需要把函数所在的环境 push 到一个数组里
- 这个数组叫做调用栈
- 等函数执行完了,就会把环境弹(pop)出来
- 然后 return 到之前的环境,继续执行后续代码 例如:
递归函数
阶乘
function f(n){
return n !== 1 ? n* f(n-1) : 1
}
理解递归
f(4)
= 4 * f(3)
= 4 * (3 * f(2))
= 4 * (3 * (2 * f(1)))
= 4 * (3 * (2 * (1)))
= 4 * (3 * (2))
= 4 * (6)
24
先递进,再回归
递归调用栈
爆栈:如果调用栈中压入的帧过多,程序就会崩溃
- 递归函数的调用栈很长,但是每个浏览器的调用栈都是有限的
函数提升
什么是函数提升
function fn(){}
//不管你把具名函数声明在哪里,它都会跑到第一行
什么不是函数提升
let fn = function(){}
//这是赋值,右边的匿名函数声明不会提升
- let不能跟函数声明同时存在
若同时有var和 函数
var add
var add =1
arguments 和 this
每个函数都有,除了箭头函数
function fn(){
console.log(arguments)
console.log(this)
}
如何传 arguments
- 调用 fn 即可传 arguments
- fn(1,2,3) 那么 arguments 就是 [1,2,3] 伪数组
如何传 this
- 目前可以用 fn.call(xxx, 1,2,3) 传 this 和 arguments
- 而且 xxx 会被自动转化成对象(JS 的糟粕)
- this默认指向window
- 如果传的this不是对象,JS自动封装成对象
- 加'use strict'不会自动转化为对象
让函数获取对象的引用
let person = {
name: 'frank',
sayHi(){
console.log(`你好,我叫` + this.name)
}
}
person.sayHi()//此种调用为小白调用
//你好,我叫frank
person.sayHi.call(person)//大师调用法
person.sayHi.call({name:'jack'})
//你好,我叫jack
推荐用大师调用法
几种方法对比,链接2
箭头函数
里面的 this 就是外面的 this
console.log(this) // window
let fn = () => console.log(this)
fn() // window
就算你加 call 都没有
fn.call({name:'frank'}) // window
立即执行函数
原理
- ES 5 时代,为了得到局部变量,必须引入一个函数
- 但是这个函数如果有名字,就得不偿失
- 于是这个函数必须是匿名函数
- 声明匿名函数,然后立即加个 () 执行它
- 但是 JS 标准认为这种语法不合法
- 所以 JS 程序员寻求各种办法
- 最终发现,只要在匿名函数前面加个运算符即可
- !、~、()、+、- 都可以
- 但是这里面有些运算符会往上走
- 所以推荐永远用 ! 来解决 例如:
这样更方便: