函数对象
当我们对函数使用typeof
操作符会返回什么?
function f() {
console.log(‘hello‘)
}
console.dir(typeof f) // function
实际上函数是一种特殊的JavaScript对象。由于函数是对象,所以它也有属性和方法,甚至还可以使用Function()
构造函数创建新函数对象。
函数属性
原有属性
length属性表示函数的参数列表中的参数个数。
name属性表示定义函数时使用的名字,如果是未命名的函数则为匿名函数。
prototype属性是函数对象的原型对象,每个函数都有自己的原型对象,当函数被作为构造函数使用是,新创建的对象从这个原型对象继承属性。
自定义属性
执行f.count = 0
不是在函数内定义一个局部变量count
。换句话说,函数属性和变量是毫不相关的两个东西。
函数是一种特殊的对象,可以在它里面添加属性,而且对它的执行没有任何影响。因此,可以将自定义属性缓存到函数对象中,而这个属性只有函数自己会用到。
function f() {
console.log(‘hello‘)
f.count++
}
f[‘count‘] = 1 // 自定义函数属性
f() // 执行函数
f() // 执行函数
console.log(`调用次数: ${f.count}`) // 2
使用函数自定义属性实现计算阶乘:
function f(n) {
if (Number.isInteger(n) && n > 0) {
if (!(n in f)) {
f[n] = n * f(n - 1)
}
return f[n]
} else {
return NaN
}
}
f[1] = 1 // 利用属性访问表达式f[1] = 1,初始化函数对象f存储的名为1的属性的值
f(6)
console.dir(f[5]) // 120,获取名为5的属性的值
函数方法
call()
call()和apply()允许为不同的对象分配和调用属于一个对象的函数,提供新的 this 值给当前调用的函数。
let o = {
print: function(date) {
console.log(`Time: ${date} | ${this.name} 说:${this.content}`)
}
}
let a = {
name: ‘xiaoming‘,
content: ‘今天天气真好!‘
}
let b = {
name: ‘xiaohong‘,
content: ‘今天天气一般!‘
}
o.print.call(a, new Date().getHours()) // Time: 22 | xiaoming 说:今天天气真好!
o.print.call(b, new Date().getHours()) // Time: 22 | xiaohong 说:今天天气一般!
call()和apply()类似于Java一样,子类继承父类,并调用父类方法。
bind()
bind()方法可以把函数绑定到对象上。如果在函数func上调用bind()方法并传入对象o,则这个方法会返回一个新函数,这个函数就像是func函数一样。
function func(y) {
return this.x + y
}
let o = {
x: 1
}
let bindFunc = func.bind(o)
console.log(bindFunc(10)) // 11
绑定完成之后,再将这个函数作为另一个对象的属性:
let p = {
x: 10,
bindFunc
}
console.log(p.bindFunc(10)) // 20
说明bindFunc依旧绑定的是对象o。
构造方法
因为函数是对象,所以就有一个Function()
构造函数可以用来创建函数:
const f = new Function(‘x‘, ‘y‘, ‘return x * y‘)
// 类似于
const f = function(x, y) {
return x * y
}