函数的扩展

函数的默认值

function log(x, y = 'World') {
  console.log(x, y);
}
//惰性求值
let x = 99;
function foo(p = x + 1) {
  console.log(p);
}
foo() // 100
x = 100;
foo() // 101
//配合解构赋值默认值
function foo({x, y = 5}) {
  console.log(x, y);
}
foo({x: 1, y: 2}) // 1 2
//使用双重默认值
function fetch(url, { body = '', method = 'GET', headers = {} } = {}) {
  console.log(method);
}
fetch('http://example.com')
// "GET"

两种默认值的写法:

// 写法一
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
//第一种是解构赋值之后的默认值,第二种则是对于整个对象的默认值

对于参数默认值的位置应该使用undefined来代替位置,会被默认值替换,而Null不行。

  • 指定了默认值之后函数的length属性,返回没有指定默认值的参数个数.
(function (a) {}).length // 1
(function (a = 5) {}).length // 0

参数作用域:

var x = 1;
function f(x, y = x) {
  console.log(y);
}
f(2) // 2
let foo = 'outer';
//参数找不到时往外面找
function bar(func = () => foo) {
  let foo = 'inner';
  console.log(func());
}
bar(); // outer
//理解作用域的小案例
var x = 1;
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x);
}
foo() // 3
x // 1

rest参数:

function add(...values){}
使用arguments变量的写法:

const sortNumbers = (...numbers) => numbers.sort();
  • 严格模式只能在全局或者没有参数的函数体内使用。
  • 使用name属性访问函数名
var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"

使用Function构造函数返回的函数实例,name为anonymous

(new Function).name // "anonymous"

bind返回的函数,name属性会加上bound前缀.

function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "

箭头函数

//箭头函数的错误用法
let foo = () => { a: 1 };
foo() // undefined
//箭头函数不需要返回值的用法
let fn = () => void doesNotReturn();
//箭头函数与变量解构配合使用
const full = ({ first, last }) => first + ' ' + last;
//箭头函数和rest参数结合使用
const numbers = (...nums) => nums;
const headAndTail = (head, ...tail) => [head, tail];

箭头函数的注意点:

1.this对象是定义时所在的对象,如:
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
2.不可作为构造函数,原因正是箭头函数没有自己的this,此外还有supernew.target都不存在,需要指向外层函数的对应变量,也就不能使用call(),apply(),bind()去改变this的指向.
ps:obj.call(db,parms)是更改绑定的this对象,并传入参数,使用,隔开;
而apply(db,[])使用数组装参数,
而bind参数和call一样,不过返回的是函数,因此还需要再进行调用.
3.不存在arguments对象,使用rest参数代替
4.不可使用yield命令,箭头函数不能用作Generator函数.

对于绑定时对应的作用域,普通函数是对应全局的作用域:

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0

不适合使用箭头函数的场景:
1.对象中有箭头函数且使用this,因为对象不是作用域,this为全局this
2.需要动态this的时候:

var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

箭头函数嵌套使用:

部署管道机制的作用,前一个输出为后一个输入:

const pipeline = (...funcs) =>
  val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5)

尾调用优化

某个函数的最后调用另一个函数,如:

function f(x){
  return g(x);
}
//这种情况不对
// 情况三
function f(x){
  g(x);
}
相当于
function f(x){
 g(x);
 return undefined;
}

尾调用优化:就是执行到尾调用函数时,可以直接将外部函数的调用帧直接替换即可,可以节省内存,但是该函数内部不能使用到外部函数的变量.
尾递归:

//返回的不是自身因此不是尾递归
function factorial(n) {
  if (n === 1) return 1;
  return n * factorial(n - 1);
}
factorial(5) // 120
//改成返回自身的递归就是尾递归
function factorial(n, total) {
  if (n === 1) return total;
  return factorial(n - 1, n * total);
}
factorial(5, 1) // 120

允许函数参数的尾逗号
Function.prototype.toString()返回函数代码本身。
允许catch代码块省略参数。

posted @   梦呓qwq  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示