JS函数

61 阅读4分钟

函数是对象

定义函数

  • 具名函数
function 函数名(形式参数1,形式参数2){
语句
return 返回值
} 
  • 匿名函数
let a=function(x,y){return x+y}
  • 箭头函数
let f1=x=>x*x
let f2=(x,y)=>x+y
let f3=(x,y)=>{return x+y}
let f4={x,y}=>({name:x,age:y})  //不能直接返回对象,需要加个圆括号
  • 构造函数
let f=new function('x','y','return x+y')

函数自身和函数调用

let fn=()=>console.log('hi')
let fn2=fn;
fn2()

fn保存了匿名函数的地址,这个地址被复制给fn,fn2()调用了匿名函数。fn和fn2都是匿名函数的引用而已,真正的函数既不是fn也不是fn2。

函数的要素

调用时机

let a=1
function fn(){
console.log(a)
}
fn()

1

let a=1
function(){
console.log(a)
}
a=2
fn()

2

let a=1
function fn(){
console.log(a)
}
fn()
a=2

1

let a=1
funcion fn(){
setTimeout()=>{
console.log(a)
},0)
}
fn()
a=2

2

作用域

每个函数都默认创建一个作用域

function fn(){
let a=1
}
console.log(a)

a不存在,就算fn执行了,也访问不到作用域里面的a
全局变量,在顶级作用域声明的变量是全局变量,window的属性是全局变量,其他的都是局部变量。

作用域规则

  • 如果多个作用域有同名的变量a,就向上取最近的作用域,简称就近原则。查找a的过程与函数执行无关,但a的值与函数执行有关。

闭包

function f1(){
let a=1
function f2(){
>      let a=2
>      function f3(){
>      console.log(a)
>     }
  a=22
  f3()
 }
console.log(a)
a=100
f2()
}
f1()

如果这个函数用到了外部的变量,那么这个函数加这个变量就叫做闭包
上面的a和f3组成了闭包。

形式参数

  • 形式参数的意思就是非实际参数
  • 形参可认为是变量声明
function add(x,y){
return x+y
}

等价于

function add(){
var x=arguments[0]
var y=arguments[1]
return x+y
}

形参只是参数取名字,形参可多可少。

返回值

  • 每个函数都有返回值
  • 函数执行完了之后才会返回
  • 只有函数有返回值

调用栈

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

递归函数

function f(n){
return n!==1?n*f(n-1):1
}

微信图片_20220418121958.png

函数提升

function fn(){}

不管把具名函数声明在哪里,它都会跑到第一行。

let fn=function(){}

赋值语句,右边的匿名函数声明不会提升。

arguments和this

除了箭头函数不含arguments和this,其余函数都有。

微信图片_20220418122754.png

微信图片_20220418124821.png 没有前提的话 this默认指向window

  • 如何传arguments 调用fn即可传arguments
    fn(1,2,3)那么arguments就是[1,2,3]伪数组
  • 如何传this 目前可以用fn.call(xxx,1,2,3)传this和arguments,而且xxx会被自动转化成对象。
    使用use strict this传的就不会变成对象

微信图片_20220418125756.png

this

如果this传的不是对象js会帮你把它封装成对象
假设没有this

let person={
name:'Kacey',
sayHi(){
console.log('你好,我叫'+person.name)
}
}

我们可以直接保存了对象地址的变量获取'name',这个方法叫引用

person如果改名,引用就没办法使用。并且我们在声明类时,如果没有声明对象,那么对象的引用也没办法使用。此时就可以使用this。
JS在每个函数里加了this,这样每个函数都能用this获取一个位置对象的引用了。

let person={
name:'frank',
sayHi(/*this*/){
console.log('你好,我叫`+this.name')
}
}
person.sayHi=()

函数调用时有两种方法:

  • person,sayHi() 会自动把person传到函数里,作为this
  • person.sayHi.call(person) 需要自己手动把person传到函数里,作为this
function add(x,y){
return x+y
}
add.call(undefined,1,2)

为什么要写undefined的原因是,第一个参数要作为this,但代码里没有this,所以只能通过undefined占位。用null也可以。

this的两种使用方法

  • 隐式传递 fn(1,2) 等价于fn.call(undefined,1,2)
    obj.child.fn(1) 等价于obj.child.fn.call(obj.child,1)
  • 显示传递 fn.call(undefined,1,2)
    fn.apply(undefined,[1,2])

绑定this

console.log(this,p1,p2)
}
let f2=f1.bind({name:'kacey'})

f2就是f1绑定了this之后的新函数 f2()等价于f1.call({name:'kacey'})