彻底弄懂ES6「箭头函数」!

325 阅读3分钟

基本语法

ES3 具名函数

    function xxx(p1, p2) {
        console.log(1)
        return 2
    }

匿名函数

    let xxx = function (p1, p2) {
        console.log(1)
        return 2
    }
// 首先声明一个匿名函数
    function (p1, p2) {
        console.log(1)
        return 2
    }

然后声明 let xxx
最后把匿名函数赋值给 xxx
在ES3中以上写法等价于

    var xxx
    temp = function (p1, p2) {
        console.log(1)
        return 2
    }
    xxx = temp

ES6中箭头函数写法

    let xxx = (p1, p2) => {
        console.log(1)
        return 2
    }

如果只有一个参数,那么可以不用写括号

    let xx2 = p1 => {
        console.log(1)
        return 2        
    }

如果函数体只有一句话

    let xx3 = (p1, p2) => {return p1 + p2}

那么就可以不用写括号,简写成

    let xx3 = (p1, p2) => p1 + p2  // 加了花括号,那么就必须加return
    
    // 极简化,当有一个值时
    let xx4 = p1 => p1 * 2

为什么会有箭头函数

没有箭头函数的之前

    function() {
        // 里面有关于this的难点
    }

this 是 call 的第一个参数

  1. 因为 this 太难用了
  2. JS ES3 支持 this 的
  3. ES6 也也支持 this, 但是箭头函数弱化了 this 的用法

ES3 怎么用 this 的

    function f(p1, p2){
       // var p1 = arguments[0]
       // var p2 = arguments[1]
        console.log(p1)
    }
    
    f('abc')
    // 当只有 p1 时,p1的值是由 f(这个玩意决定的)
    // 当有 p1、p2 时,p2的值是由 f(不是这个, 这个玩意决定的)
    // 构造一个arguments对象,arguments = [不是这个, 这个玩意决定的] 

让我们来到 this

    function f(p1, p2) {
        console.log(this)
    }

请问 this 哪来的呢?它是什么?

    let object = {
        name: "obj",
        hi: function(p1, p2){
            console.log(this.name)
        }
    }
    
    object.hi(1, 2)
    // tihs 的值是谁?

从 python 的角度来看

    class MyClass
        """A simple example class"""
        def hi(self):
            return 'hellow word'
    x = MyClass()
    x.hi() // hellow word
    
    class MyClass
        """A simple example class"""
        name = 'my name'
        def hi(self, p1):
            print self.name
            print p1
    x = MyClass()
    x.name // my name
    x.hi(1)
    // my name 
    // 1        

那么

    let object = {
        name: "obj",
        hi: function(/* this, */p1, p2){ // JS 把this 隐藏起来了
            console.log(this.name)
        }
    }
    
    object.hi(/* object, */1, 2)
  • p1 的值是由 object.hi(这个玩意决定的)
  • p2的值是由 object.hi(不是这个, 这个玩意决定的)
  • this 的值是由 这个玩意.决定的hi() object.hi(1, 2) 等价于 object.hi.call(object, 1, 2)
  • 还可以说成 this 的值是由 object.hi.call(这个, 1, 2)

this 有啥问题?

    var controller = {
        el: '#app',
        init: function(){
            $(this.el).on('click', this.xxx)
        },
        onClick: function(){
            console.log('用户点击 #app 就会调用这个函数')
            // 这里的this 是什么?
            this.getUsers()
            // this 是你调这个函数决定的,不是你写这个函数决定的,它是调用的时候传的参数
        },
        getUsers: function(){
        
        }
    }
    
    controller.init()
    controller.init.call(controller) // this 是call 的第一参数

请问 this.xxx 这个函数会被调用,那它调用的时候, call 第一个参数是什么?
没有地方看调用啊=-=,jQuery 源码里有 this.xxx.call(元素),不看它调用就不知道它传的到底是个啥。在不知道调用形式的情况下无法确定形参,它们必须在调用的时候才能确定, this 也是这样的,也就是说 this 的确定方式和p1 p2 的确定方式一模一样。
那该如何知道 this.getUsers()?我又不知道,那就不用它呗

    var controller = {
        el: '#app',
        init: function(){
            var self = this // 把外面 this保留下来(坑的没有办法写的)
            $(this.el).on('click', function(/* this */){ // 每个函数都有一个隐藏的this,那么这样就没有用到外面的this了
                this.xxx() //这个this不是外面的,它是一个元素,每一个函数都会把this改一遍,去赋值,值为多少我不知道,它的值可不是 controller!!!
                self.this() // self === controller
            })
        },
        xxx: function(){
            console.log('用户点击 #app 就会调用这个函数')
            this.getUsers()
        },
        getUsers: function(){
        
        }
    }
    
    controller.init()
    controller.init.call(controller)

为了不要去隐藏的改这个 this 于是,就有了箭头函数

    var controller = {
        el: '#app',
        init: function(){ 
            $(this.el).on('click', () => { //箭头函数第一个参数就是第一个参数,它没有隐藏的 this 
                this.xxx() // this === controller
            })
        },
        xxx: function(){
            console.log('用户点击 #app 就会调用这个函数')
            this.getUsers()
        },
        getUsers: function(){
        
        }
    }
    
    controller.init()
    controller.init.call(controller)

怎么证明箭头函数没有隐藏this的概念呢?

  1. 最外面的this是啥?fn()

global的this.png

  1. fn.call(xx)

截屏2021-09-28 下午11.35.12.png

截屏2021-09-28 下午11.35.26.png

截屏2021-09-28 下午11.41.54.png

总结

  1. 以前的函数永远都保留了一个潜在的参数,这个参数没有办法手动去指定,除非用 call ,JS 为了让这个参数自动的传进去,就不得不妥协,做了一个隐藏的 this 参数,python则是直接将其放在面前。
  2. 这段代码里的 this 是什么?
  • fn()
    this => window/global
  • obj.fn()
    this => obj
  • fn.call(xx)
    this => xx
  • fn.apply(xx)
    this => xx
  • fn.bind(xx)
    this => xx
  • new Fn()
    this => 新的对象
  • fn = ()=> {}
    this => 外面的 this