this 的改变
执行上下文
讨论箭头函数的 this 之前, 不得不再熟悉一下 执行上下文 (Execution Context), 因为 this 指针 (this value) 就存储在执行上下文中.
执行上下文保存着函数执行所需的重要信息, 其中有三个属性: 变量对象 (variable object), 作用域链 (scope chain),this 指针 (this value), 它们影响着变量的解析, 变量作用域, 函数 this 的指向. 执行上下文分为 全局执行上下文 和 函数执行上下文.
全局代码开始执行前, 会以 Windows 为目标产生一个全局执行上下文, 开始对代码预编译, 这时候 this 指向的就是 Windows, 接着开始执行全局代码.
当函数代码开始执行前, 会以函数为目标产生一个函数执行上下文, 开始对该函数预编译, 这时候 this 的指向要分几种情况 (下面讨论), 接着开始执行函数代码, 函数代码执行完后函数执行上下文就被会删除. 多个函数会产生多个执行上下文.
上面说到函数预编译的 this 分下面四种情况:
第一种: 函数自主调用 如 fun() 或者是 普通的立即执行函数 (区别于箭头函数方式的立即执行函数), this 指向 Windows;
第二种: 函数被调用, 当函数被某个对象调用时, 函数产生的执行上下文中的 this 指向 该对象;
第三种: 通过 call() apply() bind() 方法改变 this,this 指向被传入的 第一个参数;
第四种: 在构造函数中, this 指向被创建的 实例
由于箭头函数是不能通过 call() apply() bind() 方法改变 this, 也不能当做构造函数, 所以接下来只演示第一和第二种情况的代码
- var a = {
- origin: 'a',
- b: {
- origin: 'b',
- show: function(){
- var origin = 'show';
- console.log(this.origin);
- }
- }
- }
- var origin = 'window'
- a.b.show(); // 因为 b 对象调用了 show 函数, 所以 show 函数的执行上下文中的 this 指针指向 b 对象
- var fun = a.b.show; // 注意这里是将 show 函数赋值给 fun, 相当于 var fun = function(){console.log(this)}
- fun(); // 因为 fun 是自主调用, 所以 this 指针指向 Windows, 自然就打印 Windows 对象了
可能有人会有这个疑惑: a.b.show() 中, a 调用了 b, 是不是 b 的 this 指向 a 了?
前面也说到了, this 储存在执行上下文中, 而只有 全局 和 函数 才会产生执行上下文, 在执行上下文里记录着 this, 而 b 是全局中 a 对象里面的一个对象, 不存在谁调用它, 它的 this 就是谁的说法.
接下来理解箭头函数中的 this 就非常容易了.
箭头函数中的 this
首先, 箭头函数不会创建自己的 this, 它只会从自己的作用域链上找父级执行上下文的 this, 而不是谁调用它, 它的 this 就是谁. 所以箭头函数中的 this, 取决于你上层执行上下文的 this .
下例中,
obj 分别调用了 show1 和 show2 两个方法, 所以 show1 和 show2 中的 this 都是指向 obj,
show1 中, setTimeout 里面是箭头函数, 从作用域链中找到 show1 中的 this, 所以它的 this 就是 obj 对象;
show2 中, setTimeout 里面的函数换成普通函数, 函数自主调用, 所以他的 this 就是 Windows 对象
- var id = 0;
- var obj = {
- id: 1,
- show1: function(){
- setTimeout(() => {
- console.log(this.id)
- }, 1000)
- },
- show2: function(){
- setTimeout(function(){
- console.log(this.id)
- }, 2000)
- }
- }
- obj.show1(); // 打印 1
- obj.show2(); // 打印 0
不能当成构造函数
- var Foo = () => {
- };
- var foo = new Foo(); // TypeError: Foo is not a constructor
没有 prototype 属性
- var Foo = () => {
- };
- console.log(Foo.prototype); // undefined
没有 arguments 对象
在大多数情况下, 使用'...' 运算符是比使用 arguments 对象的更好选择.
- function foo(...arg) {
- return arg;
- }
- foo(1, 2, 3, 4); // 1
- function foo(...numbers) {
- numbers.forEach((number)=>{
- console.log(number);
- })
- }
- foo(1, 2, 3, 4); // 1 2 3 4
来源: https://www.cnblogs.com/wangjie-nf/p/10939704.html