函数定义
函数声明
函数名称和函数体提前,所以可以在声明一个函数前调用它
myFunc('k') // k
function myFunc(name){
console.log(name);
}
函数表达式
函数表达式不支持函数提升,因为只有var 声明变量提前了,函数代码还是在原来位置
匿名函数表达式
var myFunc2 = function (){}
命名函数表达式
console.log(myFunc3); // undefined
var myFunc3 = function funcName(){}
console.log(myFunc3); // ƒ funcName(){}
函数生成器声明
function* generator(i) {
yield i;
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 20
函数生成器表达式
const foo = function*() {
yield 'a';
yield 'b';
yield 'c';
};
let str = '';
for (const val of foo()) {
str = str + val;
}
console.log(str); // abc
箭头函数表达式
var myFunc4 = () => {}
Function构造函数
var myFunc5 = new Function('name',`return name`)
myFunc5('jack') // jack
函数参数
形参和实参
形参是函数中定义的变量,实参是运行时函数调用传入的参数
function add(a,b){
return a+b
}
add(1,2)
add(a,b) // 这里的 a 和 b 就是形参
add(1,2) // 1 和 2 就是实参
默认参数
函数默认参数允许在没有值或undefined被传入时使用默认形参
function add(a = 1){
return a
}
console.log(add(1)); // 1
console.log(add()); // 1
console.log(add(undefined)); // 1
console.log(add('')); //
console.log(add(null)); // null
剩余参数
函数的最后一个命名参数以...为前缀,则它将成为一个由剩余参数组成的真数组
function sum(...theArgs) {
let total = 0;
for (const arg of theArgs) {
total += arg;
}
return total;
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4)); // 10
arguments 对象
arguments对象是所有(非箭头)函数中都可用的局部变量。arguments对象不是一个 Array 。它类似于Array
function fn(){
console.log(arguments[0]); // 1
console.log(arguments[1]); // 2
}
fn(1,2)
Function 类型
每个函数都是Function类型的实例,因此函数实际上是一个对象。函数名是指向函数对象的指针。
function func(name){
console.log(name);
}
console.log(func.name); // func
console.log(func.length); // 1
console.log(func.prototype); // 原型对象
console.log(typeof func); // function
console.log(func instanceof Function); // true
属性
- name:函数的名字
- length:该函数希望接收的参数个数,即形参的个数。
- prototype:函数的原型
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
function fn(){
var i = 0
return function(){
return i++
}
}
var f2 = fn()
console.log(f2()); // 0
console.log(f2()); // 0
在上面这个例子中,fn()方法返回了一个匿名函数,在函数中执行 a+i,访问了外部的变量i。即使这个内部函数被返回了在其它地方调用,依然可以访问变量i
使用注意:
- 由于闭包会将函数中的变量保存在内存中,因此内存消耗比其它函数大。过度使用闭包会导致内存占用过多
- 闭包会改变父函数的变量,所以谨慎使用
高阶函数
高阶函数就是一个将函数作为参数或者返回值的函数。
在 JavaScript 的内置对象中同样存在着一些高阶函数,例如数组的map,filter,reduce方法等
比如我们想计算了一个数组元素的和。
最普通的方式:
let arr = [1, 2, 3, 4]
let sum = 0
for (let index = 0; index < arr.length; index++) {
sum += arr[index]
}
console.log(sum) // 10
使用 Array.prototype.reduce:
let arr = [1, 2, 3, 4]
let sum = arr.reduce(function (value, item) {
return value + item
})
console.log(sum) // 10
创建一个自己的高阶函数,模拟实现 map() 方法 :
let arr = [1, 2, 3, 4]
Array.prototype.mapFn = function(callbackfn,thisArg){
if (typeof callbackfn !== 'function') {
throw new TypeError(`callbackfn is not function`)
}
let result = []
const current = this
for (let index = 0; index < current.length; index++) {
result[index] = callbackfn.call(thisArg,current[index],index,current)
}
return result
};
let result = arr.mapFn((item)=>{
return item * 2
})
console.log(result) // [2, 4, 6, 8]
我们在 Array 原型上面定义了 mapFn() 方法,它接受一个回调函数 callbackfn 和 thisArg用作执行 callbackFn 函数时被用作 this 的值。
我们循环调用这个函数的数组,在每次循环的时候callbackfn方法接受当前元素、索引、调用mapFn()方法的数组作为参数,然后将 callbackfn方法存储在返回结果中 result。循环完毕后再返回出函数
柯里化函数
函数柯里化也是高阶函数的一个应用。其含义是把接收多个参数的函数变成一个可以接收单一参数的函数,并且返回接受余下的参数并返回结果的新函数
function add(y){
return function(x){
return x + y
}
}
add(2)(1) // 3
柯里化工具函数封装:
function curry(fn, args) {
var args = args || []
return function () {
argsList = args.concat(Array.prototype.slice.call(arguments))
if (argsList.length < fn.length) {
// 传入的参数大于等于原始函数fn的参数个数,则直接执行该函数
return curry.call(this, fn, argsList)
} else {
// 否则继续对当前函数进行柯里化,返回一个接受所有参数(的函数
return fn.apply(this, argsList)
}
}
}
function add(x, y) {
return x + y
}
const addCurry = curry(add)
console.log(addCurry(1)(2)) // 6
console.log(addCurry(1, 2)) // 6
console.log(addCurry(1, 2)) // 6