Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6箭头函数的坑 #2

Open
phenomLi opened this issue Sep 21, 2017 · 0 comments
Open

ES6箭头函数的坑 #2

phenomLi opened this issue Sep 21, 2017 · 0 comments

Comments

@phenomLi
Copy link
Owner

箭头函数() => ()是ECMAScript2015中代替function的一个语法糖,他增强了JS中Functional programming的能力。箭头函数与传统的functuon(){}声明并没有什么区别,但是在表现上,还是有一点微小区别的,而且这微小区别如果处理不好就会出现大bug。



先看看官方对箭头函数与function的区别的定义:

1、对 this 的关联。函数内置 this 的值,取决于箭头函数在哪儿定义,而非箭头函数执行的上下文环境。
2 、new 不可用。箭头函数不能使用 new 关键字来实例化对象,不然会报错。
3、this 不可变。函数内置 this 不可变,在函数体内整个执行环境中为常量。
4、没有arguments对象。更不能通过arguments对象访问传入参数。只能使用显式命名或其他ES6新特性来完成。




第四点不重要,重要的是前三点,简单来说,就是箭头函数和function对内部的this的处理是不一样的。function内部的this由function决定,而箭头函数的this则由上下文决定。下面来看一个小例子:

const obj = {
    a: function() {
        console.log(this);
    },
    b: () => {
        console.log(this);
    }
};
obj.a();  //输出obj
obj.b();  //输出window

可以看到在箭头函数中,this指针指向的是全局变量window。
为什么会这样呢,其实上面js字面量的写法就等同于下面这种:

const obj = {};
obj.a = function() {
    console.log(this);
};

obj.b = () => {
    console.log(this);
};

这时外层上下文并不是obj而是window,所以箭头函数里面this就指向了window。



有时候这种特性会很方便,比如,我们要在setTimeout函数里面获取当前对象,如果这样写:

const obj = {
    fn: function() {
        setTimeout(function() {
            console.log(this);  //window
        }, 0);
    }
};

会发现打印出来的值是window对象而不是obj,因为setTimeout的真正写法是window.setTimeout此时setTimeout里面的上下文是window,打印出来的自然是window。
但是如果想要在setTimeout里面获得obj该怎么办呢,一种老的hack写法是这样:

const obj = {
    fn: function() {

        const _this = this;  //保存当前上下文
        
        setTimeout(function() {
            console.log(_this);
        }, 0);
    }
};

老的写法是把当前this保存在一个变量里,但是这种写法毕竟是一种hack。现如今有了箭头函数,我们可以这样做:

const obj = {
    fn: function() {
        setTimeout(() => {       //使用箭头函数
            console.log(this);     //obj
        }, 0);
    }
};

因为箭头函数中的this根据的是外层上下文,而在setTimeout函数中内层是window,外层是obj,所以可以轻松拿到正确的值。





之前在写react的过程中,就遇到了箭头函数的一些坑,如在React.createClass方法中,最好不要用箭头函数来声明方法:

const trank = React.createClass({

    handler: () => {
        console.log('now the pointer "this" is ' + this + '.');      //点击div,打印出的this是window
        this.setState();      //同时setState方法也会无效
    },

    render: function() {
        return React.createElement('div', {onClick: this.handler}, 'hello');
    }

});

至于具体原因,上面也解释得很清楚了,就是上下文得问题,至于解决方法,目前只有两个:

  1. 不要用箭头函数,用回常规的function
  2. 使用ES6class语法定义React组件
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant