当前位置: 首页 > news >正文

this作用全解(全局this 、函数this、全局函数 this call apply bind……)

文章目录

  • this 是什么
  • 全局上下文的 this
  • 函数上下文的 this
    • 全局上下文中的函数
    • 对象中的函数
    • 箭头函数
    • 构造函数
  • 显式改变函数上下文的 this
    • call
    • apply
    • bind


this 是什么

老是记不住 this 指向谁,我觉得这是非常正常的现象,因为 this 指向的情况本身就比较多,面对这种不太好记的知识点,我们可以延续之前的学习方式,采用敲代码实验 + 画图记忆 + 真题训练的方式,这种学习方式学知识更高效一点。

首先,学习一个知识,先要理解它是什么,在大多数面向对象语言中,this 表示当前对象的一个引用,而 JS 中的 this 是完全不同的概念。
我们查阅 MDN 文档可知,this 是当前执行上下文(global、function 或 eval)的一个属性。
也就是说,我们可以把 JS 中的 this 分为三种,分别是:

  • 全局上下文中的 this。
  • 函数上下文中的 this。
  • eval 上下文中的 this。

关于 eval ,在 MDN 或很多书籍和文档中都建议永远不要使用它,我们就不讨论它了,接下来,我们将主要讨论全局上下文和函数上下文的 this。
有一点需要注意的是,node 环境中的 this 和 web 环境中的 this 是不同的,为了避免大家一开始接受太多概念,我们先只讨论 web 环境的 this。
接下来,我们就通过做实验的方式,来学习一下 this 的指向。

全局上下文的 this

全局上下文的 this 指向非常明确,不管有没有启用严格模式,都指向 window 对象。可以打开右侧的实验环境,我们敲代码来验证一下。随便新建一个 test.html 文件,在文件中写入如下代码:

<body>
  <script>
    console.log(this === window); // 输出 true
    ("use strict");
    console.log(this === window); // 输出 true
  </script>
</body>

然后可以启动一下环境中的 web server,查看代码输出情况,可以看到,的确是不管有没有启用严格模式,全局上下文的 this 都指向 window 对象。

给 this 添加属性,就相当于给 window 添加属性,给window 添加属性,就相当于给 this 添加属性,如下代码所示:

this.userName = "zhangsan";
window.age = 18;

console.log(this.age); // 输出 18
console.log(window.userName); // 输出 'zhangsan'

函数上下文的 this

全局上下文的 this 很简单,记住无脑指向 window 就完事,复杂就复杂在函数上下文的 this,函数上下文中的 this 与 arguments 一样,就是函数的隐式参数,可以在任意函数中调用,它的指向不是固定不变的,取决于函数处于什么位置、以什么方式调用,可以总结成如下图:

在这里插入图片描述

全局上下文中的函数

直接调用全局上下文中的函数,this 指向默认情况下为 window。

function fn() {
  console.log(this); // 输出 window
}
fn();
function fn() {
  let a = 1;
  console.log(this.a); // 输出 2
}
var a = 2;
fn();

但是在严格模式下,this 指向的就是 undefined。

function fn() {
  "use strict";
  console.log(this); // 输出 undefined
}
fn();

对象中的函数

调用对象中的函数,this 指向为这个对象。

const obj = {
  a: 1,
  fn() {
    console.log("this :>> ", this); // 输出 obj
    console.log("this.a :>> ", this.a); // 输出 1
  },
};

obj.fn();

但是如果函数嵌套有函数,此时的 this 指向为 window,就非常令人迷惑。

const obj = {
  a: 1,
  fn() {
    return function () {
      console.log("this :>> ", this); // 输出 window
      console.log("this.a :>> ", this.a); // 输出 100
    };
  },
};

var a = 100;

obj.fn()();

其实可以这么理解:

obj.fn()();

等价于;

const temp = obj.fn(); // 定义一个临时变量来存储 obj.fn 返回的函数
temp(); // 执行这个函数

箭头函数

遇到对象里有函数嵌套函数的情况,想要 this 指向这个对象,es6 之前,可以用一个临时变量 _this 来暂存 this,代码如下:

