- 参数变量是默认声明的,所以不能用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) {}
// SyntaxError: Duplicate parameter name not allowed in this context
// 写法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]
// x 和 y 都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]
// x 有值,y 无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
- 一般设置在尾部,因为设置了默认值可以省略
- 参数为undefined触发默认值
function foo(x, y = 6, z = 7) {
console.log(x, y, z);
}
foo(5, undefined, null)
// 5 6 null
length:默认值的参数之前的数量
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
作用域是单独的作用域,参数使用let声明
var x = 1;
function foo1(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo1() // 3
x // 1
function foo2(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo2() // 2
x // 1
- 是数组
- 只能是最后一个参数
- 函数的length属性,不包括 rest 参数
严格模式只能设置在有参数的函数体外。因为假如函数体设置为严格模式,但参数却应该先于函数体执行,参数并不是严格模式执行的
// 报错
// 执行参数不报错,执行到函数题才报错。正确应该一开始执行就报错
function doSomething(value = 070) {
'use strict';
return value;
}
var bar = function baz() {};
bar.name // "baz"
var f = function () {};
f.name // ES5:""
f.name // ES6:"f"
(new Function).name // "anonymous"
(new Function).bind({}).name // bound anonymous
let fn = () => void 1;
- 自身没有this,函数体内的this对象等于外层代码的this。
- 自身没有arguments对象,函数体内的arguments对象对象等于外层代码的arguments对象。
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
- 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
// 只有函数foo的this
function foo() {
return () => {
return () => {
return () => {
console.log('id:', this.id);
};
};
};
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1
- 对象属性函数
- 需要动态this
// 对象属性函数
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
// 需要动态this
document.getElementById('press').addEventListener('click', () => {
this.classList.toggle('on');
});
// Redux compose函数
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)
// 12
尾调用某个函数的最后一步是调用另一个函数
function f(x){
return g(x);
}
只保留内层函数的调用帧
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
function Fibonacci (n) {
if ( n <= 1 ) {return 1};
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Fibonacci(10) // 89
Fibonacci(100) // 超时
Fibonacci(500) // 超时
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 实测会爆栈!!!
ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。 这是因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。严格模式禁用这两个变量
- func.arguments:返回调用时函数的参数。
- func.caller:返回调用当前函数的那个函数。
递归会爆栈,改用循环
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
function clownsEverywhere(
param1,
param2,
) { /* ... */ }
clownsEverywhere(
'foo',
'bar',
);
以前会忽略注释
function /* foo comment */ foo () {}
foo.toString()
// "function /* foo comment */ foo () {}"
允许catch语句省略参数
try {
// ...
} catch (err) {
// 处理错误
}
// ES2019
try {
// ...
} catch {
// ...
}