zoukankan      html  css  js  c++  java
  • ES6使用箭头函数注意点

    新事物也是有两面性的,箭头函数有他的便捷有他的优点,但是他也有缺点,他的优点是代码简洁,this提前定义,但他的缺点也是这些,比如代码太过简洁,导致不好阅读,this提前定义,导致无法使用JS进行一些ES5里面看起来非常正常的操作。

    本质来说箭头函数没有自己的this,它的this是派生而来的,根据“词法作用域”派生而来。

    由于箭头函数在调用时不会生成自身作用域下的thisarguments值,其持有外部包含它的函数的this值,并且在调用的时候就定下来了,不可动态改变,下面我就总结一下什么情况下不该使用箭头函数。

    在对象上定义函数

    const test = {
        array: [1, 2, 3],
        sum: () => {
            console.log(this === window); // => true
            return this.array.reduce((result, item) => result + item);
        }
    };
    test.sum();
    // TypeError: Cannot read property 'reduce' of undefined
    

    原因就是,箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域。

    对象方法内的this指向调用这个方法的对象,如果使用箭头函数,this和对象方法在调用的时候所处环境的this值一致。因为 test.sum()是在全局环境下进行调用,此时this指向全局。

    解决方法也很简单,使用函数表达式或者方法简写(ES6 中已经支持)来定义方法,这样能确保 this 是在运行时是由包含它的上下文决定的。

    const test = {
        array: [1, 2, 3],
        sum() {
            console.log(this === test); // => true
            return this.array.reduce((result, item) => result + item);
        }
    };
    test.sum();
    // 6
    

    定义原型方法

    在对象原型上定义函数也是遵循着一样的规则

    function Person(name) {
        this.name = name;
    }
    
    Person.prototype.sayName = () => {
        console.log(this === window); // => true
        return this.name;
    };
    
    const cat = new Person('Mew');
    cat.sayName(); // => undefined
    

    使用传统的函数表达式就能解决问题

    function Person(name) {
        this.name = name;
    }
    
    Person.prototype.sayName = function() {
        console.log(this === Person); // => true
        return this.name;
    };
    
    const cat = new Person('Mew');
    cat.sayName(); // => Mew
    

    定义事件回调函数

    thisJS中非常强大的特点,他让函数可以根据其调用方式动态的改变上下文,然后箭头函数直接在声明时就绑定了this对象,所以不再是动态的。

    在客户端,在DOM元素上绑定事件监听函数是非常普遍的行为,在DOM事件被触发时,回调函数中的this指向该DOM,但是,箭头函数在声明的时候就绑定了执行上下文,要动态改变上下文是不可能的,在需要动态上下文的时候它的弊端就凸显出来:

    const button = document.getElementById('myButton');
    button.addEventListener('click', () => {
        console.log(this === window); // => true
        this.innerHTML = 'Clicked button';
    });
    

    因为这个回调的箭头函数是在全局上下文中被定义的,所以他的thiswindow。换句话说就是,箭头函数预定义的上下文是不能被修改的,这样 this.innerHTML 就等价于 window.innerHTML,而后者是没有任何意义的。

    使用函数表达式就可以在运行时动态的改变 this

    const button = document.getElementById('myButton');
    button.addEventListener('click', function() {
        console.log(this === button); // => true
        this.innerHTML = 'Clicked button';
    });
    

    定义构造函数

    如果使用箭头函数会报错。

    显然,箭头函数是不能用来做构造函数。

    const Message = (text) => {
        this.text = text;
    };
    const helloMessage = new Message('Hello World!');
    // Throws "TypeError: Message is not a constructor"
    

    理论上来说也是不能这么做的,因为箭头函数在创建时this对象就绑定了,更不会指向对象实例。

    太简短的(难以理解)函数

    箭头函数可以让语句写的非常的简洁,但是一个真实的项目,一般由多个开发者共同协作完成,箭头函数有时候并不会让人很好的理解:

    const multiply = (a, b) => b === undefined ? b => a * b : a * b;
    const double = multiply(2);
    double(3); // => 6
    multiply(2, 3); // => 6
    

    代码看起来很简短,但大多数人第一眼看上去可能无法立即搞清楚它干了什么。

    这个函数的作用就是当只有一个参数a时,返回接受一个参数b返回a*b的函数,接收两个参数时直接返回乘积。

    为了让这个函数更好的让人理解,我们可以为这个箭头函数加一对花括号,并加上return语句,或者直接使用函数表达式:

    function multiply(a, b) {
        if (b === undefined) {
            return function(b) {
                return a * b;
            }
        }
        return a * b;
    }
    
    const double = multiply(2);
    double(3); // => 6
    multiply(2, 3); // => 6
    

    毫无疑问,箭头函数带来了很多便利。恰当的使用箭头函数可以让我们避免使用早期的.bind()函数或者需要固定上下文的地方并且让代码更加简洁。

    箭头函数也有一些不便利的地方。我们在需要动态上下文的地方不能使用箭头函数:定义对象方法、定义原型方法、定义构造函数、定义事件回调函数。在其他情况下,请尽情的使用箭头函数。

  • 相关阅读:
    关于metaclass,我原以为我是懂的
    有趣的版本号
    关于乱序(shuffle)与随机采样(sample)的一点探究
    我在博客园的这一年
    我的进程去哪儿了,谁杀了我的进程
    Elasticsearch学习系列之term和match查询
    数据库垂直拆分 水平拆分
    分布式锁的几种实现原理
    Redis常见面题
    github建仓库注意
  • 原文地址:https://www.cnblogs.com/liangyin/p/7823441.html
Copyright © 2011-2022 走看看