js中的箭头函数

 箭头函数是ES6标准中新增的一种函数,在详细的讨论箭头函数之前,我们先来看看函数的四种定义方式

  函数的四种定义方式

  1、函数声明的方式(常用)

function sum (num1,num2) {
      return num1 + num2;
 }

  注意函数定义最后没有加分号。必须有名字,会函数提升,在预解析阶段就已经创建,声明前后都可以调用。

  2、函数表达式的方式

let sum = function(num1,num2) {
      return num1 + num2;
};

  一种变量赋值,函表达式可以没有名字(匿名函数),没有函数提升。函数表达式创建方式和函数声明几乎是等价的,这里代码定义了一个变量sum并将其初始化为一个函数,这个函数可以通过sum来引用。注意这里函数末尾是有分号的,与任何变量初始化语句一样。

  3、箭头函数的方式

   //多个参数需要括号
    let sum = (num1,num2) => {
        return num1 + num2;
    };
    //以下两种写法都有效,只有一个参数可以不写括号
    let double = (x) => { return 2 * x };
    let double = x => { return 2 * x };
    //没有参数需要括号
    let getRandom = () => { return Math.random() };

     注意:箭头函数在参数和箭头之间不能换行,但是,可以通过在 ‘=>’ 之后换行,或者用 ‘( )’、'{ }'来实现换行

  任何可以使用函数表达式的地方,都可以使用箭头函数。箭头函数语法简单,非常适合嵌入函数的场景。

   let ints = [1,2,3];
   console.log(ints.map(function (i){
        return i + 1
   }));//[2,3,4]
   console.log(ints.map(i => {return i + 1 }));//[2,3,4]
    //map()方法定义在JavaScript的Array中,它返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。

  4、构造函数的方式(不推荐)

let sum = new Function("num1","num2","return num1 + num2");

  不推荐使用这种语法定义,因为这段代码会被解释两次:第一次是把它作为常规ES代码,第二次是解释传给构造函数的字符串。这显然会影响性能。不过,把函数想象为对象,把函数名想象为指针这很重要。而上面的语法很好地诠释了这个概念。

 

  箭头函数中的this

  箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,即箭头函数内部的this是词法作用域,由上下文确定

  在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this值:

  • 如果该函数是一个构造函数,this指针指向一个新的对象
  • 在严格模式下的函数调用下,this指向undefined
  • 如果该函数是一个对象的方法,则它的this指针指向这个对象
  • 等等

  由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数

var adder = {
  base : 1,

  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v => v + this.base;
    var b = {
      base : 2
    };

    return f.call(b, a);
  }
};

console.log(adder.add(1));         // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2

 

  接下来我们来看一个箭头函数应用的例子:我们想每隔一秒输出this.age的值加1

  function Person() {
        // Person() 构造函数定义 `this`作为它自己的实例.
        this.age = 0;

        setInterval(function add() {
            // 在非严格模式, add()函数定义 `this`作为全局对象,
            // 与在 Person()构造函数中定义的 `this`并不相同.
            this.age++;
            console.log(this.age);
        }, 1000);
    }
    var p = new Person();

 

  但是你会发现,每隔一秒都会有一个NaN打印出来,而不是累加的数字。到底哪里错了呢? 实际上setInterval里面的this绑定到全局对象window,而window.age未定义,那么怎么解决这一问题呢?

  在ECMAScript 3/5中,通过将this值分配给封闭的变量,可以解决this问题。

  function Person() {
        var that = this;
        that.age = 0;

        setInterval(function add() {
            that.age++;// 回调引用的是`that`变量, 其值是预期的对象.
            console.log(that.age);
        }, 1000);
    }
    var p = new Person();

 

  使用箭头函数解决,箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

  function Person() {
        this.age = 0;

        setInterval(() => {
            this.age++;
            console.log(this.age);
        }, 1000);
    }
    var p = new Person();

 

  箭头函数不绑定arguments

  箭头函数不绑定arguments对象。

    function foo() {
        console.log(arguments[0]);
    }
    foo(5);//5

    let bar = () => {
        console.log(arguments[0]);
    }
    bar(5)//arguments is not defined

 

  虽然箭头函数没有arguments对象。但可以在包装函数中把它提供给箭头函数:

    function foo() {
        let bar = () => {
            console.log(arguments[0]);//5
        }
        bar()
    }
    foo(5);

 

  箭头函数不能用作构造函数

  和new一起使用会抛出异常

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

 

  箭头函数没有prototype属性

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

 

  返回对象字面量

  记住用params => {object:literal}这种简单的语法返回对象字面量是行不通的。

var func = () => { foo: 1 };
// Calling func() returns undefined!
var func = () => ({foo: 1});
//所以,记得用圆括号把对象字面量包起来:

var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name

 

  箭头函数也不能使用super和new.target

 

posted @ 2021-10-16 11:44  打遍天下吴敌手  阅读(3817)  评论(0编辑  收藏  举报