【重学前端】ECMAScript6 - 函数的扩展

33 阅读2分钟

函数的扩展

length

函数的length属性,用于返回函数的参数个数。但需要注意的是,如果我们使用了参数默认值,则length属性只能返回没有默认值的参数个数。

function func1(a, b, c){}
console.log(func1.length); // 3

function func2(a, b = 1, c = 2) {}
console.log(func2.length); // 1

length有什么用?比如我们可以自己手写一个不算太完美的柯里化函数。

function curry(fn){
  let acceptArgs = [];
  let fnArgsLen = fn.length;
  return function next() {
    acceptArgs.push(...arguments);
    if (acceptArgs.length < fnArgsLen) {
      return next;
    } else {
      return fn.apply(null, acceptArgs);
    }
  }
}

function add(a, b, c) {
  return a + b + c;
}

let newAdd = curry(add);
console.log(newAdd(1)(2)(3)); // 6
// newAdd(1,2)(3)或newAdd(1,2,3)也可以

name

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

function hello(){}
console.log(hello.name); // hello

console.log((new Function()).name); // anonymous

// 使用bind之后的函数,前缀会加上bound
console.log(hello.bind({}).name); // bound hello

箭头函数

主要聚焦于箭头函数的使用注意点。

  • 箭头函数没有自己的this对象;
  • 不能当作构造函数,即不能对箭头函数使用new
  • 箭头函数内没有arguments对象;
  • 不能用作Generator函数,不能使用yield命令。

this

最需要注意的便是箭头函数内部的this指向问题。因为箭头函数没有自己的this对象,箭头函数的this永远指向它定义时所在的上层作用域(也可以理解为外层第一个普通函数的this),且不会改变。所以callapplybind这些改变this指向的不会生效。

let a = {
  i: 0,
  func1: function() {
    console.log('func1: ' + this.i);
  },
  func2: () => {
    console.log('func2: ' + this.i);
  }
}

let obj = {
  i: 100,
}
var i = 500; 
a.func1.call(obj); // 100
a.func2.call(obj); // 500,func2在定义时,它的外层能够拿到this的便是window。如果将var i改用let声明,因为let声明的变量并不是挂在window上,则不是输出500,而是undefined

再添加一个例子巩固:

var i = 'window'
let obj = {
  i: 'obj',
  func: function() {
    return () => {
      console.log(this.i);
    }
  },
  func2: function() {
    return function() {
      console.log(this.i);
    }
  }
}
let obj2 = {
  i: 'obj2'
}
let newFunc = obj.func().bind(obj2); // 即使用了bind,仍旧指向原来的的调用对象obj。
let newFunc2 = obj.func2().bind(obj2);
newFunc(); // obj
newFunc2(); // obj2

new

因为new的原理中涉及到this的绑定,那没有this的箭头函数自然而然不能当作一个构造函数来new。不能使用new,那也就无法使用ES6新引入的属性new.target

const A = () => {}
let a = new A(); // Uncaught TypeError: A is not a constructor

arguments

箭头函数内部没有自己的arguments对象。

const func = () => {
  console.log(arguments); // Uncaught ReferenceError: arguments is not defined
}
func();

需要使用rest参数来代替。

const hello = (...rest) => {
  console.log(rest);
}

hello(1,2,3); // [1,2,3]

generator

直接在语法上就无法将generator函数的符号*拼凑上去。

箭头函数不适用的场景

如果我们需要用this来判断调用发生的目标对象,则不适合用箭头函数。

<button>click</button>
<script>
  const btn = document.querySelector('button');
  btn.addEventListener('click', () => {
    console.log(this); // 此时this指向window,改window上的innerHTML没有实际意义了
    this.innerHTML = 'Changed!';
  });

  // 需改成
  btn.addEventListener('click', function() {
    console.log(this);
    this.innerHTML = 'Changed!';
  });
</script>

总结来说,就是如果一个函数内部需要用到动态this(在执行时确定),则不适合使用箭头函数。

参考