函数全解

468 阅读3分钟

函数的环境

什么是函数?

子程序 最开始程序员写的程序大部分是汇编,后来有C语言C++等,这个阶段没有函数的概念,但有一个子程序的概念,(几行代码完成一个功能,给这几行代码起个名字,那时候不叫函数,叫子程序)

数学中的函数

数学中的函数有三个要素:定义域(A),值域(B),法则(f) 数学函数 假设函数为f,假设输入A集合中的某个值,那么必定有一个输出B集合中的某个值

f(A[3])=B[3] //一旦规则确定,不管你输入多少次A[3],输出都是B[3]
f() //在数学中是不合法的,因为没有输入
如果你的函数符合数学函数的定义,就是函数式的

函数中的返回值是由什么确定的

调用时输入的参数params
定义时的环境env

闭包

闭包能让一个函数维持住一个变量,但并不能维持这个变量的值
对象也可以维持住一个变量,如果一门语言不支持闭包,你可以用对象

let obj = {
    i: 0,
    fn() {
        this.i += 1
        console.log(`我是obj的闭包i:${this.i}`)
    }
}
const handle = function () {
    let i = 0
    return function () {
        i++
        console.log(`我是实例化的闭包i:${i}`)
    }
}

obj.fn()
obj.fn()
let fn2 = handle()
fn2()
fn2()

this的值

如果你不知道什么是this
请参考阮一峰老师的文章
箭头函数this是环境,非箭头函数的this是一个隐式参数

const fn = function (p1, p2) {
    console.log(this, p1, p2)
}
fn(1, 2)//隐式传参,不写会自动传undefined
fn.call(undefined, 1, 2)//显示传参,如果为undefined,浏览器会帮我们将this指向全局window

学会call,bind,apply等调用方法指定this,用来加深this的理解
你得知道函数是怎么调用的,你才能确定this的值

递归与记忆化

递归 递归的特点就是自己调用自己,并且有一个结束条件,不然就是无限递归,永远无法拿到结果
所有的递归都可以用循环实现,我们可以认为尾递归是另一种for循环的写法 js中不管我们是否进行了尾递归优化,它都会帮我们压栈,我们可以使用memorize进行函数缓存

memorize实现

const memo = (fn) => {
    function memoed(key) {
        memoed.cache[key] = memoed.cache[key] || fn.apply(this, arguments)
        return memoed.cache[key]
    }
    memoed.cache = {}
    return memoed
}
const x = memo((x) => {
    console.log('执行了')
    return x * 2
})
console.log(x(1))//第一次进来打印执行了
console.log(x(1))//不会打印,说明没有再次执行传进去的函数,而是直接拿上次缓存的结果
console.log(x(1))//不会打印
console.log(x(1))//不会打印
console.log(x(2))//发现没有缓存,调用函数,缓存函数结果

柯里化

让所有的函数只接受一个参数

单一参数有什么意义?

怎么支持两个参数

使用闭包

const add = function (a){
	return function(b){
		return a+b
	}
}
add(1)(2)//输出3

柯里化一个函数

const curring = (fn, params = []) => {
    return (arg) => {
        const newParams = params.concat(arg)
        if (fn.length === newParams.length) {
            return fn(...newParams)
        } else {
            return curring(fn, newParams)
        }
    }
}
const addTow = (a, b) => a + b
const addThree = (a, b, c) => a + b + c
const newAddTow = curring(addTow)
const newAddThree = curring(addThree)
console.log(newAddTow(1)(2))
console.log(newAddThree(1)(2)(3))

高阶函数

把函数作为参数或返回值的函数就是高阶函数
js内置的高阶函数

Function.prototype.bind
Function.prototype.apply
Function.prototype.call
Function.prototype.sort
Function.prototype.map
Function.prototype.filter
Function.prototype.reduce
function fn (){
	console.log(this)
    console.log(arguments)
}
bind.call(fn,{name:'tj'},2,3,4)
apply.call(fn,{name:'tj'},[2,3,4])
call.call(fn,{name:'tj'},2,3,4)