函数只定义一次但可能被执行或调用任意次,但在定义的时候并不会执行。
函数的参数有形参和实参,形参是函数中定义的变量,实参是在运行是的函数调用时传入的参数。
函数使用function关键字来定义,es6可以用=>来定义,函数的组成:
- 函数名
- 一对圆括号(由0个或多个标识符组成,这些标识符是函数的参数名称,他们就像函数体中的局部变量)
- 一对花括号(其中包含0条或多条js语句。一旦调用函数,就会执行这些语句)
函数调用
- 函数调用(由一个函数对象和左圆括号,参数列表和右圆括号组成)
- 方法调用 (调用的上下文不同,也就是this不同)
- 构造函数调用 (如果函数或者方法调用之前带有关键字new,他就构成构造函数调用。)
- 间接调用(call和apply方法间接调用)
形参和实参
当调用函数的时候传入的实参比函数声明时指定的形参个数要少,剩下的形参都将设置为undefined值。
可变长的实参列表
function b(x,y){console.log(arguments.length)}
b(1,2,3) //3
callee和caller
callee和caller指代调当前正在执行的函数。caller是非标准的。它们在匿名函数中用来递归会非常有用。
作为值的函数
函数还可以作为值
function fun(x){
return x*x
}
fun(4) //16
此时,这个是作为值。
当函数作为对象的属性调用时,函数就称为方法。
var o={fun:function(x){return x*x}}
var y=o.fun(4) //16
函数属性
函数是一种特殊对象,说明函数也可以拥有属性。
int.counter=0
function int(){
return int.count++
}
每次调用都会返回一个唯一的整数。
匿名函数
没有函数名的的函数
(function(){
//do
}())
闭包
在js中作用域内部可以访问外部变量,反之则不可以,这时候我们就需要闭包来实现。
函数的执行依赖于变量作用域,作用域是在函数定义时决定的,而不是调用时决定的。
函数对象通过作用域相互关联起来,函数体内部的变量都可以保存在函数的作用域内,这种特性被称为闭包。
var a=1
function foo(){
var a=2
function f(){return a}
return f
}
foo()() //2
这段代码中,foo只返回一个函数对象,看起来就像在作用域外部拿到作用域内部的变量一样。
函数的方法和属性
函数也有length属性,它表示传入的实参个数(在定义的时候)。
prototype表示函数定义的时候从原型对象上继承的属性。
// call和apply都是表示临时调用方法
f.call(o)
f.apply(o)
//上面代码等同于下面代码
o.m=f
o.m()
delete o.m
//apply和call不同之处在于apply可传入实参作为数组的性式传入。
//把函数绑定至某个对象
function f(y){return this.x+y}
var o={x:1}
var g=f.bind(o)
g(2) //3
//es5中不仅可以绑定至对象也可以绑定到this,这种技术被称之为柯里化(有种搭积木的感觉)。
function f(y,z){return this.x+y+z}
var g=f.bind({x:1},2)
g(3) // 6 (this.x=1,y=2,z=3)
记忆
函数记忆是指将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。(适用于计算量大,复杂的情况)
function memoize(f) {
var cache = {};
return function(){
var key = arguments.length + Array.prototype.join.call(arguments, ",");
if (key in cache) {
return cache[key]
}
else return cache[key] = f.apply(this, arguments)
}
}
var propValue = function(obj){
return obj.value
}
var memoizedAdd = memorize(propValue)
console.log(memoizedAdd({value: 1})) // 1
console.log(memoizedAdd({value: 2})) // 1
//优化一下记忆的方法 加入了hasher判断唯一性
var memorize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = '' + (hasher ? hasher.apply(this, arguments) : key);
if (!cache[address]) {
cache[address] = func.apply(this, arguments);
}
return cache[address];
};
memoize.cache = {};
return memoize;
};
var memoizedAdd = memorize(add, function(){
var args = Array.prototype.slice.call(arguments)
return JSON.stringify(args)
})
console.log(memoizedAdd(1, 2, 3)) // 6
console.log(memoizedAdd(1, 2, 4)) // 7