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

news2024/12/23 1:19:37

文章目录

  • 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193749.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux secure boot(安全启动)下为内核模块签名

文章目录linux secure boot(安全启动)下为内核模块签名背景Secure Boot安全启动开启关闭方法内核驱动签名生成签名证书和私钥导入签名证书BIOS(UEFI)导入证书(重要)制作带签名的驱动参考linux secure boot(安全启动)下为内核模块签名 背景 随着计算机性能和存储空间的提升&am…

Mybatis对象关联数据库表【对多关联AND对一关联】

一对多分成两部分&#xff1a;对一、对多 1. 准备两张表oder、customer 2. 对多关联实现 对多关联&#xff1a;Customer类下创建一个List集合OrderBean类 public class Customer {private Integer id;private String name;//对多关联private List<OrderBean> orderBeanL…

结构型设计模式 Structural Patterns :适配器 Adapter(Python 实现)

文章大纲 python 代码实现实现1实现2实现3解决实际问题的例子参考文献与学习路径使用示例: 适配器模式在 Python 代码中很常见。 基于一些遗留代码的系统常常会使用该模式。 在这种情况下, 适配器让遗留代码与现代的类得以相互合作。 识别方法: 适配器可以通过以不同抽象或…

visual studio2019 定位内存泄漏的方法

1、首先下载一个好用的工具&#xff0c;哈哈&#xff0c;链接在下方https://kinddragon.github.io/vld/下载完后&#xff0c;进行安装&#xff0c;安装完后&#xff0c;文件夹如下所示&#xff1a;2、下面就是打开visual studio进行配置&#xff0c;将include配置好&#xff0c…

关于MAC zsh: command not found: bee 处理方案

最近在玩GO语言&#xff0c;接触到GoBee 这个框架&#xff0c;安装完成后检查beego版本时发现了这个错误“zsh: command not found: bee”。 原因:GO环境配置出问题。 此博文跳过GO的安装过程&#xff0c;直接进入正题。前提是&#xff1a;已经装好了GO。MAC 环境&#xff0c…

六氟磷酸锂洗桶废水除氟树脂吸附工艺

在六氟磷酸锂过程中&#xff0c;主要排放合成氟化锂生产废水和产品六氟磷酸锂桶清洗废水&#xff0c;主要含有氟、磷酸盐及锂&#xff0c;这是一种高氟、高浓度磷酸盐无机化工废水。 针对这类高氟、高浓度磷酸盐无机化工废水&#xff0c;常用于这类生产废水的处理技术有化学沉淀…

力扣刷题|513.找树左下角的值、112. 路径总和、113.路径总和 ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

文章表一LeetCode 513.找树左下角的值题目链接&#x1f517;思路LeetCode 112. 路径总和题目链接&#x1f517;思路LeetCode 113.路径总和 ii题目链接&#x1f517;思路LeetCode 106.从中序与后序遍历序列构造二叉树题目链接&#x1f517;思路LeetCode 105.从前序与中序遍历序列…

Java-基础-5.多线程

一&#xff1a;为什么出现多线程&#xff1f; 1. 线程是指&#xff0c;一段代码的运行&#xff08;cpu&#xff0c;代码&#xff0c;数据&#xff09;。但是&#xff0c;生产中&#xff0c;我们真实情况&#xff0c;数据都是并发传送的&#xff0c;所以&#xff0c;我们仅仅使用…

城市交通应急广播系统方案

恒星科通发布于2023-2-2 一、城市交通指挥与疏导广播系统概述 城市交通指挥与疏导广播即“GSM 无线智能广播”&#xff0c;是利用 GSM 无线接入设备与扩音广播系统组合形成的一款 GSM 无线智能广播系统&#xff0c;该系统用在交通指挥与疏导等智能交通项目有不可替代的优势。系…

C语言之深入解析如何理解指针和结构体指针、指针函数、函数指针

一、指针变量 首先要明白指针就是一个变量&#xff0c;可以使用如下代码来验证&#xff1a; #include "stdio.h"int main(int argc, char **argv) {unsigned int a 10;unsigned int *p NULL;p &a;printf("&a %d\n",a);printf("&a …

