ES6 学习笔记(函数)

参数默认值
// 默认值最好放在后面,即尾参数
function Point(x = 0, y = '') {
  // 构造函数默认返回 this,即实例
  this.x = x;
  this.y = y;
  // 参数不能再次声明
  let x = 1; // SyntaxError: Identifier 'x' has already been declard
  const y = 2; // SyntaxError: Identifier 'x' has already been declard
}
// 但是这样却可以
function foo(x = 1) {
  var x = 3;
  console.log(x);
}
foo(); // 3
// 或
function foo(x) {
  var x = 3;
  console.log(x);
}
foo(); // 3

// 参数同名
// 允许
function foo (x, x, y) {}
// SyntaxError: Duplicate parameter name not allowed in this context
function foo(x, x, y = 1) {}

// 惰性求值
let x = 99;
function foo(p = x + 1) {
  console.log(p);
}
foo(); // 100
x = 100;
foo(); // 101

// 解构赋值1️⃣
function foo({x, y = 5}) {
  console.log(x,y);
}
foo({}); // undefined 5
foo({x:1,y:2}); // 1 2
foo({x:1}); // 1 5
foo(); // TypeError: Cannot destructure property `x` of 'undefined' or 'null'

// 解构赋值2️⃣
function foo({x, y = 5} = {}) {
  console.log(x, y);
}
foo(); // undefined 5

// 解构赋值3️⃣
// 默认空对象,x y 任何时候都有值
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}
// 默认{x: 0, y: 0}
function m2({x, y} = {x: 0, y: 0}) {
  return [x, y];
}
m1(); // [0, 0]
m2(); // [0, 0]
m1({x: 3, y: 8}); // [3, 8]
m2({x: 3, y: 8}); // [3, 8]
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

// 解构赋值4️⃣
function f(x = 1, y) {
  return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // Uncaught SyntaxError: Unexpected token ,
f(undefined, 1) // [1, 1]

// 解构赋值5️⃣
function f(x, y = 5, z) {
  return [x, y, z];
}
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // Uncaught SyntaxError: Unexpected token ,
f(1, undefined, 2) // [1, 5, 2]

// 传入 undefined 触发默认值,而 null 不会
function foo(x = 5, y = 6) {
  console.log(x, y);
}
foo(undefined, null); // 5 null复制代码
length 属性

返回没有默认值的参数个数,计算最后一个有默认值的参数前面的参数个数

(function(x){}).length; // 1
(function(x = 1){}).length; // 0
(function(x, y = 1){}).length; // 1
(function (a = 0, b, c) {}).length; // 0
(function (a, b = 1, c) {}).length; // 1
(function(...args) {}).length; // 0复制代码
作用域

函数参数有默认值时,在函数初始化时在参数上会行程单独的作用域(context)

// 1️⃣
var x = 1;
function f(x, y = x) { // y 指向第一个参数 x
  console.log(y);
}
f(2); // 2
// 2️⃣
let x = 1;
function f(y = x) { // y 延
  let x = 2;
  console.log(y);
}
f(); // 1
// 3️⃣
function f(y = x) {
  let x = 2;
  console.log(y);
}
f(); // ReferenceError: x is not defined
// 4️⃣
var x = 1;
function foo(x = x) {
}
foo(); // ReferenceError: x is not defined
// 5️⃣
let foo = 'outer';
function bar(func = () => foo) {
  let foo = 'inner';
  console.log(func());
}
bar(); // outer
// 6️⃣
function bar(func = () => foo) {
  let foo = 'inner';
  console.log(func());
}
bar() // ReferenceError: foo is not defined
// 7️⃣
var x = 1;
function foo(x, y = function() { x = 2; }) { // 匿名函数内部的 x 指向第一个参数 x
  var x = 3; // 和参数中的x不是一个作用域
  console.log(y(), x);
}
foo(); // undefined 3
x; // 1
// 8️⃣
var x = 1;
function foo(x, y = function() { x = 2; }) {
  x = 3; 
  console.log(x, y(), x);
}
foo(); // 3 undefined 2
x; // 1复制代码
rest 参数
// rest 参数本身是数组
function add(...values) {
  let sum = 0;
  for (let val of values) {
    sum += val;
  }
  return sum;
}
add(2, 5, 3); // 10

function sortNumbers() {
  // arguments 是类数组对象
  return Array.prototype.slice.call(arguments);
}
// 同上
const sortNumbers = (...numbers) => numbers.sort();

// rest 参数后不能再有其他参数
function f(a, ...b, c){} // Uncaught SyntaxError: Rest Parameter must be last formal parameter复制代码
严格模式

只要函数参数使用了默认值、解构赋值或扩展运算符,那函数内部就不能用显式设定严格模式。因为函数参数先执行(可能是非严格模式),但是到了函数内部中时发现是严格模式,所以报错。

 // Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list
function doSomething(a, b = a) {
  'use strict';
}
const doSomething = function ({a, b}) {
  'use strict';
};
const doSomething = (...a) => {
  'use strict';
};
const obj = {
  doSomething({a, b}) {
    'use strict';
  }
};

// 解决办法
'use strict';
function doSomething(a, b = a) {}
// 或
const doSomething = (function() {
  'use strict';
  return function(value = 42) {
    return value;
  }
}());复制代码
name 属性
function foo() {}
foo.name; // foo

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

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

(new Function).name; // "anonymous"

function foo() {}
foo.bind({}).name; // "bound foo"

(function () {}).bind({}).name; // "bound "复制代码
箭头函数
  • 若返回对象需要用括号包起来
  • 函数体内的 this 是定义时所在对象,而不是使用时所在的对象,即固定的
    // setTimeout 内 this 指向 window
    function foo() {
    setTimeout(function() {
      console.log('id:', this.id);
    }, 100);
    }
    var id = 21;
    foo.call({ id: 42 }); // 21
    // setTimeout 内 this 指向 {id: 42},定义时确定且不会改变
    function foo() {
    setTimeout(() => {
      console.log('id:', this.id);
    }, 100);
    }
    var id = 21;
    foo.call({ id: 42 });复制代码
  • 不可以当构造函数 Uncaught TypeError: fn is not a constructor at <anonymous>:1:1
  • 没有 arguments 对象
  • 不可以用 yield 命令
let getTempItem = id => {id: id, name: 'Temp'}; // Uncaught ReferenceError: Function is not defined;

// 不需要返回值
let fn = () => void doesNotReturn();

// 利用箭头函数自动将传参以数组返回
const numbers = (...nums) => nums;
numbers(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

// pipeline 机制
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复制代码
尾调用

尾调用只在严格模式下开启,正常模式无效,即 func.arguments(返回调用时函数的参数) 和func.caller (返回调用当前函数的那个函数)俱无效。

尾递归
// 尾递归优化
function sum(x,y){
  if (y > 0) {
    return sum(x+1, y-1);
  } else {
    return x;
  }
}
// 会发生RangeError: Maximum call stack size exceed,即堆栈溢出
sum(1, 100000); 

// 蹦床函数
function trampoline(f) {
  while(f && f instanceof Function) {
    f = f();
  }
  return f;
}
// 每次sum函数执行都会返回自身的另一个版本
function sum(x, y) {
  if (y > 0) {
    return sum.bind(null, x + 1, y - 1);
  }
  return x;
}
trampoline(sum(1, 100000));复制代码

转载于:https://juejin.im/post/5a01703451882578d84edec7

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值