• [ES6系列-02]Arrow Function:Whats this?(箭头函数及它的this及其它)


    [原创] 码路工人

    大家好,这里是码路工人有力量,我是码路工人,你们是力量。


    如果没用过CSharp的lambda 表达式,也没有了解过ES6,那第一眼看到这样代码什么感觉?

    /* eg.0
     * function definition
     */
     
    var arr = [1,2,3,5,8,13,21]
    
    arr.forEach(n => console.log(n))
    

    数组的forEach 方法里需要传入一个函数(没用过 CSharp 里委托 delegate 的也许会觉得奇怪,js 里参数竟然可以是一个方法,其实 C# 里也是早就有的),这n =>是什么鬼?

    这是今天要说的主角,箭头函数Arrow Function

    #注:

    • C# 中操作集合的各种 lambda 表达式其实就是一个个简短的匿名函数,
    • ES6的箭头函数就可以理解为 C# 中的 lambda 表达式式的东西,
    • Python 中同样也是有 lambda 表达式的(当时用的时候有限定,只能写一句),
    • 只是不同语言间写法或语法不同,所以我有个观点就是:
    • 认真学一门语言,不只停留在入门,不能说精通也要达到进阶,
    • 再去学其它的,就会发现编程语言是相通的,编程思想更是相通的
    • 码工我不是搞 Java 的,但是会 C# 的看起 Java 代码也是不太费劲,因为真的很像
      => Java 里也有 lambda 。

    1. Arrow Function 的基本用法

    1.1 本质就是匿名函数

      普通定义一个函数,要用到function 关键字,不管是存在提升现象的function foo() { } 还是定义给变量var foo = function() { } ,这样的话调用时才能找到这个函数,就像每个人都有名字一样。
      匿名函数就不一样了,它没有名字,因此只能在定义它的位置调用(这么说不严谨,但不影响理解,具体见下文)。所以,用箭头函数去定义一个单独函数而不调用不执行,是没有意义的。当然能这么写,js本身不会报错。
      除了定义时的区别,匿名函数使用时,跟普通函数还是相似的,要么定义给一个变量,要么直接当作回调函数写在参数位置。
      因为本身就没有function 关键字和方法名,也就无法像ES5里那样定义类/构造函数。不可能也没理由这样用。如果 "var Foo = () => { }" 这样写,也不能当作类/构造函数,"new Foo()" 的时候会报错。毕竟用ES6的话也不会这样定义类。(用classconstructor

    /* eg.1
     * function definition
     */
     
    //-------------------------------------------------
    
    function logParam(param) {
        console.log(param)
    }
    
    logParam("foo")     // foo
    
    //-------------------------------------------------
    
    // Should not define a funtion using arrow-function itself
    // because no function name to call and will not execute
    (param) => console.log(param)
    
    const foo = (param) => console.log(param)
    foo("bar")       // bar
    
    //-------------------------------------------------
    

    1.2 基本使用特点

    • 普通的正常写法

      /* eg.2
      * arrow function
      */
      
      //-------------------------------------------------
      var arr = [1,2,3,5,8,13,21]
      
      // Normal:
      console.log(arr.map(function(item, index) {
          return `No.${index}: ${item}`
      }))
      //["No.0: 1", "No.1: 2", "No.2: 3", "No.3: 5", "No.4: 8", "No.5: 13", "No.6: 21"]
      
      // Use arrow function:
      console.log(arr.map((item, index) => {
          return `No.${index}: ${item}`
      }))
      //["No.0: 1", "No.1: 2", "No.2: 3", "No.3: 5", "No.4: 8", "No.5: 13", "No.6: 21"]
      //-------------------------------------------------
      

      最直观的一点就是写法上稍微简易了一丢丢。它基本的特点就是简易了,继续往下看。

    • 只有一个参数时,参数括号 可省略

      /* eg.2
      * arrow function
      */
      
      //-------------------------------------------------
      var arr = [1,2,3,5,8,13,21]
      
      // Normal:
      arr.forEach(function(item) {
          console.log("当前元素:" + item)
      })
      
      // Use arrow function:
      arr.forEach( item => {
          console.log("当前元素:" + item)
      })
      //-------------------------------------------------
      

      以上例子中只有一个item参数,所以参数括号省略了也能正常执行。

    • 方法体只有一句 { return expression } 时,花括号跟 return 可省略

      当然,如果本身就没有做return也是可以只省略花括号的,没有返回值处理时默认就是返回undefined

      /* eg.3
      * arrow function
      */
      //-------------------------------------------------
      
      var arr = [1,2,3,5,8,13,21]
      
      // Normal:
      arr.forEach(function(item){
          console.log("当前元素:" + item)
      })
      console.log(arr.map(function(item,index){
          return `No.${index}: ${item}`
      }))
      
      // Use arrow function:
      arr.foreach((item,index) => console.log(`No.${index}: ${item}`))
      console.log(arr.map((item,index) => `No.${index}: ${item}` ))
      
      //-------------------------------------------------
      

      以上例子中分别演示了无return与有return时箭头函数中的简便写法。
      执行结果可以在 chrome 浏览器下的 console 里查看(F12打开开发者模式)。

    1.3 补充:没有参数时

      没有参数的情况也是有的,可以跟普通函数一样,空括号就可以了。另外,还有一种约定俗成的写法:_ 。如下:

    /* eg.4
    * arrow function: no-param
    */
    
    //-------------------------------------------------
    const foo = () => "bar"
    const foo = _ => "bar"
    
    // as same as ↓
    const foo = function () {
        return "bar"
    }
    

    2. 其它特点

    2.1 this 指向的问题

      箭头函数用起来感觉轻便了许多,但也有不少问题。其中主要、最经常遇到的可能就是this指向问题了。

    /* eg.5
    * arrow function: this
    */
    //-------------------------------------------------
    
    const person = {
        name: "Coder Power",
        greet1: function() {
            console.log(this)
            console.log("Hello!I am " + this.name + ".")
        },
        greet2: () => {
            console.log(this)
            console.log("Hello!I am " + this.name + ".")
        }
    }
    
    // 'this' in normal function
    // is object person
    person.greet1()
    
    // 'this' in arrow function
    // is object window
    person.greet2()
    
    //-------------------------------------------------
    

      以上代码例子中,greet1this指向为person对象。这一点非常好理解,以外 js 中的 this 是谁调用,指向谁。

      而greet2中的this却指向了 window对象。怎么会这样?

      其实码工刚开始也没弄明白,只是知道 this 不一样。后来仔细想了想,箭头函数里的 this 为定义函数时它外部函数里的 this ,也就时在 person 定义中,这时的 this 就是 window。(window.person)

    • 箭头函数this总结
      => 函数没有自己的this
      => 函数里的this 是父级作用域里的this
      => 函数不能通过apply/call 的方式绑定this

      /* eg.6
      * arrow function: this
      */
      //-------------------------------------------------
      
      // can not change 'this' in arrow function
      // by apply/call
      person.greet2.call(person)
      person.greet2.apply(person)
      // ↑"this.name" will still be undefined
      //-------------------------------------------------
      

      所以在需要用到this 的方法中要慎重。

    2.2 ES6箭头函数的其它特点

      在前文 1.1 中我们就说了,箭头函数定义出来的函数变量不能通过new 来实例化出一个对象。
    它跟继承扯不上关系,不能做构造函数,也没有原型(prototype)。获取参数也仅限与方法调用传参,不能用arguments来取。

    ES6箭头函数中没有以下属性/对象:

    • 箭头函数不能new

    • 箭头函数没有prototype

    • 箭头函数没有super

      上一篇中介绍了 ES5 及 ES6 里的类与继承,其中 ES6 里子类的构造函数里必须先调用一次super 也就是父类的构造函数,才生成了实例对象this 。而箭头函数是没有super 的。

    • 箭头函数没有arguments

    • 箭头函数没有new.target (本来就不能 new ,就更没有 new.target 了)

      上述这些相对不常用或说在使用箭头函数时相关性较小,箭头函数本意是简化书写,更多的是用在填写一个普通的回调函数上。


    读到这里,对于 JavaScript/ES6 里箭头函数 Arrow Function 的使用方法就掌握差不多了吧。
    思考一下,哪些场景下适合/不适合用箭头函数呢?可以评论区留个言再走啊~

    希望对你能有帮助,下篇再见。


    欢迎关注分享,一起学习提高吧。
    QRCode/微信订阅号二维码

    QRCode


    作者:码路工人

    公众号:码路工人有力量(Code-Power)

    欢迎关注个人微信公众号 Coder-Power

    一起学习提高吧~

  • 相关阅读:
    数据仓库的直白概述
    Google准实时数据仓库Mesa(一)
    活动预告丨易盾CTO朱浩齐将出席2018 AIIA大会,分享《人工智能在内容安全的应用实践》
    3招搞定APP注册作弊
    【0门槛】PR稿的自我修养
    Hive中文注释乱码解决方案(2)
    Hive中文注释乱码解决方案
    网易考拉Android客户端网络模块设计
    有运气摇号来不及挑选?网易有数帮你科学选房
    selenium下拉框踩坑埋坑
  • 原文地址:https://www.cnblogs.com/CoderMonkie/p/arrow-function-in-es6.html
Copyright © 2020-2023  润新知