欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ES6之箭头函数深入理解

程序员文章站 2022-03-22 12:13:24
相对于普通函数的区别 新的书写方式 this 的改变 不能当构造函数 没有 prototype 属性 没有 arguments 对象 新的书写方式 书写方式很简单!直接看下图, 常规方式写一个函数 const fun = function(number){ return number * 2 } 使 ......

相对于普通函数的区别

新的书写方式 

this 的改变

不能当构造函数

没有 prototype 属性

没有 arguments 对象

 

新的书写方式

书写方式很简单!直接看下图,

常规方式写一个函数
const fun = function(number){
    return number * 2
}
 
使用箭头函数
const fun = (number) => {
    return number * 2
}
 
如果只有一个参数,还可以省略前面的小括号
const fun = number => {
    return number * 2
}
 
如果只有一条执行语句,甚至可以省略后面的大括号,而且可以也不能写 return
const fun = number => number * 2 
 
也可以写成立即执行函数
const fun = (() => 3 * 2)()  // 6

 

this的改变

执行上下文

讨论箭头函数的 this 之前,不得不再熟悉一下 执行上下文(execution context),因为 this 指针(this value) 就存储在执行上下文中。

执行上下文保存着函数执行所需的重要信息,其中有三个属性:变量对象(variable object),作用域链(scope chain),this指针(this value),它们影响着变量的解析、变量作用域、函数 this 的指向。执行上下文分为 全局执行上下文函数执行上下文

全局代码开始执行前,会以 window 为目标产生一个全局执行上下文, 开始对代码预编译,这时候 this 指向的就是 window,接着开始执行全局代码。

当函数代码开始执行前,会以函数为目标产生一个函数执行上下文,开始对该函数预编译,这时候 this 的指向要分几种情况(下面讨论),接着开始执行函数代码,函数代码执行完后函数执行上下文就被会删除。多个函数会产生多个执行上下文。

上面说到函数预编译的 this 分下面四种情况:

第一种: 函数自主调用 如 fun() 或者是 普通的立即执行函数(区别于箭头函数方式的立即执行函数), this 指向 window

第二种: 函数被调用,当函数被某个对象调用时,函数产生的执行上下文中的 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 指针指向 window,自然就打印 window 对象了

可能有人会有这个疑惑: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 就是 window 对象

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