# 16.箭头函数

# 基础语法

普通函数: 1、函数作为全局函数被调用时,this 指向全局对象 2、函数作为对象中的方法被调用时,this 指向该对象 3、函数作为构造函数的时候,this 指向构造函数 new 出来的新对象 4、还可以通过 call,apply,bind 改变 this 的指向

1、箭头函数没有 this,函数内部的 this 来自于父级最近的非箭头函数,并且不能改变 this 的指向。 2、箭头函数没有 super 3、箭头函数没有 arguments 4、箭头函数没有 new.target 绑定。 5、不能使用 new 6、没有原型 7、不支持重复的命名参数。

通常函数的定义方法

var fn1 = function (a, b) {
  return a + b;
};

function fn2(a, b) {
  return a + b;
}
1
2
3
4
5
6
7

使用 ES6 箭头函数语法定义函数,将原函数的“function”关键字和函数名都删掉,并使用“=>”连接参数列表和函数体。

var fn1 = (a, b) => {
  return a + b;
};

(a, b) => {
  return a + b;
};
1
2
3
4
5
6
7

箭头函数相当于匿名函数(不完全是,后面介绍)

当函数参数只有一个,括号可以省略;但是没有参数时,括号不可以省略。

// 无参
var fn1 = function () {};
var fn1 = () => {};

// 单个参数
var fn2 = function (a) {};
var fn2 = (a) => {};

// 多个参数
var fn3 = function (a, b) {};
var fn3 = (a, b) => {};

// 可变参数
var fn4 = function (a, b, ...args) {};
var fn4 = (a, b, ...args) => {};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

如果返回一个对象,需要特别注意,如果是单表达式要返回自定义对象,不写括号会报错,因为和函数体的{ ... }有语法冲突。 注意,用小括号包含大括号则是对象的定义,而非函数主体

(x) => {
  key: x;
}; // 报错
(x) => ({
  key: x,
}); // 正确
1
2
3
4
5
6

箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别: 箭头函数内部的 this 是词法作用域(块级作用域),由上下文确定。(词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变 。)

非箭头函数

在这里插入图片描述

现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 Person

在这里插入图片描述

由于 this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略

JavaScript 中的每一个 Function 对象都有一个 apply()方法和一个 call()方法

apply 调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即 A 对象调用 B 对象的方法。func.apply(thisArg, [argsArray]) call 调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1, args2);即 A 对象调用 B 对象的方法。func.call(thisArg, arg1, arg2, ...)

在这里插入图片描述

# 箭头函数与 function 的区别

# 1、this 的指向:

使用 function 定义的函数,this 的指向随着调用环境的变化而变化的,而箭头函数中的 this 指向是固定不变的,一直指向的是定义函数的环境。 如上面所说的。

# 2、构造函数

function 是可以定义构造函数的,而箭头函数是不行的。

//使用function方法定义构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}
var lenhart = new Person(lenhart, 25);
console.log(lenhart); //{name: 'lenhart', age: 25}

//尝试使用箭头函数
var Person = (name, age) => {
  this.name = name;
  this.age = age;
};
var lenhart = new Person("lenhart", 25); //Uncaught TypeError: Person is not a constructor
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3、变量提升

由于 js 的内存机制,function 的级别最高,而用箭头函数定义函数的时候,需要 var(let const 定义的时候更不必说)关键词,而var 所定义的变量不能得到变量提升,故箭头函数一定要定义于调用之前!

foo(); //123
function foo() {
  console.log("123");
}

arrowFn(); //Uncaught TypeError: arrowFn is not a function
var arrowFn = () => {
  console.log("456");
};
1
2
3
4
5
6
7
8
9

# 什么时候不该使用箭头函数

# 1、在对象上定义函数

var obj = {
  array: [1, 2, 3],
  sum: () => {
    console.log(this === window); // => true
    console.log(this.window.array); // => [1,2,3]
    console.log(this.array); // => undefined
  },
};
obj.sum();
1
2
3
4
5
6
7
8
9

sum 方法定义在 obj 对象上,当调用的时候我们发现了一个 undefined,因为函数中的 this 是 window 对象,所以 this.array 也就是 undefined。原因也很简单,相信只要了解过 es6 箭头函数的都知道

箭头函数没有它自己的 this 值,箭头函数内的 this 值继承自外围作用域

解决方法也很简单,就是不用呗。这里可以用 es6 里函数表达式的简洁语法,在这种情况下,this 值就取决于函数的调用方式了。

var obj = {
  array: [1, 2, 3],
  sum() {
    console.log(this === obj); // => true
  },
};

obj.sum();
1
2
3
4
5
6
7
8

顺便提一嘴

var obj = {
  array: [1, 2, 3],
  sum() {
    console.log(this.array); // => true
  },
};
array = "22";

obj.sum(); // => [1,2,3]
var test = obj.sum;
test(); // => '22'
//也就是说,对象里面的函数,谁调用,this指向谁。
1
2
3
4
5
6
7
8
9
10
11
12

# 2、在原型上定义函数

在对象原型上定义函数也是遵循着一样的规则

# 3、动态上下文中的回调函数

this 是 js 中非常强大的特点,他让函数可以根据其调用方式动态的改变上下文,然后箭头函数直接在声明时就绑定了 this 对象,所以不再是动态的。 在客户端,在 dom 元素上绑定事件监听函数是非常普遍的行为,在 dom 事件被触发时,回调函数中的 this 指向该 dom, 可当我们使用箭头函数时:

var button = document.getElementById("myButton");
button.addEventListener("click", () => {
  console.log(this === window); // => true
  this.innerHTML = "Clicked button";
});
1
2
3
4
5

因为这个回调的箭头函数是在全局上下文中被定义的,所以他的 this 是 window。所以当 this 是由目标对象决定时,我们应该使用函数表达式。

# 4、构造函数中

在构造函数中,this 指向新创建的对象实例

this instanceOf MyFunction === true

需要注意的是,构造函数不能使用箭头函数,如果这样做会抛出异常

var Person = (name) => {
  this.name = name;
};

// Uncaught TypeError: Person is not a constructor
var person = new Person("wdg");
1
2
3
4
5
6
Last Updated: 6/3/2024, 1:08:34 AM