函数

基础知识

声明定义

在JS中函数也是对象函数是Function类的创建的实例,下面的例子可以方便理解函数是对象。

const fn = new Function('title', 'console.log(title)')
fn('mkimq')

标准语法是使用函数声明来定义函数

function fn(num) {
    console.log(num)
}

对象字面量属性函数简写

const user = {
    name: null,
    getName: function (name) {
        return this.name
    },
    // 简写
    setName(name) {
        this.name = name
    }
}

使用let/const时不会压入window

const fn = function() {
    console.log('mkimq')
}

window.fn()

匿名函数

函数是对象所以可以通过赋值来指向到函数对象的指针,当然指针也可以传递给其他变量,注意后面要以;结束。下面使用函数表达式将 匿名函数 赋值给变量

const fn = function () {}

const fn2 = fn

标准声明的函数优先级更高,解析器会优先提取函数并放在代码树顶端,所以标准声明函数位置不限制。 标准声明优先级高于赋值声明

立即执行

立即执行函数指函数定义时立即执行

  • 可以用来定义私有作用域防止污染全局作用域
(function () {
    var web = 'mkimq.com'
})()

console.log(web) // web is not defined

使用 let/const 有块作用域特性,所以使用以下方式也可以产生私有作用域

{
    let web = 'mkimq.com'
}

console.log(web)

函数提升

fn() // mkimq

function fn() {
    conosle.log('mkimq')
}

变量函数定义不会被提升

形参实参

形参是在函数声明时设置的参数,实参指在调用函数时传递的值。

  • 形参数量大于实参时,没有传参的形参值为 undefined
  • 实参数量大于形参时,多于的实参将忽略并不会报错
function sum(n1, n2) {
    return n1 + n2
}

sum(1, 2) // 3

默认参数

下面通过计算年平均销售额来体验以往默认参数的处理方式

function avg(total, year) {
    year = year || 1

    return Math.round(total / year)
}

// 使用新版本默认参数方式如下
// 默认参数要放在最后面
function avg(total, year = 1) {
    return Math.round(total / year)
}

函数参数

函数可以做为参数传递,这也是大多数语言都支持的语法规则。

function filterFun(item) {
    return item <= 3
}

const arr = [1, 2, 3, 4, 5, 6].filter(filterFun)

arguments

arguments 是函数获得到所有参数集合,下面是使用 arguments 求和的例子

function sum() {
    return [...arguments].reduce((total, num) => {
        return total += num
    }, 0)
}

// 使用展示语法
function sum(...args) {
    return args.reduce((total, num) => {
        return total += num
    }, 0)
}

箭头函数

箭头函数是函数声明的简写形式,在使用递归调用、构造函数、事件处理器时不建议使用箭头函数。

无参数时使用空扩号即可

const sum = () => {}

// return
const sum = () => 1 + 2

// 只有一个参数时可以省略括号
const fn = name => name

递归调用

递归指函数内部调用自身的方式。

  • 主要用于数量不确定的循环操作
  • 要有退出时机否则会陷入死循环

下面通过阶乘来体验递归调用

function factorial(num = 3) {
    return num == 1 ? num : num * factorial(--num)
}

累加计算方法

function sum(...num) {
    return num.length == 0 ? 0 : num.pop() + sum(...sum)
}

回调函数

在某个时刻被其他函数调用的函数称为回调函数,比如处理键盘、鼠标事件的函数。

展开语法

展示语法或称点语法体现的就是收/放特性,做为值时是放,做为接收变量时是收。

let mk = [1, 2, 3]
const [a, b, c] = [...mk]

[...mk] = [4, 5, 6]

使用展示语法可以替代 arguments 来接收任意数量的参数 也可以用于接收部分参数

标签函数

使用函数来解析标签字符串,第一个参数是字符串值的数组,其余的参数为标签变量。

function fn(str, ...values) {
    console.log(str)
    console.log(values)
}

const name = 'mkimq'
const url = 'mkimq.com'

fn`站点${name}:${url}`

this

调用函数时 this 会隐式传递给函数指函数调用时的关联对象,也称之为函数的上下文。

函数调用

全局环境下this就是window对象的引用

console.log(this == window) // true

使用严格模式时在全局函数内this为undefined

方法调用

函数为对象的方法时this 指向该对象

  1. 构造函数

函数当被 new 时即为构造函数,一般构造函数中包含属性与方法。函数中的上下文指向到实例对象。

  • 构造函数主要用来生成对象,里面的this默认就是指当前对象
function User() {
    this.name = 'mkimq'

    this.say = function() {
        console.log(this)
        return this.name
    }
}

const user = new User()

console.log(user.say())
  1. 对象字面量
const obj = {
	site: 'mkimq',
	show() {
		console.log(this.site)
		console.log(`this in show method: ${this}`)

		function fn() {
			console.log(typeof this.site)
			console.log(`this in fn function: ${this}`)
		}

		fn()
	}
}

obj.show()

箭头函数

箭头函数没有this, 也可以理解为箭头函数中的this 会继承定义函数时的上下文,可以理解为和外层函数指向同一个this。

  • 使用箭头函数后 this 为定义该函数的上下文,也可以理解为定义时父作用域中的this
  • 事件函数可理解为对象onclick设置值,所以函数声明时this为当前对象,但使用箭头函数时this为声明函数上下文

apply/call/bind

改变this指针,也可以理解为对象借用方法,就现像生活中向邻居借东西一样的事情。

原理分析

构造函数中的this默认是一个空对象,然后构造函数处理后把这个空对象变得有值。

function User(name) {
	this.name = name
}

const user = new User('mkimq')

可以改变构造函数中的空对象,即让构造函数this指向到另一个对象。

function User(name) {
	this.name = name
}

const mk = {}

User.call(mk, 'MKIMQ')

console.log(mk.name)

apply/call

call与apply 用于显示的设置函数的上下文,两个方法作用一样都是将对象绑定到this,只是在传递参数上有所不同。

  • apply 用数组传参
  • call 需要分别传参
  • 与 bind 不同 call/apply 会立即执行函数

语法使用介绍

function show(title) {
	console.log(`${title + this.name}`)
}

const lisi = {
	name: '李四'
}

const zhangsan = {
	name: '张三'
}

show.call(lisi, 'mkimq')
show.apply(zhangsan, ['MKIMQ'])

bind

bind()是将函数绑定到某个对象,比如 a.bind(hd) 可以理解为将a函数绑定到hd对象上即 hd.a()。

  • 与 call/apply 不同bind不会立即执行
  • bind 是复制函数形为会返回新函数

bind是复制函数行为

const a = function () {}

const b = a
console.log(a === b) // true

const c= a.bind()
console.log(a == c) // false

绑定参数注意事项

function fn(a, b) {
	return this.f + a + b;
}

// 使用bind会生成新函数
let newFunc = fn.bind({
	f: 1
}, 3)

// 1+3+2 参数2赋值给b即 a=3,b=2
console.log(newFunc(2))
贡献者: mankueng