JS函数概览(二)

131 阅读2分钟

返回值

每个函数都有返回值

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 到之前的环境,继续执行后续代码 例如:

2.png

递归函数

阶乘

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

先递进,再回归

递归调用栈

3.png 爆栈:如果调用栈中压入的帧过多,程序就会崩溃

  • 递归函数的调用栈很长,但是每个浏览器的调用栈都是有限的

函数提升

什么是函数提升

function fn(){}
//不管你把具名函数声明在哪里,它都会跑到第一行

什么不是函数提升

let fn = function(){}
//这是赋值,右边的匿名函数声明不会提升
  • let不能跟函数声明同时存在

若同时有var和 函数

var add

1641828947(1).png

var add =1

微信图片_20220110233648.png

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 程序员寻求各种办法
  • 最终发现,只要在匿名函数前面加个运算符即可
  • !、~、()、+、- 都可以
  • 但是这里面有些运算符会往上走
  • 所以推荐永远用 ! 来解决 例如:

1641830215(1).png

1641830343(1).png

这样更方便:

555.png