ES6 函数的扩展

发布于 2024-05-14 00:13:58 字数 5039 浏览 19 评论 0

箭头函数

  1. 箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错
  2. 如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用 return 语句返回
  3. 简化回调函数
  4. 箭头函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象,在箭头函数中,它是固定的。

而普通函数 this 指向运行时所在的作用域(即全局对象)

  1. 不可以当作构造函数,也就是说,不可以使用 new 命令 ,否则会抛出一个错误。this 指向的固定化,并不是因为箭头函数内部有绑定 this 的机制,实际原因是箭头函数根本没有自己的 this,导致内部的 this 就是外层代码块的 this。正是因为它没有 this,所以也就不能用作构造函数。也就不能用 call()apply()bind() 这些方法去改变 this 的指向
// 箭头函数没有自己的 this,所以 bind 方法无效,内部的 this 指向外部的 this
(function() {
    return [
        (() => this.x).bind({ x: 'inner' })()
    ];
}).call({ x: 'outer' });
// ['outer']

  1. 不可以使用 arguments 对象,该对象在函数体内不存在 。如果要用,可以用 rest 参数代替。

argumentssupernew.target 三个变量在箭头函数之中也是不存在的

  1. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

不适用场合

定义对象的方法,且该方法内部包括 this

因为对象不构成单独的作用域 ,导致 jumps 箭头函数定义时的作用域就是全局作用域。调用 cat.jumps() 时,如果是普通函数,该方法内部的 this 指向 cat;如果写成上面那样的箭头。

函数,使得 this 指向全局对象,因此不会得到预期结果。

const cat = {
    lives: 9,
    jumps: () => {
        this.lives--;
    }
}

需要动态 this 的时候,也不应使用箭头函数

下面代码运行时,点击按钮会报错,因为 button 的监听函数是一个箭头函数,导致里面的 this 就是全局对象。如果改成普通函数,this 就会动态指向被点击的按钮对象。

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

如果函数体很复杂,有许多行,或者函数内部有大量的读写操作,不单纯是为了计算值,这时也不应该使用箭头函数,而是要使用普通函数,这样可以提高代码可读性

尾调用优化/尾递归优化

注意: ES6 的尾调用优化只在严格模式下开启 ,正常模式是无效的。因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈

  • func.arguments :返回调用时函数的参数。
  • func.caller :返回调用当前函数的那个函数

函数调用会在内存形成一个 调用记录,又称 调用帧(call frame),保存调用位置和内部变量等信息。所有的调用帧,就形成一个 调用栈(call stack)。

只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化”,确保最后一步只调用自身,把所有用到的内部变量改写成函数的参数 。

// 尾递归
function factorial(n, total) {
    if (n === 1) return total;
    return factorial(n - 1, n * total);
}
factorial(5, 1) // 120

// 非尾递归 Fibonacci 数列
function Fibonacci (n) {
    if ( n <= 1 ) {return 1};
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}
//尾递归优化
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
    if( n <= 1 ) {return ac2};
    return Fibonacci2 (n - 1, ac2, ac1 + ac2);
}
Fibonacci2(100) // 573147844013817200000
Fibonacci2(1000) // 7.0330367711422765e+208
Fibonacci2(10000) // Infinity

尾递归优化的实现

采用 循环 换掉 递归

function sum(x, y) {
    if (y > 0) {
        return sum(x + 1, y - 1);
    } else {
        return x;
    }
}
sum(1, 100000)
// Uncaught RangeError: Maximum call stack size exceeded(…)


// 蹦床函数(trampoline)可以将递归执行转为循环执行
function trampoline(f) {
    while (f && f instanceof Function) {
        f = f();
    }
    return f;
}

function sum(x, y) {
    if (y > 0) {
        return sum.bind(null, x + 1, y - 1); // 每一步返回另一个函数
    } else {
        return x;
    }
}

// 使用蹦床函数执行 sum,就不会发生调用栈溢出。
trampoline(sum(1, 100000)) // 100001

蹦床函数并不是真正的尾递归优化,下面的实现才是

function tco(f) {
    var value;
    var active = false;
    var accumulated = [];
    return function accumulator() {
        accumulated.push(arguments);
        if (!active) {
            active = true;
            while (accumulated.length) {
                value = f.apply(this, accumulated.shift());
            }
            active = false;
            return value;
        }
    };
}
var sum = tco(function(x, y) {
    if (y > 0) {
        return sum(x + 1, y - 1)
    }
    else {
        return x
    }
});
sum(1, 100000)
// 100001

tco 函数是尾递归优化的实现,它的奥妙就在于状态变量 active。默认情况下,这个变量是不激活的。一旦进入尾递归优化的过程,这个变量就激活了。然后,每一轮递归 sum 返回的都是 undefined ,所以就避免了递归执行;而 accumulated 数组存放每一轮 sum 执行的参数,总是有值的,这就保证了 accumulator 函数内部的 while 循环总是会执行。这样就很巧妙地将“递归”改成了“循环”,而后一轮的参数会取代前一轮的参数,保证了调用栈只有一层

柯里化

将多参数的函数转换成单参数的形式

// 第一种
function currying(fn, n) {
    return function (m) {
        return fn.call(this, m, n);
    };
}
function tailFactorial(n, total) {
    if (n === 1) return total;
    return tailFactorial(n - 1, n * total);
}
const factorial = currying(tailFactorial, 1);
factorial(5) // 120

// 第二种
function factorial(n, total = 1) {
    if (n === 1) return total;
    return factorial(n - 1, n * total);
}
factorial(5) // 120

函数参数的尾逗号

catch 命令的参数省略

try {
    // ...
} catch {
    // ...
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

情感失落者

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

安静被遗忘

文章 0 评论 0

喔爱吃橙子

文章 0 评论 0

草莓味的萝莉

文章 0 评论 0

梦里兽

文章 0 评论 0

mb_83J3Cyxa

文章 0 评论 0

时间海

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文