函数 ES6 - 77797963/review-notes GitHub Wiki
函数参数的默认值
参数变量是默认声明的,不能用let或者const再次声明 function foo(x = 5) { let x = 1; // error const x = 2; // error } 使用参数默认值时,函数不能有同名参数 // 不报错 function foo(x, x, y) { // ... }
// 报错 function foo(x, x, y = 1) { // ... }
参数默认值不是传值的,而是每次都重新计算默认值表达式的值 let x = 99; function foo(p = x + 1) { console.log(p); }
foo() // 100
x = 100; foo() // 101
rest参数 形式(...变量名),rest参数搭配的变量是一个组数,rest参数之后不能有其它参数,只能是最后一个参数,函数的length属性不包括rest参数
(function(a) {}).length // 1 (function(...a) {}).length // 0 (function(a, ...b) {}).length // 1
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); }
var id = 21;
foo.call({ id: 42 }); // id: 42 除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target。 function foo() { setTimeout(() => { console.log('args:', arguments); }, 100); }
foo(2, 4, 6, 8) // args: [2, 4, 6, 8] 上面代码中,箭头函数内部的变量arguments,其实是函数foo的arguments变量。 由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。 (function() { return [ (() => this.x).bind({ x: 'inner' })() ]; }).call({ x: 'outer' }); // ['outer']
上面代码中,箭头函数没有自己的this,所以bind方法无效,内部的this指向外部的this。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。 foo::bar(...arguments); // 等同于 bar.apply(foo, arguments);
尾调用之所以与其他调用不同,就在于它的特殊的调用位置。 函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。 ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。
这是因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。
func.arguments:返回调用时函数的参数。
func.caller:返回调用当前函数的那个函数。
尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效。