const obj = {
  a: 1,
  fn() {
    const _this = this;
    return function () {
      console.log("this :>> ", _this); // 输出 obj
      console.log("this.a :>> ", _this.a); // 输出 1
    };
  },
};

obj.fn()();

es6 推出了箭头函数的概念,之后我们就可以使用箭头函数解决这个问题,代码如下:

const obj = {
  a: 1,
  fn() {
    return () => {
      console.log("this :>> ", this); // 输出 obj
      console.log("this.a :>> ", this.a); // 输出 1
    };
  },
};

obj.fn()();

对于普通函数来说,内部的 this 指向函数运行时所在的对象。

对于箭头函数,它不会创建自己的 this,它只会从自己的作用域链的上一层继承 this。

所以这里 fn 中嵌套的匿名箭头函数中的 this,指向它作用域链的上一层的 this,也就是函数 fn 的 this,也就是 obj。

其实,箭头函数内部实现也是定义临时变量 _this 来暂存 this,用 babel 一试便知,如下图:

在这里插入图片描述

构造函数

构造函数内,如果返回值是一个对象,this 指向这个对象,否则 this 指向新建的实例。

function Person(name) {
  this.name = name;
}
const p = new Person("zhangsan");
console.log(p.name); // 'zhangsan'
function Person(name) {
  this.name = name;
  return {
    name: "xxx",
  };
}
const p = new Person("zhangsan");
console.log(p.name); // 'xxx'
function Person(name) {
  this.name = name;
  return {};
}
const p = new Person("zhangsan");
console.log(p.name); // 'undefined'

如果有返回值,但是不是一个对象,this 还是指向实例。

function Person(name) {
  this.name = name;
  return 123;
}
const p = new Person("zhangsan");
console.log(p.name); // 'zhangsan'

显式改变函数上下文的 this

call

Function.prototype.call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

function fn() {
  console.log(this.name);
}

const obj = {
  name: "zhangsan",
};
fn.call(obj); // 指定 this 为 obj,输出 'zhangsan'

apply

Function.prototype.apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

apply 和 call 的功能完全一样,只是传参形式不一样,call 是传多个参数,apply 是只传参数集合。

function add(x, y, z) {
  return this.x + this.y + this.z;
}

const obj = {
  x: 1,
  y: 2,
  z: 3,
};

console.log(add.call(obj, 1, 2, 3)); // 输出 6
console.log(add.apply(obj, [1, 2, 3])); // 输出 6,只是传参形式不同而已

bind

Function.prototype.bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

bind 和 call、apply 的区别是,函数调用 call 和 apply 会直接调用,而调用 bind 是创建一个新的函数,必须手动去再调用一次,才会生效。

function add(x, y, z) {
  return this.x + this.y + this.z;
}

const obj = {
  x: 1,
  y: 2,
  z: 3,
};

const add1 = add.bind(obj, 1, 2, 3); // bind 会返回一个新的函数
console.log(add1()); // 执行新的函数,输出 6

相关文章:

  • k8s核心资源ingress
  • 【MySQL】《狂飙》电视剧火了,如果程序一直狂飙,扛不住了,怎么办呢?
  • golang 协程关闭——谁敢说没踩过坑
  • 熵值法原理及python实现 附指标编制案例
  • Small RTOS51 学习笔记(10)Small RTOS51 的移植
  • CentOS7 LVM 逻辑卷2种读写策略(磁盘IO性能优化)—— 筑梦之路
  • 湫湫系列故事——减肥记Ⅰ(Python)
  • 分享158个ASP源码,总有一款适合您
  • 机器学习常见面试问题汇总
  • 低代码:让企业“活”起来,赋能企业数字转型
  • SAP IFRS 17 面向服务架构详细解析(包含分类账规则)
  • JavaWeb:过滤器与监听器
  • SpringBoot Log4j2日志
  • 导致商标注册失败的四大原因?
  • Arx遍历块内实体
  • 剑指 Offer II 009. 乘积小于 K 的子数组
  • GF_CLR初始用 - 正式版
  • visual studio2019 定位内存泄漏的方法
  • 懂了委托,才算真正入门C#
  • Python | 数据类型之集合 | 函数
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