箭头函数

javascript 复制代码
// 普通函数
function (){}

// 箭头函数
()=>{}

ES6 中允许使用 => 来定义函数,省去关键字 function

箭头函数与普通函数功能基本类似,但是写法简单、清晰

箭头函数相当于匿名函数,并简化了函数的定义

箭头函数一般当作函数表达式或回调函数去使用

一、特点

1、只有一个形参的时候,() 可以省略
javascript 复制代码
// 只有一个形参
var test = (a)=>{
  console.log(111,a)
}

// 省略 () 写法
var test2 = a =>{
  console.log(111,a)
}
2、只有一条执行语句,且只返回某个变量或者js表达式,可以省略 {} 和 return
less 复制代码
// 只有一个返回值
var test = (a)=>{
  return 100*a
}

// 省略 {} 后的代码
var test2 = a=>100*a
3、如果只返回一个对象,可以把对象看作一个整体,用小括号括起来,当作一条语句,就可以省略大括号 和 return
javascript 复制代码
const fn = ()=>{
  return {
    a:1,
    b:2
  }
}

const fn2 = ()=>({a:1,b:2})
4、没有 arguments
javascript 复制代码
//通过形参获取参数
var test = function(a,b,c){
    console.log(a,b,c) 
}
test(1,2,3)

//通过函数内部的 arguments 属性获取函数传参
var test2 = function(){
    console.log(arguments[0],arguments[1],arguments[2]) 
}
test2(1,2,3)

// 箭头函数访问 arguments
var test3 = ()=>{
  console.log(arguments)
}
test3(1,2,3)
5、this 指向

箭头函数 this 指向父级作用域

箭头函数的 this 继承自它所在词法作用域的 this

函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="text" id="myInput">
  <script>
    const inputEl = document.getElementById('myInput')

    inputEl.oninput = function(){
      //1、 普通函数
      // setTimeout(function(){
      //   // 此时的 this 指向 window
      //   console.log(this) 
      // }, 1000);

      //2、 临时存储 this
      // const _this =this
      // setTimeout(function(){
      //   // 此时的 _this 指向 input 元素
      //   console.log(_this) 
      // }, 1000);

      // 3、箭头函数
      setTimeout(()=>{
        // 此时的 this 指向 input 元素
        console.log(this) 
      }, 1000);
    }
  </script>
</body>
</html>
javascript 复制代码
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);
javascript 复制代码
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}
var id = 21;
foo.call({ id: 42 });
javascript 复制代码
function debounce(func,duration=500){
  let timer;
  return function(...args){
    clearTimeout(timer)
    timer = setTimeout(()=>{
      func.apply(this,args)
    },duration)
  }
}

function debounce2(func, duration = 500) {
  let timer;
  return function () {
    const context = this; // 保存 this 指向
    const args = arguments; // 获取参数

    clearTimeout(timer);
    timer = setTimeout(function () {
      func.apply(context, args); // 使用 apply 保证 this 指向
    }, duration);
  };
}
scss 复制代码
//请问下面的代码之中有几个this?
function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()();
var t2 = f().call({id: 3})(); 
var t3 = f()().call({id: 4});
kotlin 复制代码
var name="张三"
function fun(){
  this.name="李四"
  return ()=>{
    console.log(this.name)
  }
}
const obj = {
  name:"王麻子",
  fun2:fun()
}
const obj2 = {
  name:"王麻子",
  fun2:()=>console.log(this.name)
}

obj.fun2()
obj2.fun2()
typescript 复制代码
<script lang="tsx">
  import { SetupContext } from "vue"

  interface TabItemProps {
    label: string
    value: string | number
  }
  interface IProps {
    modelValue: string | number
    tabs: TabItemProps[]
  }

  export default defineComponent({
    props: {
      modelValue: {
        type: [String, Number] as PropType<string | number>,
        default: "",
      },
      tabs: {
        type: Array as PropType<TabItemProps[]>,
          required: true,
      },
    },
    emits: ["update:modelValue", "change"],
    setup(_props: IProps, ctx: SetupContext) {
      const tabAct = computed({
        get() {
          return _props.modelValue !== undefined ? _props.modelValue : _props.tabs.length ? _props.tabs[0]?.value : ""
        },
        set(value) {
          ctx.emit("update:modelValue")
        },
      })

      const handleTabClick = (item: TabItemProps) => {
        tabAct.value = item.value
      }

      return () => {
        return (
          <div class="w-full flex">
          <div class="tabs-box">
          {_props.tabs.map((item: TabItemProps) => {
            return (
              <div
              class={`tab-item ${item.value === tabAct.value ? "tab-active" : ""}`}
                           onClick={() => handleTabClick(item)}
        >
        {item.label}
    </div>
                                )
  })}
    </div>
    </div>
  )
    }
    },
    })
    </script>
5、不可以使用new命令
ini 复制代码
var test = ()=>{}
var newTest = new test()

二、箭头函数与普通函数的区别

语法格式 new 和 原型 arguments super new.target this 指向 call、apply、bind
箭头函数 ()=>{} 函数表达式 没有 没有 一般是全局对象,被普通函数包含指向上一层 不可改变 this 的指向
普通函数 function(){} 函数声明 函数表达式 动态 可修改 this 的指向

三、箭头函数为什么不能作为构造函数?

1、箭头函数没有自己的 this ,this 的值是在定义的时候确定的,而不是在运行的时候,它继承自父级作用域。而构造函数需要动态绑定 this,指向新创建的实例对象。

2、不能通过 new 调用,当通过 new 调用一个箭头函数时, javascript 引擎会直接报错。因为箭头函数没有构造函数的特性

  • 构造函数必须有 prototype ,用于定义创建的实例对象的原型。

3、super 关键字不可用,而子类的构造函数通常需要使用 super() 调用父类的构造函数。

四、arguments、super、new.target

arguments
  • 作用: arguments 是一个类数组对象,它包含了传递给函数的所有参数。
  • 可用性: arguments 对象只在函数内部可用。
  • 特点:
    • 虽然 arguments 看起来像数组,但它不是真正的数组,它没有数组方法,例如 push、pop、slice 等。
    • 你可以使用索引访问 arguments 中的参数,例如 arguments[0] 表示第一个参数。
    • arguments 对象拥有一个 length 属性,表示传递给函数的参数个数。
javascript 复制代码
function myFunction() {
  console.log(arguments.length);   // 输出参数个数
  console.log(arguments[0]);      // 输出第一个参数
}

myFunction(1, 2, 3);
super
  • 作用: super 关键字用于访问父类的构造函数和方法。
  • 可用性: super 关键字只在类的构造函数和方法内部可用。
  • 使用场景:
    • 在子类的构造函数中,你必须使用 super() 调用父类的构造函数,以初始化继承的属性。
    • 在子类方法中,你可以使用 super.methodName() 调用父类的方法。
javascript 复制代码
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a sound.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);           // 调用父类构造函数
    this.breed = breed;
  }

  speak() {
    super.speak();         // 调用父类方法
    console.log(`${this.name} barks.`);
  }
}

const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak();
new.target
  • 作用: new.target 属性用于确定一个函数或构造函数是否使用 new 关键字调用。
  • 返回值:
    • 如果函数使用 new 调用,则 new.target 返回构造函数本身。
    • 如果函数未使用 new 调用,则 new.target 返回 undefined。
sql 复制代码
function myFunction() {
  if (new.target) {
    console.log('Called with new');
  } else {
    console.log('Called without new');
  }
}

new myFunction();     // 输出: Called with new
myFunction();          // 输出: Called without new
scss 复制代码
function myConstructor() {
  if (!new.target) {
    throw new Error('Must be called with new');
  }
  // ... 构造函数逻辑
}

new myConstructor();   // 正确调用
myConstructor();        // 抛出错误

五、使用注意点

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

六、不适用场景

  • 定义对象的方法,且该方法内部包括this
javascript 复制代码
const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}
// 上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。
// 调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;
// 如果写成上面那样的箭头函数,使得this指向全局对象
// 因此不会得到预期结果。这是因为对象不构成单独的作用域
// 导致jumps箭头函数定义时的作用域就是全局作用域。
  • 需要动态this的时候,也不应使用箭头函数。
javascript 复制代码
var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});
// 上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,
// 导致里面的this就是全局对象。
// 如果改成普通函数,this就会动态指向被点击的按钮对象。

七、使用场景

  • ES6数组方法(map、forEach、filter...)
  • 不需要动态绑定 this 时
  • 高阶函数
  • 链式调用
  • vue 组件 tsx 语法 事件绑定
相关推荐
江城开朗的豌豆8 分钟前
JavaScript篇:typeof 的魔法:原来你是这样判断类型的!
前端·javascript·面试
江城开朗的豌豆11 分钟前
JavaScript篇:数组扁平化:从‘千层饼’到‘一马平川’的六种神操作 🥞→📜
前端·javascript·面试
当归10241 小时前
Fuse.js:打造极致模糊搜索体验
开发语言·javascript·ecmascript
難釋懷2 小时前
Vue-Todo-list 案例
前端·vue.js·list
前端达人2 小时前
React 播客专栏 Vol.18|React 第二阶段复习 · 样式与 Hooks 全面整合
前端·javascript·react.js·前端框架·ecmascript
GISer_Jing2 小时前
Monorepo 详解:现代前端工程的架构革命
前端·javascript·架构
比特森林探险记3 小时前
Go Gin框架深度解析:高性能Web开发实践
前端·golang·gin
前端百草阁6 小时前
JavaScript 模块系统:CJS/AMD/UMD/ESM
javascript·ecmascript
打小就很皮...6 小时前
简单实现Ajax基础应用
前端·javascript·ajax
wanhengidc7 小时前
服务器租用:高防CDN和加速CDN的区别
运维·服务器·前端