美文网首页
箭头函数

箭头函数

作者: yujiawei007 | 来源:发表于2017-08-24 12:12 被阅读0次

    箭头函数

    ES6标准新增了一种新的函数:Arrow Function(箭头函数)。

    为什么叫Arrow Function?因为它的定义用的就是一个箭头:

    x => x * x
    

    上面的箭头函数相当于:

    function (x) {
        return x * x;
    }
    

    箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }return

    x => {
        if (x > 0) {
            return x * x;
        }
        else {
            return - x * x;
        }
    }
    

    如果参数不是一个,就需要用括号()括起来:

    // 两个参数:
    (x, y) => x * x + y * y
    
    // 无参数:
    () => 3.14
    
    // 可变参数:
    (x, y, ...rest) => {
        var i, sum = x + y;
        for (i=0; i<rest.length; i++) {
            sum += rest[i];
        }
        return sum;
    }
    

    如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

    // SyntaxError:
    x => { foo: x }
    

    因为和函数体的{ ... }有语法冲突,所以要改为:

    // ok:
    x => ({ foo: x })
    

    this

    箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

    回顾前面的例子,由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:

    var obj = {
        birth: 1990,
        getAge: function () {
            var b = this.birth; // 1990
            var fn = function () {
                return new Date().getFullYear() - this.birth; // this指向window或undefined
            };
            return fn();
        }
    };
    

    现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj

    var obj = {
        birth: 1990,
        getAge: function () {
            var b = this.birth; // 1990
            var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
            return fn();
        }
    };
    obj.getAge(); // 25
    

    如果使用箭头函数,以前的那种hack写法:

    var that = this;
    

    就不再需要了。

    由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

    var obj = {
        birth: 1990,
        getAge: function (year) {
            var b = this.birth; // 1990
            var fn = (y) => y - this.birth; // this.birth仍是1990
            return fn.call({birth:2000}, year);
        }
    };
    obj.getAge(2015); // 25
    

    附录:

    var xiaoming = {
        name: '小明',
        age: 14,
        gender: true,
        height: 1.65,
        grade: null,
        'middle-school': '\"W3C\" Middle School',
        skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
        toJSON:  () => ({'Name': this.name,'Age': this.age});
    };
    

    这样是不行的,获取不到this.name和this.age,要这样写:

    var xiaoming = {
        name: '小明',
        age: 14,
        gender: true,
        height: 1.65,
        grade: null,
        'middle-school': '\"W3C\" Middle School',
        skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
        toJSON:  function(){
        var fn=()=>({'Name': this.name,'Age': this.age})
        return fn()
        }
    };
    

    ----------------------------------------------------分割线------------------------------------------------
    总结了下, 不一定对
    用"只想安安静静码"的方法在对象中使用箭头函数:

     var xiaoming_1 = {
            name: '小明',
            age: 14,
            gender: true,
            height: 1.65,
            grade: null,
            'middle-school': '\"W3C\" Middle School',
            skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
            toJSON:  function(){
                var fn=()=>({'Name': this.name,'Age': this.age})  // 将箭头函数放置于一个方法内
                return fn()
            }
        };
        xiaoming_1.toJSON()  // Object {Name: "小明", Age: 14}
    

    而用"创新ZCS"的方法, 直接将箭头函数作为对象方法,将得不到对象的this.name跟this.age, 而是得到windows的name和age:

      var xiaoming_2 = {
            name: '小明',
            age: 14,
            gender: true,
            height: 1.65,
            grade: null,
            'middle-school': '\"W3C\" Middle School',
            skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
            toJSON:  ()=>({'Name': this.name,'Age': this.age})
        };
        xiaoming_2.toJSON() // Object {Name: "list", Age: undefined}  正好我的windows有个名为name的属性值为"list"
    

    有趣的是如果将匿名函数直接作为对象的方法, 则this的指向却是正确的:

       var xiaoming_3 = {
            name: '小明',
            age: 14,
            gender: true,
            height: 1.65,
            grade: null,
            'middle-school': '\"W3C\" Middle School',
            skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
            toJSON:  function () { return {'Name':this.name,'Age': this.age}}
        };
        xiaoming_3.toJSON()   // Object {Name: "小明", Age: 14}
    

    原因我认为就是箭头函数的this会按照词法作用域绑定, 也就是指向外层调用者. (注意, 普通的定义在对象方法或内部方法中的内部函数的this就没有这个特点)

    如果在全局环境下调用一个对象的一个由箭头函数实现的方法, 则这个箭头函数的外层调用者是windows, 箭头函数的this指向windows对象. 如xiaoming_2
    如果调用箭头函数的是一个对象的方法, 则这个箭头函数的外层调用者是拥有该方法的对象, 箭头函数的this指向该对象. 如xiaoming_1

    可以粗暴理解成"箭头函数在哪儿被调用, 箭头函数的this就指向哪儿"

    而xiaoming_3中方法toJSON的实现就是个匿名函数, 也就是一个普通的内部函数, 它其中的this和一般内部函数中的this没有什么不同, 只要用obj.xxx形式访问这个方法, 匿名方法中的this指向的就是obj

    相关文章

      网友评论

          本文标题:箭头函数

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