this与箭头函数

简介: this与箭头函数

1. this的指向

在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了,也就是说,this的指向完全取决于函数调用的位置, 即this是在执行的时候被绑定的。


  • 函数调用: 当一个函数不是一个对象的属性时,直接作为函数来调用时,this指向全局对象,立即执行函数,默认的定时器等函数,this也是指向window。
  • 方法调用: 如果一个函数作为一个对象的方法来调用时,this指向这个对象。
  • 构造函数调用: this指向这个用new新创建的对象。
  • apply 、 call 和 bind 调用模式: 这三个方法都可以显示的指定调用函数的 this 指向。
  • 箭头函数的this: 指向声明时所在作用域下 this 的值,即箭头函数的this去他的上级作用域下寻找,任何方法都改变不了他的指向

隐式绑定

  // 严格模式:
  // 'use strict'
  // 1. 独立函数调用
  function foo() {
    console.log(this === window); //true
  }
  foo();
  // 2. 方法调用
  var obj = {
    name: "zgc",
    running: function () {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log(this);
    },
  };
  obj.running(); //obj对象
  var fn = obj.running;
  fn(); // window对象
  function bar() {
    console.log(this);
  }
  var baz = {
    name: "wf",
    bar: bar,
  };
  baz.bar(); // baz对象
  function test(fn) {
    fn();
  }
  test(baz.bar); // window对象
  // 3. 构造函数调用(new) 绑定
  function Student(name) {
    this.name = name;
    console.log("构造函数", this); // {name: 'zgc'}
  }
  const stu = new Student("zgc");
  // 4. 严格模式下, 独立函数调用this指向的是undefined

显式绑定(apply & call & bind)

  • apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
  • apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
  • apply是把参数放在一个数组里面作为它的第二个参数,而call、bind从第二个参数开始以参数列表的形式展现。
  • bind则是返回改变了this指向的一个函数,便于稍后调用;apply 、call 则是立即调用
  • bind方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数, 这个函数的 this指向除了使用new 时会被改变,其他情况下都不会改变
  var obj = {
    name: "zgc",
  };
  function foo(name, age) {
    console.log("foo", this, name, age);
  }
  // 让 foo的this指向obj
  // 1. call
  // 第一个参数, 绑定this
  // 第二个参数开始, 以参数列表的形式展现
  foo.call(obj, "zgc", 18); // foo {name: 'zgc'} zgc 18
  // 2. apply
  // 第一个参数, 绑定this
  // 第二个参数, 以数组的形式传入额外的实参
  foo.apply(obj, ["wf", 20]); // foo {name: 'zgc'} wf 20
  // 3. bind
  // 如果我们希望一个函数总是显示的绑定在一个对象上, 而不是每一次调用时再去绑定, 那么可以使用bind
  //  bind方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数, 便于稍后调用
  // 第一个参数, 绑定this
  // 第二个参数开始, 以参数列表的形式展现
  const baz = foo.bind(obj, "wlc", 22);
  baz(); // foo {name: 'zgc'} wlc 22]
  const bar = foo.bind(obj);
  bar("cx", 24); // foo {name: 'zgc'} cx 24

内置函数的this指向

 //  JavaScript的内置函数
  // 1. 定时器
  setTimeout(function () {
    console.log("定时器", this); // window
  }, 1000);
  // 2. 点击事件
  var btn = document.querySelector("button");
  // btn.onclick = function () {
  //   console.log("btn", this); // btn(<button>按钮</button>)
  // };
  btn.addEventListener("click", function () {
    console.log("btn", this); // btn(<button>按钮</button>)
  });
  // 3. forEach等方法
  //默认 window, 第二个参数可以绑定this
  var names = ["zgc", "wf"];
  var obj = { name: "zgc" };
  names.forEach(function () {
    console.log("forEach", this); // { name: "zgc" }
  }, obj);
  // 4. 补充: 立即执行函数this指向window
  (function () {
    console.log("立即执行函数", this);
  })();

2. this绑定的优先级

  function foo(age) {
    console.log(this);
    this.age = age;
  }
  var obj = {
    name: "zgc",
    foo: foo,
  };
  // 1. 隐式绑定(方法)的优先级高于默认绑定(独立函数调用)
  obj.foo(18); // obj: {name: 'zgc', age: 18, foo: ƒ}
  // 2. 显式绑定的优先级高于隐式绑定
  var bar = {
    name: "cx",
  };
  obj.foo.call(bar, 18); // bar: {name: 'cx', age: 18}
  // 3. new不可以和call/apply一起使用, 但绑定的优先级高于bind绑定
  var baz = obj.foo.bind(bar);
  var test = new baz(18);
  console.log(test); // test: {age: 18}
  // 4. bind的优先级高于 apply/call
  baz.call(obj); // bar: {name: 'cx', age: 18}
  // 5: 在显式绑定中, 如果我们的第一个参数为null和undefined, 那么这个显式绑定会被忽略, 使用默认规则
  obj.foo.call(null); // window

3. 箭头函数

