ES6 ——箭头函数

137 阅读5分钟

可以说是es6的一大亮点,使用箭头函数,可以简化编码过程,是代码更加的简洁。 箭头函数允许我们用更短的语法定义函数。箭头函数可用于替代传统函数function() {}。

允许使用“箭头”(=>)定义函数。

var f = a => a;
var f = function (a) {
  return a;
};

上面两个是同一个函数,实现功能都是返回a。可以看到使用箭头函数后代码简洁了很多。如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

var f = () => 5;
// 等同于
var f = function () { return 5 };
 
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

使用箭头函数,可以让我们的回调函数特别的简洁。

//正常函数写法
[1,2,3].map(function (x) {
  return x + x;
});
 
// 箭头函数写法
[1,2,3].map(x => x + x);

箭头函数在参数中使用

var arr= [1,2,3];
arr = arr.map((a)=>a*a);
console.log(arr);

箭头函数可以与解构一起使用

/变量为目标,返回值为源
let cal = (a, b) => {
    return {
        add: a+b,
        sub: a-b,
        mul: a*b,
        div: a/b
    };
}
let {add, sub, mul, div} = cal(10, 5);

//形参为目标,实参为源
var show = ({one, two}) => {
	console.log(one + "---" + two);
}
show({one: "hello", two: "你好"});

一、特点

1. 相比普通函数,箭头函数有更加简洁的语法。

普通函数

function add(num) {
  return num + 10
}

箭头函数

const add = num => num + 10;

2. 箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this。

这句话需要注意的是,箭头函数的外层如果有普通函数,那么箭头函数的this就是这个外层的普通函数的this,箭头函数的外层如果没有普通函数,那么箭头函数的this就是全局变量

  • 下面这个例子是箭头函数的外层有普通函数。
let obj = {
  fn:function(){
      console.log('我是普通函数',this === obj)   // true
      return ()=>{
          console.log('我是箭头函数',this === obj) // true
      }
  }
}
console.log(obj.fn()())
  • 下面这个例子是箭头函数的外层没有普通函数。
let obj = {
    fn:()=>{
        console.log(this === window);
    }
}
console.log(obj.fn())
// true

3. 箭头函数是匿名函数,不能作为构造函数,不可以使用new命令,否则后抛出错误。

let f = () => {};
let t =new f (); // f is not a constructor

4. 箭头函数不绑定arguments,取而代之用rest参数解决,同时没有super和new.target。

箭头函数没有arguments、super、new.target的绑定,这些值由外围最近一层非箭头函数决定。

下面的这个函数会报错,在浏览器环境下。

let f = ()=>console.log(arguments);
//报错
f(); // arguments is not defined

下面的箭头函数不会报错,因为arguments是外围函数的。

function fn(){
  let f = ()=> {
    console.log(arguments)
  }
  f();
}
fn(1,2,3) // [1,2,3]

箭头函数可以通过拓展运算符获取传入的参数。

const testFunc = (...args) =>{
    console.log(args);  [[1,2,3]] ,undefind
}
testFunc([1,2,3])

5. 使用call,apply,bind并不会改变箭头函数中的this指向。

当对箭头函数使用call或apply方法时,只会传入参数并调用函数,并不会改变箭头函数中this的指向。 当对箭头函数使用bind方法时,只会返回一个预设参数的新函数,并不会改变这个新函数的this指向。 请看下代码

window.name = "window_name";

let f1 = function () {
return this.name;
};
let f2 = () => this.name;

let obj = { name: "obj_name" };

console.log(f1.call(obj));  //obj_name
console.log(f2.call(obj));  // window_name
console.log(f1.apply(obj)); // obj_name
console.log(f2.apply(obj)); // window_name
console.log(f1.bind(obj)());  // obj_name
console.log(f2.bind(obj)());  // window_name

6. 箭头函数没有原型对象prototype这个属性

由于不可以通过new关键字调用,所以没有构建原型的需求,所以箭头函数没有prototype这个属性。

let F = ()=>{};
console.log(F.prototype) // undefined

二、arguments辨析

既然上文我们提到了arguments,那么下面我们就仔细讲讲这个arguments。

arguments有什么用?

arguments对象是所有非箭头函数中都可用的局部变量,可以使用arguments对象在函数中引用函数的参数,此对象包含传递给函数的每一个参数,第一个参数在索引0的位置。

如何将arguments对象转换为数组

通过slice 通过拓展运算符 通过Array.from

var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);

const args = Array.from(arguments);
const args = [...arguments];

arguments函数如何调用自身函数?

我们先看下面这个函数,这个是可以正常运行的。

function factorial (n) {
    return !(n > 1) ? 1 : factorial(n - 1) * n;
}

[1,2,3,4,5].map(factorial);

但是作为匿名函数则不行。

[1,2,3,4,5].map(function (n) {
    return !(n > 1) ? 1 : /* what goes here? */ (n - 1) * n;
});

因此arguments.callee诞生了。

[1,2,3,4,5].map(function (n) {
    return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});

所以arguments要想调用自身的匿名函数,可以通过arguments.callee来调用

(2)适合使用的场景

ES6 之前,JavaScript 的 this 对象一直很令人头大,回调函数,经常看到 var self = this 这样的代码,为了将外部 this 传递到回调函数中,那么有了箭头函数,就不需要这样做了,直接使用 this 就行。

所以,当我们需要维护一个 this 上下文的时候,就可以使用箭头函数。

(3)总结

面试题:

  • 要有个箭头
  • 箭头的前面是小括号,放形参,只有一个形参的时候可以省略小括号;
  • 箭头的后面是函数体;
  • 如果函数体只有一个语句,没有{},此时的返回值不需要return;
  • 箭头函数里面的this总是指向最靠近的function 内部的this;
  • 对象里面的方法,尽可能不要使用箭头函数;
  • 箭头函数里面没有arguments,可以使用…reset,接收过来就是数组类型,接收的是形参之外的所有的实参;
var show = (a, b, ...reset) => {
	console.log(a + b);
	console.log(reset);
}
show(1, 2, 3, 4, 5);