Docker如何连接至本地私服Harbor中 推送镜像、查看镜像、下载镜像

1.基础环境 win/mac/linux装有Docker私服 Harbor Docker Docker中文站 Docker官方站 下载并安装Docker Harbor Harbor GitHub Harbor 官方地址 下载并安装 Harbor (测试的话 推荐用Docker镜像来启动Harbor 减少环境问题) 2.配置流程 登录Harbor 启动后 访问 Harbor 的…

状态空间模型与卡尔曼滤波

1.状态空间模型 状态空间模型 (State Space Model)&#xff0c;包括两个方程模型&#xff1a; 一是状态方程模型&#xff0c;反映动态系统在输入变量作用下在某时刻所转移到的状态&#xff1b; 二是输出或测量方程模型&#xff0c;它将系统在某时刻的输出和系统的状态及输入变…

1.Echarts的简单使用

目录 1 下载echarts.min.js 2 使用示例 3 其他参数 Echarts是做前端数据可视化的&#xff0c;数据可视化是将数据做成图表&#xff0c;常见的可视化库有D3.js&#xff0c;ECharts.js,Highchart.js,AntV等 ECharts官网地址 Apache ECharts 进入后点击所有示例 示例中有各…

【MySQL】《狂飙》电视剧火了,如果程序一直狂飙,扛不住了,怎么办呢?

程序如果狂飙了怎么办呢&#xff1f;《狂飙》电视剧你看了吗&#xff1f;程序“狂飙”&#xff0c;你担心吗&#xff1f;性能优化步骤适合创建索引的情况不适合创建索引的情况Explain 性能分析id说明select_type 说明type字段说明Extra说明一下《狂飙》电视剧你看了吗&#xff…

PMI开通便捷的人民币付款

人民币付款通道正式开通啦当PMI持证人士通过PMI全球英文网站(www.pmi.org )进行证书更新缴费时&#xff0c;在原有美金支付的基础上&#xff0c;开通了新的人民币付款通道&#xff0c;包含支付宝和多种信用卡支付方式&#xff0c;持证人士可以按需选择<美金USD>或<人民…

基于梯度下降神经网络训练整体流程

文章目录基于梯度下降神经网络训练整体流程梯度下降优化算法一、简介二、梯度下降方法2.1 批量梯度下降法BGD2.2 随机梯度下降法SGD三、传统梯度下降法面临的挑战四、优化器4.1 Momentum4.2 Adagrad4.3 Adam4.4 对比与选择过拟合、拟合和欠拟合一、防止过拟合方法1.1 早停基于梯…

FFMPEG Vcl Player 7.0 For Delphi Crack

FFMPEG Vcl Player For Delphi 7.0【www_flashavconverter_com】是一个基于 directshow 和 ffmpeg 的 vcl 播放器&#xff0c;用于解码和播放视频/音频。 新增&#xff1a;升级到最新的FFMPEG Runtime(5.1.x)并支持Delphi 11.2 支持 Dash 回放 支持播放AES加密网络流 Nvidia 卡…

一文搞懂MD5、SHA-1、SHA-2、SHA-3,哪个算法比较安全

MD5、SHA-1、SHA-2、SHA-3都是比较常见的单向散列函数&#xff0c;这几种单向散列函数都有自己的特性。下面&#xff0c;给大家介绍一下它们的区别&#xff0c;以及MD5、SHA-1、SHA-2、SHA-3的安全性如何&#xff0c;哪种算法比较安全&#xff1f;一、简介单向散列函数是指对不…

JavaWeb:过滤器与监听器

一、过滤器Filter 1.1 过滤器Filter概述 Filter表示过滤器&#xff0c;是JavaWeb三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一。Servlet我们之前都已经介绍过了&#xff0c;Filter和Listener我们今天都会进行介绍。 过滤器可以把对资源的请求 拦截 下来&…

Python的判断语句

进行逻辑判断&#xff0c;是生活中常见的行为。 同样&#xff0c;在程序中&#xff0c;进行逻辑判断也是最为基础的功能。 布尔类型和比较运算符 布尔类型的字面量&#xff1a; true 表示真&#xff08;是、肯定&#xff09;false 表示假&#xff08;否、否定&#xff09; …