首页 > 其他分享 >前端JS箭头函数和普通函数的区别全解 面试必问

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

时间:2024-07-17 17:00:51浏览次数:17  
标签:function 必问 console log 作用域 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 函数。

标签:function,必问,console,log,作用域,JS,箭头,函数
From: https://blog.csdn.net/2301_78320134/article/details/140498652

相关文章

  • 适用任意复杂转移函数及方程式的 matlab 二维曲线作图与客制化界面
    優點曲線可自行定義粗細,顏色,精細度......等等字可自行定義字體,顏色,大小,方向,位置......等等可自行定義虛線與字來標註曲線上的某一點此方法可延伸至matlab三維曲線或曲面作圖,亦或是同樣概念,但是改用其他程式諸如python來實現前情提要matlab現有表達轉移函數,......
  • FastJson详解
    文章目录一、FastJson介绍二、FastJson序列化API1、序列化Java对象2、序列化List集合3、序列化Map集合三、FashJson反序列化API1、反序列化Java对象2、反序列化List集合3、反序列化Map集合(带泛型)四、SerializerFeature枚举1、默认字段为null的不显示2、格式化五、@JSo......
  • JS 实现在指定的时间点播放列表中的视频
     为了实现在指定的时间点播放列表中的视频,你可以使用JavaScript中的setTimeout或setInterval结合HTML5的<video>元素。但是,由于你需要处理多个时间点,并且每个时间点播放不同的视频,使用setTimeout会更直接一些,因为你可以为每个时间点设置一个独立的定时器。以下是一个基本的实......
  • 避免函数形参为空指针
    展示一个函数形参为空指针的隐患:执行第32行代码时,相当于执行double*pdPoint=pdTemp;,由于pdTemp=NULL,所以pdPoint=NULL。在然后 voidPointer(double*pdPoint,intiDim)函数中对pdPoint赋了一块动态内存,此时 pdPoint!=NULL,但是 pdPoint和pdTemp只是赋值......
  • js 将table转成Excel
    1.情景展示如何使用js将网页中的表格转成Excel文件?2.具体分析通过SheetJS的xlsx.js文件实现。3.解决方案下载地址:https://github.com/SheetJS/sheetjs/archive/refs/tags/v0.18.5.zip打开压缩包,找到dis目录下的xlsx.full.min.js将该文件解压出来,放到项目当中。在需要......
  • 购买一台云服务器,安装nvm,能够将配置全局命令链接js文件执行
    全局安装@vue/cli为什么会添加命令vuelinux或者MAC系统中通过whichvue查看vue地址,通过进入该地址查看文件发现软链接指向真实文件,真实文件同级别下的package.json中的bin字段中的名决定了输入命令vue2.全区安装@vue/cli时将包放在了node安装位置的node_modules下并且在包中的p......
  • 破解反爬虫策略 /_guard/auto.js(一) 原理
    背景当用代码或者postman访问一个网站的时候,访问他的任何地址都会返回<scriptsrc="/_guard/auto.js"></script>,但是从浏览器中访问显示的页面是正常的,这种就是网站做了反爬虫策略。本文就是带大家来破解这种策略,也就是反反爬虫。思路寻找关键参数既然在浏览器中访问没问题......
  • 多种模块格式,包括 ES, CommonJS, UMD, AMD, SystemJS 和 IIFE的区别点分别是什么
    【转】https://zhuanlan.zhihu.com/p/668530823以下是各种模块格式的主要特点:ESModules(ESM):这是ECMAScript6(ES6)引入的官方标准格式。它支持导入和导出语句,以及静态分析和tree-shaking。它是唯一的静态模块系统,意味着你可以在编译时确定导入和导出的内容。CommonJS(C......
  • 手把手教你基于华为云鲲鹏弹性云服务器部署Node.js环境
    本文分享自华为云社区《华为云之使用鲲鹏弹性云服务器部署Node.js环境【玩转华为云】》,作者:江湖有缘。一、本次实践介绍1.1实践环境简介本次实践环境使用华为KooLabs云实验平台。本次实践基于基于华为云鲲鹏弹性云服务器。在HCE系统上安装、部署、测试Node.js项目。1.3本......
  • 华为OD机试D卷 --找座位--24年OD统一考试(Java & JS & Python & C & C++)
    文章目录题目描述输入描述输出描述用例题目解析java源码python源码javascript源码c源码c++源码题目描述在一个大型体育场内举办了一场大型活动,由于疫情防控的需要,要求每位观众的必须间隔至少一个空位才允许落座。现在给出一排观众座位分布图,座位中存......