ES6允许使用箭头(=>)定义函数,箭头函数多用于匿名函数的定义

  1. 如果形参只有一个,则小括号可以省略;
  2. 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果,return省略
  3. 箭头函数其实本身并没有绑定this,,即箭头函数的this去他的上级作用域下寻找,任何方法都改变不了他的指向
  4. 箭头函数是匿名函数,不能作为构造函数实例化;
  5. 不能使用 arguments,使用reset参数
  6. 当省略花括号与return, 并且返回值是一个对象时, 对象必须包一个小括号
  // 1. 箭头函数的定义
  // var foo = (参数1, 参数2) => { 代码块 };
  // 2. 当省略花括号与return, 并且返回值是一个对象时, 对象必须包一个小括号
  var num = () => 1;
  var obj = () => ({ name: "zgc" });
  console.log(num(), obj()); // 1 {name: 'zgc'}
  // 3. this的使用
  // 箭头函数其实本身并没有绑定this,,即箭头函数的this去他的上级作用域下寻找
  // 所以任何方法都无法改变该this的指向
  var foo = () => {
    console.log(this);
  };
  foo(); // window
  var obj = {
    name: "zgc",
    running: () => {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log("箭头函数", this); // window
    },
  };
  obj.running();
  var obj = {
    name: "wf",
    running: function () {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log("普通函数", this); // obj
      var bar = () => {
        console.log("bar", this); // obj
      };
      return bar;
    },
  };
  const fn1 = obj.running();
  fn1();
  var name = "xxxx";
  var obj = {
    name: "wf",
    running: function () {
      // 这里的上级作用域是window, 对象是数据类型, 不是代码块, 没有作用域
      console.log("普通函数", this); // window
      var bar = () => {
        console.log("bar", this, name); // window xxxx
      };
      return bar;
    },
  };
  const fn2 = obj.running;
  fn2();
  fn2()();
相关文章
|
Prometheus 监控 Kubernetes
Prometheus + Grafana安装
Prometheus + Grafana安装
|
存储 编解码 算法
音视频入门基础理论知识
音视频入门基础理论知识
549 0
|
7月前
|
Web App开发 Linux 数据库
Omnissa Horizon 8 2503 (ESB Release) - 虚拟桌面基础架构 (VDI) 和应用软件
Omnissa Horizon 8 2503 (ESB Release) - 虚拟桌面基础架构 (VDI) 和应用软件
506 8
Omnissa Horizon 8 2503 (ESB Release) - 虚拟桌面基础架构 (VDI) 和应用软件
|
缓存 Java 应用服务中间件
一文带你使用xxl-job定时任务
将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求。 将任务抽象成分散的JobHandler,交由“执行器”统一管理,“执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑。 因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性;
4778 0
一文带你使用xxl-job定时任务
|
运维 Kubernetes Cloud Native
云原生技术入门及实践
【10月更文挑战第39天】在数字化浪潮的推动下,云原生技术应运而生,它不仅仅是一种技术趋势,更是企业数字化转型的关键。本文将带你走进云原生的世界,从基础概念到实际操作,一步步揭示云原生的魅力和价值。通过实例分析,我们将深入探讨如何利用云原生技术提升业务灵活性、降低成本并加速创新。无论你是云原生技术的初学者还是希望深化理解的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
搜索推荐 数据可视化 Linux
【超乎想象】Archman Linux:一款基于Arch Linux的极致轻量、极速稳定、超凡体验的Linux发行版!
【8月更文挑战第22天】Archman Linux是一款基于Arch Linux的轻量级、快速且稳定的发行版,继承了Arch的技术优势并提供友好的桌面环境。安装步骤包括下载ISO镜像、创建启动盘、从USB启动进入Live环境、运行安装程序、分区、配置网络及安装基本系统、设置密码、安装引导程序并重启。配置涉及系统更新、安装桌面环境与常用软件、个性化设置、安装驱动、设置自动更新和备份计划。通过提供的Shell脚本可自动化完成部分配置工作。无论新手还是老手,Archman Linux都能提供出色的体验。
617 2
|
SQL DataWorks 关系型数据库
DataWorks操作报错合集之执行读取任务时遇到报错:“ERROR: failed to acquire resources on one or more segments”,该怎么解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
存储 中间件 API
ThinkPHP 集成 jwt 技术 token 验证
本文介绍了在ThinkPHP框架中集成JWT技术进行token验证的流程,包括安装JWT扩展、创建Token服务类、编写中间件进行Token校验、配置路由中间件以及测试Token验证的步骤和代码示例。
ThinkPHP 集成 jwt 技术 token 验证
|
存储 网络架构
Next.js 实战 (四):i18n 国际化的最优方案实践
这篇文章介绍了Next.js国际化方案,作者对比了网上常见的方案并提出了自己的需求:不破坏应用程序的目录结构和路由。文章推荐使用next-intl库来实现国际化,并提供了详细的安装步骤和代码示例。作者实现了国际化切换时不改变路由,并把当前语言的key存储到浏览器cookie中,使得刷新浏览器后语言不会失效。最后,文章总结了这种国际化方案的优势,并提供Github仓库链接供读者参考。
682 0
Next.js 实战 (四):i18n 国际化的最优方案实践
|
网络协议 网络架构
【网络工程师配置篇】VRRP与BFD联动配置案例
【网络工程师配置篇】VRRP与BFD联动配置案例
440 1