前端JS箭头函数和普通函数的区别全解 面试必问

基本语法:

普通函数 function
function fc(a1,b2,...,pnan){

sumnews;

}

即格式为:

funtion 函数名(参数列表) {

        语句;

        return 表达式

}

2.箭头函数 

// 当只有一个参数时,圆括号是可选的
(singleParam) => { statements }
singleParam => { statements }
 
// 没有参数的函数应该写成一对圆括号
() => { statements }
 
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
//相当于:(param1, param2, …, paramN) =>{ return expression; }

上述基本语法可以概括为: 

  1. 如果只有一个形参,则可以省略圆括号();
  2. 如果没有形参,则必须写成一对圆括号();
  3. 如果函数体只有一行,则可以省略花括号{},且同时,省略return,函数的返回值为该条语句的执行结果;

看列子:

箭头函数

 let f =v=>console.log('',v);
 f(20) 
//v:20

普通函数:

 let fn =function(v){
     console.log('v:',v);
  }
   fn(30) 
// v:30

箭头函数的概念:

箭头函数内部的this是词法作用域(块级作用域),由上下文确定。(词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变 。)

箭头函数的this指向:

概念

对于普通函数来说,内部的this指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的 

let fn = () => {
      console.log('this',this);}
  fn()
//结果 window

 列子如下Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了 3 次,而timer.s2一次都没更新。

箭头函数实际上可以让this指向固定化,绑定this使得它不再可变,这种特性很有利于封装回调函数。

 

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0

 

 列子:DOM 事件的回调函数封装在一个对象里面。

var handler = {
  id: '123456',

  init: function() {
    document.addEventListener('click',
      event => this.doSomething(event.type), false);
  },

  doSomething: function(type) {
    console.log('Handling ' + type  + ' for ' + this.id);
  }
};

上面代码的init()方法中,使用了箭头函数,这导致这个箭头函数里面的this,总是指向handler对象。如果回调函数是普通函数,那么运行this.doSomething()这一行会报错,因为此时this指向document对象。

总之,箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

 

以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:argumentssupernew.target

function foo() {
  setTimeout(() => {
    console.log('args:', arguments);
  }, 100);
}

foo(2, 4, 6, 8)
// args: [2, 4, 6, 8]

上面代码中,箭头函数内部的变量arguments,其实是函数fooarguments变量。

另外,由于箭头函数没有自己的this,所以当然也就不能用call()apply()bind()这些方法去改变this的指向。

 箭头函数没有 prototype 属性:

var Fn = () => {};
console.log(Fn.prototype);

箭头函数不绑定arguments

function fn(){
        console.log(arguments ,'普通函数');
      }fn(1,2,3,4,5 )
      let fn2=(...num)=>console.log(...num,'箭头函数');
      fn2(1,2,3,4,5)

 ​​​​​​

let obj1 = {

a: 10,


// 匿名函数 function

b: function () {

console.log("obj1.b的this:",this);

console.log("obj1.b的this.a:",this.a);

},


// 箭头函数

c: () => {

// this继承父层的this

console.log("obj1.c的this:",this);

console.log("obj1.c的this.a:",this.a);

},

};

obj1.b()

obj1.c()

在对象的方法中分别使用匿名函数function和箭头函数,对象调用该方法时,匿名函数的this指向被其调用的对象obj1,箭头函数的this指向父层的this,由于该代码是写在 Vue 项目中,因此this指向组件实例,在组件实例中,并没有变量a,因此this.a是undefined。

箭头函数不能用作Generator函数

箭头函数内部不可以使用yield命令,因此箭头函数不能用作Generator函数。

let fn = function *() {

yield '萱不是渲';

}

let p = fn();

console.log(p.next());
let fn = *() => {

yield '渲不是萱';

}

let p = fn();

console.log(p.next());

 

不适用场合

由于箭头函数使得this从“动态”变成“静态”,下面两个场合不应该使用箭头函数。

第一个场合是定义对象的方法,且该方法内部包括this

const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。

再看一个例子。

globalThis.s = 21;

const obj = {
  s: 42,
  m: () => console.log(this.s)
};

obj.m() // 21

上面例子中,obj.m()使用箭头函数定义。JavaScript 引擎的处理方法是,先在全局空间生成这个箭头函数,然后赋值给obj.m,这导致箭头函数内部的this指向全局对象,所以obj.m()输出的是全局空间的21,而不是对象内部的42。上面的代码实际上等同于下面的代码。

globalThis.s = 21;
globalThis.m = () => console.log(this.s);

const obj = {
  s: 42,
  m: globalThis.m
};

obj.m() // 21

由于上面这个原因,对象的属性建议使用传统的写法定义,不要用箭头函数定义。

第二个场合是需要动态this的时候,也不应使用箭头函数。

var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。

另外,如果函数体很复杂,有许多行,或者函数内部有大量的读写操作,不单纯是为了计算值,这时也不应该使用箭头函数,而是要使用普通函数,这样可以提高代码可读性。

箭头函数的注意点

 

(1)箭头函数没有 this ,普通函数的 this 指向依赖它是如何被调用的

(2)不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值