ES6标准---【四】【学习ES6标准看这一篇就够了!!!】

目录

ES6以往文章

rest参数

注意事项

函数的name属性

函数参数的尾逗号

Function.prototype.toString()

catch命令的参数省略

尾调用优化

什么是尾调用?

尾调用优化

尾递归

递归函数的改写

 方法一:

方法二:

ES6以往文章

ES6标准---【一】【学习ES6看这一篇就够了!!】-CSDN博客

ES6标准---【二】【学习ES6看这一篇就够了!!】-CSDN博客

ES6标准---【三】【学习ES6看这一篇就够了!!!】-CSDN博客

rest参数

RES6引入rest参数(形式为“...变量名”),用于获取函数解构赋值多余参数,这样就不需要引入“arguments”对象了

rest参数搭配的变量是一个数组,该变量将多余的参数传入数组

function add(...values) {
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(2, 5, 3) // 10

注意事项

rest参数之后不能再有其它参数(即只能是最后一个参数),否则会报错

// 报错
function f(a, ...b, c) {
  // ...
}

函数的.length属性,不包括 rest 参数

(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

函数的name属性

函数的name属性,返回该函数的函数名

function foo() {}
foo.name // "foo"

如果将一个匿名函数赋值给一个变量,ES5name属性会返回空字符串,而ES6name属性会返回变量名

var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"

但如果给这个匿名函数赋一个具体的名字,则ES5、ES6的name属性都会返回这个具名函数原本的名字

const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"

函数参数的尾逗号

ES6允许函数的最后一个参数有“尾逗号

  • 定义某个函数的参数时,可以有尾逗号
  • 调用某个函数填写参数时,可以有尾逗号
function clownsEverywhere(
  param1,
  param2,
) { /* ... */ }
clownsEverywhere(
  'foo',
  'bar',
);

Function.prototype.toString()

ES6之前的toString()方法返回函数代码本身,会省略注释空格

function /* foo comment */ foo () {}
foo.toString()
// function foo() {}

修改后的toString()方法,明确要求返回一模一样的原始代码:

<body>
	<script>
		function /* 代码注释1111 */ foo () {}
		console.log(foo.toString())
	</script>	
</body>

效果

catch命令的参数省略

ES6以前,JavaScript的“try...catch”结构,明确要求catch命令后面必须跟参数,接收try代码块抛出的错误对象

try {
  // ...
} catch (err) {
  // 处理错误
}

ES6中,catch语句允许省略参数

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

尾调用优化

什么是尾调用?

尾调用是函数式编程的一个重要概念,是指某个函数的最后一步是调用另一个函数(递归的特殊情况)

尾调用只在严格模式下开启,正常模式是无效的

function f(x){
  return g(x);
}

下面三种情况都不属于“尾调用”:

// 情况一
function f(x){
  let y = g(x);
  return y;
}
// 情况二
function f(x){
  return g(x) + 1;
}
// 情况三
function f(x){
  g(x);
}

情况一:调用函数g之后,还有赋值操作,所以不属于尾调用

情况二:调用函数g之后,还有一个加法操作,所以不属于尾调用

情况三:等同于下面代码:

function f(x){
  g(x);
  return undefined;
}

尾调用不一定出现在函数尾部,只要是最后一步操作即可:

function f(x) {
  if (x > 0) {
    return m(x)
  }
  return n(x);
}

上面代码中,函数m函数n都属于尾调用,因为它们都是函数f的最后一步调用

尾调用优化

尾调用的特殊点是:“它特殊的调用位置

函数调用会在内存形成一个“调用记录”,又称“调用帧”,保存调用位置内部变量等信息

如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧

等到函数B运行结束,将结果返回给A,A的调用帧才会消失

如果函数B内部还调用函数C,那就还有一个C的调用帧

所有的调用帧共同组成了“调用栈”(call back)

  • 尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用不到了,只要内层函数的调用帧,取代外层函数的调用帧即可
function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f();
// 等同于
function f() {
  return g(3);
}
f();
// 等同于
g(3);

只保留了g(3)的调用帧,这就叫做“尾调用优化

注意:

  • 只有不再用到外层函数的内部变量,内层函数的调用帧才会取代外层函数的调用帧,否则就无法进行“尾调用优化
function addOne(a){
  var one = 1;
  function inner(b){
    return b + one;
  }
  return inner(a);
}

上述代码就没有办法进去“尾调用优化”,因为内层函数inner调用了外层函数的内部变量one

尾递归

函数调用自身,称为递归,如果尾调用自身,就称为尾递归

地柜非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出

但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出

一般求阶乘的递归改为尾递归求阶乘

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

递归函数的改写

实现尾递归有两种方法

  1. 可以把所有用到的内部变量改写成函数的参数
  2. 利用函数默认值

 方法一:

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

方法二:

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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是洋洋a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值