0


前端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

,所以也就不能用作构造函数。

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

arguments

super

new.target

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

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

上面代码中,箭头函数内部的变量

arguments

,其实是函数

foo

arguments

变量。

另外,由于箭头函数没有自己的

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 函数。


本文转载自: https://blog.csdn.net/2301_78320134/article/details/140498652
版权归原作者 萱不是渲 所有, 如有侵权,请联系我们删除。

“前端JS箭头函数和普通函数的区别全解 面试必问”的评论:

还没有评论