函数

77 阅读1分钟

所有函数都是Function的实例(包括Function本身)

arguments

虽然 arguments 很像数组,但它是一个对象。数组专有的方法(比如 sliceforEach ),不能在arguments 对象上直接使用。
如果要让 arguments 对象使用数组方法,真正的解决方法是将 arguments 转为真正的数组。下面是两种常用的转换方法:slice 方法和逐一填入新数组。

// 使用call()盗用slice()方法
function foo(a,b,c){
  var args = Array.prototype.slice.call(arguments);
  console.log(args.slice(0, 2));
}
foo(4, 5, 6);  // [4,5]

// 遍历逐一填入数组
var args = [];
for (var i = 0; i < arguments.length; i++) {
  args.push(arguments[i]);
}

模拟函数重载

arguments 对象判断传递给函数的参数个数,即可模拟函数重载。

function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 5);
  } else if(arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}

doAdd(10);	// 15
doAdd(40, 20);	// 60

默认参数

// es5 
function show (msg,duration) {
  duration = duration || 3000
  ...
}

// es6
function show (msg,duration = 3000) {
  ...
}

函数调用中跳过参数

// es6 传递一个 undefined 会使用默认值
function sayHi(arg1=1,arg2=2,arg3=3){
  console.log(arg1, arg2, arg3)
}

sayHi('第一个参数',undefined,'第二个参数')

// 传递一个对象
function sayHi(person){
  let name = person.name
  let height = person.height
  console.log(name, height)
}

sayHi({name:'lxx',age:25,height:1.88})

函数名解耦

arguments.callee 指向拥有这个 arguments 对象的函数。

function box(num) {
  if (num <= 1) { 
    return 1;
  } else {
    return num * arguments.callee(num - 1); 
  }
}
box(5) 

柯里化

只传递给函数一部分参数来调用它,让它返回一个函数处理剩余的参数。

// 未柯里化
function add1(x,y,z) {
  return x + y + z
}

add1(10,20,30)

// 柯里化处理的函数
function add2(x) {
  return function(y) {
    return function(z) {
      return x + y + z
    }
  }
}

add2(10)(20)(30)

单一职责原则

每一个函数处理的问题尽可能单一,避免将众多处理过程交给一个函数。

// 未柯里化
function sum(x,y,z) {
  x = x + 2
  y = y * 2
  z = z * z
  return x + y + z
}

sum(10,20,30)

// 柯里化
function sum(x,y,z) {
  x = x + 2
  return function (y) {
    y = y * 2
    return function (z) {
      z = z * z
      return x + y + z
    }
  }
}

sum(10)(20)(30)

柯里化逻辑复用案例1

function makeAdder(count) {
  // ... 如果还有其他逻辑
  return function (num) {
    return count + num
  }
}

// 用法一
makeAdder(10)(10) // 20
makeAdder(20)(10) // 30

// 用法二
var adder5 = makeAdder(5)  // 这里就是对 makeAdder 其他逻辑的复用
adder5(10) // 15
adder5(20) // 25
adder5(30) // 35

柯里化逻辑复用案例2

传统方式:每一个参数都需要传递,存在重复传递。

function log(date,type,message) {
  console.log(`[${date.getHours()}:${date.getMinutes()}]-[${type}]-[${message}]`)
}

log(new Date(),'debug','轮播图错误')
log(new Date(),'debug','菜单错误')
log(new Date(),'debug','编辑器错误')

柯里化方式

function log(date,type,message) {
  return function (type) {
    return function (message) {
      console.log(`[${date.getHours()}:${date.getMinutes()}]-[${type}]-[${message}]`)
    }
  }
}

// 将 date 提取出,不需要传递,只传递 type 和 message
var nowLog = log(new Date())
nowLog('debug')('标题栏错误')
nowLog('debug')('编辑器错误')

// 将 date 和 type 提取出,不需要传递,只传递 message
var nowMessage = log(new Date())('debug')
nowMessage('登录错误')
nowMessage('注册错误')

箭头函数柯里化

var log = date => type => message => {
  console.log(`[${date.getHours()}:${date.getMinutes()}]-[${type}]-[${message}]`)
}