美文网首页
箭头函数

箭头函数

作者: 小泡_08f5 | 来源:发表于2019-06-26 19:14 被阅读0次

    先来看看箭头函数的基本语法:

    let func = value => value;
    
    // 相当于
    let func = function (value) {
        return value;
    };
    

    如果需要给函数传入多个参数:

    let func = (value, num) => value * num;
    

    如果函数的代码块需要多条语句:

    let func = (value, num) => {
        return value * num
    };
    

    如果需要直接返回一个对象:

    let func = (value, num) => ({total: value * num})
    

    与变量解构结合:

    let func = ({value, num}) => ({total: value * num})
    
    // 使用
    var result = func({
        value: 10,
        num: 10
    })
    
    console.log(result); // {total: 100}
    
    比较

    比较一下箭头函数与普通函数的区别:
    1. 没有this
    2. 没有 arguments
    3. 不能通过new 关键字调用
    4. 没有new.target
    5. 没有原型
    6. 没有 super

    1. 没有this
    箭头函数没有this,所以需要通过查找作用域链来确定this的值。

    这就意味着箭头函数被非箭头函数包含,this绑定的就是最近一层非箭头函数的this

    模拟一个例子:
    点击一个按钮,改变该按钮的背景色

    为了方便开发, 我们抽离了一个Button组件,当需要使用的时候,直接可以用下面代码调用:

    // 传入元素 id 值即可绑定该元素点击时改变背景色的事件
    new Button("button")
    

    HTML代码如下:

    <button id="button">点击变色</button>
    

    js代码如下:

    // 箭头函数没有this,所以需要通过查找作用域链来确定this的值
            function Button(id) {
                this.element = document.querySelector("#" + id);
                this.bindEvent();
            }
            
            Button.prototype.bindEvent = function() {
               this.element.addEventListener("click", this.setBgColor, false); 
                // this.element.addEventListener("click", this.setBgColor.bind(this), false); // es5的解决办法
                // this.element.addEventListener("click", (e) => {this.setBgColor(e)}, false);
            };
            
            Button.prototype.setBgColor = function() {
                console.log(this);
                this.element.style.backgroundColor = '#1abc9c'
            };
            
            var button = new Button("button");
    

    点击按钮报错了


    image.png

    看着好像没有问题, 结果却是报错。
    打印一下代码里的this


    image.png

    这是因为当使用addEventListener() 为一个元素注册事件的时候, 事件函数里的this值是该元素的引用, 所以如果我们在setBgColor中 console.log(this), this指向的是按钮元素, 那this.element就是undefined了,所以报错了

    既然this都指向了按钮元素, 那我们直接修改setBgColor函数为

    Button.prototype.setBgColor = function() {
        this.style.backgroundColor = '#1abc9c'
    };
    

    问题确实可以解决了, 但是在实际的开发中,可能会在setBgColor中还调用其他的函数, 比如写成这种:

    Button.prototype.setBgColor = function() {
        this.setElementColor();
        this.setOtherElementColor();
    };
    

    所以还是希望setBgColor中的this是指向实例对象的, 这样就可以调用其他的函数,
    可以利用bind显式绑定setBgColor()的this为实例对象

    Button.prototype.bindEvent = function() {
        this.element.addEventListener("click", this.setBgColor.bind(this), false);
    };
    

    现在用ES6, 可以更好的解决这个问题:

    this.element.addEventListener("click", (e) => {this.setBgColor(e)}, false);
    

    由于箭头函数没有this, 所以会向外层查找this的值, 即bindEvent中的this, 此时this指向实例对象,所以可以正确的调用this.setBgColor方法, 而this.setBgColor中的this也会正确指向实例对象。

    在这里再额外提一点, 就是注意bindEvent和setBgColor在这里使用的是普通函数的形式,而非箭头函数, 如果我们改成箭头函数, 会导致函数里的this指向window(非严格模式下)

    最后,因为箭头函数没有this, 所以也不能用call(), apply(), bind()这些方法改变this指向,

    var value = 1;
    var result = (() => this.value).bind({value: 2})();
    console.log(result); // 1
    

    2. 没有arguments
    箭头函数没有自己的arguemnts, 不过箭头函数可以访问外围函数的arguments对象

    constant = () => {
        console.log(arguments);
    }
    
    var result = constant(1);
    console.log(result()); 
    
    image.png
    function constant() {
        return () => arguments[0]
    }
    
    var result = constant(1);
    console.log(result()); // 1
    
    image.png

    此时的箭头函数访问的是外围函数constant的arguments

    那如果我们就是要访问箭头函数的参数呢?
    可以通过命名参数或者rest参数的形式访问参数

    let nums = (...nums) => console.log(nums);
    nums(1,2,3)
    
    image.png

    3. 不能通过new关键字调用

    var Foo = () => {};
    var foo = new Foo(); // TypeError: Foo is not a constructor
    

    箭头函数没有[[Construct]]方法,不能被用作构造函数,如果通过new的方式调用,会报错。

    因为JavaScript函数有两个内部方法: [[Call]] 和 [[Construct]],
    当通过new 调用函数时, 执行 [[Construct]]方法,创建一个实例对象,然后再执行函数体, 将this绑定到实例上。
    当直接调用的时候, 执行[[Call]] 方法,直接执行函数体。

    4. 没有new.target
    因为不能使用new调用,所以也没有new.target值

    5. 没有原型
    由于不能使用new调用箭头函数, 所以也没有构建原型的需求,于是箭头函数也不存在prototype这个属性

    var Foo = () => {};
    console.log(Foo.prototype); // undefined
    

    6. 没有super
    连原型都没有,自然也不能通过super来访问原型的属性,所以箭头函数也是没有super的,不过很this,arguments,new.targer由于,这些值由外围最近一层非箭头函数决定。

    总结

    箭头函数表达式的语法比函数表达式更端,并且不绑定自己的this,arguments, super或new.target. 这些函数表达式最适合用于非方法函数,并且它们不能用作构造函数。

    那什么是非方法函数?
    对象属性中的函数被称为方法, 那么非方法函数就是指不被用作对象属性中的函数了。

    var obj = {
      i: 10,
      b: () => console.log(this.i, this),
      c: function() {
        console.log( this.i, this)
      }
    }
    obj.b();
    // undefined Window
    obj.c();
    // 10, Object {...}
    

    自执行函数
    自执行函数形式为:

    image.png
    最后改成
    ((() => {
        console.log(1)
    })()) // 1
    

    相关文章

      网友评论

          本文标题:箭头函数

          本文链接:https://www.haomeiwen.com/subject/djvqcctx.html