ES6 函数的扩展
Posted gaogao999
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6 函数的扩展相关的知识,希望对你有一定的参考价值。
第三章 函数
函数形参的默认值
ES5模拟默认参数
function makeRequest (url, timeout, callback)
timeout = timeout || 2000;
callback = callback || function () ;
为形参赋予默认值,说明了该参数为可选参数。
ES6的默认参数值
function makeRequest (url, timeout = 2000, callback = function () )
// 函数执行
需要注意的是,在参数中,null也是合法的参数值,所以传入null的时候不会用默认值替代。
ES6真正的可选参数是参数后面带?声明。
默认参数值对arguments对象的影响
在ES5非严格模式中,函数命名参数的变化会体现在arguments对象中。
在ES5严格模式中,无论参数如何变化,arguments对象不再随之改变。
ES6默认处于严格模式,默认参数值的存在使得arguments对象保持与命名参数的分离。
默认参数表达式
默认参数值可以使用任意数据类型,甚至是函数执行返回的结果。
ES6的参数声明具有临时性死区的特性,不能在声明之前调用。
function add (first = second, second = 1)
return first + second;
// 这是一个运行时才会抛出的错误,只有当first传入了非法值,引发默认值赋值的时候,才会抛出error。
add(1, 2); //3,没有使用默认值
add(); // ReferenceError,使用默认值时候发现在second声明前使用了second
处理无命名参数
ES5中的无命名参数
ES5调用arguments对象来获取所有的实参,从而间接地对无命名参数操作。
不定参数
ES6引入在命名参数前的三个点...来表明不定参数(rest parameters)。所有自它之后传入的所有参数,都被纳入以这个参数命名的数组中。ES6中arguments依然存在,但是应当尽可能地使用不定参数来替代它的作用。
使用限制:
- 不定参数一定要放在参数表的末尾。
- 不能用于对象字面量setter中(因为它的参数有且只能有1个)。
增强的Function构造函数
ES6增强了Function构造函数的功能,支持在创建函数时定义默认参数和不定参数。
var add = new Function('first', 'second = 1', 'return first + second;');
add(1, 1); // 2
add(1); // 2
name属性
ES6为所有函数添加了name属性,其特性为:
- 函数自身的命名,权重最高,不会被覆盖。
- 函数表达式所赋值的变量名,权重其次,会覆盖匿名函数表达式的name。
- getter/setter会有get/set前缀,bind返回的函数表达式会有bound前缀。
- Function构造函数创建的函数,名称为anonymous。
不能使用name来获取对于函数的引用。
展开运算符
和不定参数使用相对的是展开运算符,同样也是...声明。
它使用在传递实参的时候,将一个Array展开为参数表的形式。
let values = [25, 50, 75, 100];
// 两者等价
Math.max.apply(Math, values);
Math.max(...values);
明确函数的多重用途
JS函数有两个不同的内部方法: [[Call]]和[[Construct]]。
通过new关键字调用函数时,执行的是[[Construct]]函数,它负责创建一个实例对象,然后再执行函数体,将this绑定到实例上。
不通过new调用函数,则执行[[Call]]函数,直接执行代码中的函数体。
ES5判断函数被调用方法
使用this instanceof class的形式。
function Person (name)
// new关键字将this绑定到实例
if(this instanceof Person)
this.name = name;
// [[Call]]调用不会绑定this到实例
else
throw new Error('必须使用new关键字调用Person');
元属性(Metaproperty)new.target
new.target表示new操作符的目标,即该构造函数。如果[[Call]]方式调用,则其为undefined。
块级函数
ES6引入块级作用域后,在块级作用域中声明的函数只能在块内使用,当跳出块后,该函数将无法访问。
严格模式下,function声明的块级函数会被提升到块级作用域的顶部。
非严格模式下,function声明的跨级函数会被提升到外层的函数作用域。
箭头函数(Lambda)
与传统函数的不同:
- 没有this、super、arguments和new.target绑定,这些值由外层最近一层非箭头函数决定。
- 不能通过new关键字调用,没有[[Construct]]方法。
- 没有原型。
- 不可以改变this绑定(因为始终从外层获取)。
- 不支持重复的命名参数。
lambda表达式也有name属性,类似于函数。
没有this绑定
lambda表达式的this必须通过查找作用域链来决定其值。
箭头函数的返回值
没有用包裹时,lambda表达式只能有一条执行语句,并返回该语句的返回值。
var result = [].sort((a, b) => a - b); // 等同于 return a - b
尾递归优化(TCO)
function TCO (fn)
let value,
active = false,
accumulated = [];
// 在f内部进行递归调用的时候,其实调用的是这个返回的accumulator
// 这里需要注意的是,要将f中的递归调用函数名使用accumulator被赋予的变量名
return function accumulator(...args)
accumulated.push(args);
if(!active)
active = true;
while(accumulated.length)
/**
* 由于每次需要递归的fn.apply都会导致accumulated被push进一个新的arguments,
* 所以这个while一直要到全部执行结束才会跳出,
* 但这种结构只会保持最多两层的调用栈
*/
value = fn.apply(this, accumulated.shift());
active = false;
return value;
var sum = TCO(function(x, y)
if(y > 0)
// 再次调用的其实是闭包返回的accumulator,而不是这个传入的function
return sum(x + 1, y - 1);
else
return x;
);
以上是关于ES6 函数的扩展的主要内容,如果未能解决你的问题,请参考以下文章