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

V少JS基础班之第八弹:this

文章目录

    • 一、 前言
    • 二、本节涉及知识点
    • 三、重点内容
      • 1、从新的角度认识this
      • 2、this是函数的参数
      • 3、this的值
      • 4、函数的调用
          • 1- 裸函数调用
          • 2- 函数作为构造函数调用
          • 3- 函数作为对象的方法调用
          • 4- 函数显示调用
          • 5- 箭头函数

一、 前言

第八弹内容是this。this相对来说难度不大,外面都说this背诵多过于理解,但是今天我们在这篇文章里由浅入深的理解一下this。文章更新有点慢,脑子一热跑去学后端去了。最近赶赶进度,把之前丢的给补回来。
本系列为一周一更,计划历时6个月左右。从JS最基础【变量与作用域】到【异步编程,密码学与混淆】。希望自己能坚持下来, 也希望给准备入行JS逆向的朋友一些帮助, 我现在脸皮厚度还行。先要点赞,评论和收藏。也是希望如果本专栏真的对大家有帮助可以点个赞,有建议或者疑惑可以在下方随时问。
先预告一下【V少JS基础班】的全部内容,我做了一些调整。看着很少,其实,正儿八经细分下来其实挺多的,第一个月的东西也一点不少。
第一个月【变量作用域BOMDOM数据类型操作符
第二个月【函数闭包原型链this
第三个月【面向对象编程、 异步编程、nodejs】
第四个月【密码学、各类加密函数】
第五个月【jsdom、vm2、express】
第六个月【基本请求库、前端知识对接】

==========================================================

二、本节涉及知识点

函数的参数、对象、 this

==========================================================

三、重点内容

市面上很多资料都说:this的学习记忆多于理解。 只有记住了各种使用方法才能灵活运用。所以经常会有一批人上来就去背诵this的五种绑定方式:
默认绑定隐式绑定显示绑定new绑定箭头函数绑定
刚开始我也是这么学习的,但是说实话,这种靠背诵学习知识点的方式并不适合爬虫逆向。

今天,我们还是以理解为主,让我们开始今天的this学习。

1、从新的角度认识this

首先,学习这篇文章时,请丢掉在外面学习的关于this的任何知识。无论是python中的self,还是c++中的指针。

  • 在this的学习中,我们最先接触的:
    • 第一个概念就是函数。
      • 函数是什么,不知道的去看我之前关于函数的章节。
    • 第二个要接触的概念就是函数的参数
      • 一个函数可以传参也可以不传参
function say_hello(){console.log('hello world!')
}function sum_op(a, b) {return a + b;
}// 调用示例
say_hello()
console.log(sum_op(3, 5)); // 输出 8

但是, 有一个参数, 无论函数传不传参,它都在那。我们不用赋值,只要函数调用时我们就可以使用的一个参数:this

那到这里,我们都能理解的话,那我们已经能掌握this了。 如果我们能理解函数的参数,那理解this就是很简单的事。
我们丢掉我们无法理解的这句话:this是函数执行上下文里的隐藏变量
只需要记住这句话:

this是函数调用时的隐藏参数
1- this是什么:this是个参数
2- this的值: 对象 或 undefined
3- 什么时候用:函数调用时使用

我们今天的大部分内容都围绕着这三个点展开

2、this是函数的参数

我们认识this的途径不止从上下文中来,还可以从函数的参数的角度。
this是作为函数的隐藏参数在函数调用时传递。 函数在定义时我们给定一个形参,而只有在函数调用时,他才会有值。
甚至我们都不用去给他定义形参,在函数调用时,我们随时可以使用this。hook住指定调用时的函数,随意的就能取到this的值
在这里插入图片描述

3、this的值

this的值只会有两种类型: 对象 & undefined
在严格模式下,裸函数调用, this的返回值就是undefined。 在非严格模式下,裸函数调用返回的是window。 window本身就是一个对象。 那其他情况下也是如此,this要么是对象,要么是undefined。

4、函数的调用

说了这么多,其实就是一句话的事情。 那么我们学习this到底是在学习什么呢?那就是现在要说的。 函数的调用。 我们都说了:this是函数调用时的隐藏参数,参数的值只能是对象或者undefined。 那么什么情况下this是对象什么情况下是undefined。 我们如何判断this的值呢。 这就是我们要学习的,函数的几种调用方式。

函数的各种调用方式:

1- 裸函数调用

“裸函数调用”其实就是最直接、最普通的函数调用方式,没有通过对象、call/apply/new 等手段修饰,只是单纯调用函数本身。

function foo() {console.log(this);
}// 裸函数调用
foo();

为什么会有严格和非严格模式下值不同的区别。

其实很简单,严格模式下,是真正的裸函数调用。 没有任何对象调用它,函数自己执行了。此时,是没有任何对象传递的,所以,此时的this是undefined。而在非严格模式下,浏览器环境中,所有的属性和方法都是挂在在window上的,所以非严格模式下,浏览器中的裸函数调用不是真正的裸函数,而是window.fn()

同理,在不同的环境中裸函数调用的this值也是不一样的。比如在浏览器中this为window,而在nodejs的全局中this的值则为global

这就是this背诵点之: 默认绑定
很多课件上来就说,this有五种绑定,我们背诵一下第一种绑定:默认绑定。默认绑定就是:当一个函数被调用时,如果 没有明确指定 this(没有作为对象方法调用、没有 call/apply/bind、没有 new 构造),那么 this 会按照 默认规则绑定。

我觉得这是一种本末倒置的学习方式,如果我们要理解默认绑定,因为由以下方式理解。

什么是默认绑定: 默认绑定就是裸函数调用,没有任何第三方对象或者方法介入。直接用函数名+() 的形式运行函数,就是裸函数调用,也就是八股文中的 this的默认绑定

到此,我们就学会了this的第一个绑定方式。它是一种绑定方式,是由裸函数调用的方式决定了它的绑定方式。

2- 函数作为构造函数调用

那函数除了裸函数调用之外,还有哪些调用方式呢。

还记得函数篇中我们提到的构造函数吗。 除了箭头函数,任何普通函数都可以使用new的方式进行调用,此时的函数为构造函数。 当使用 new 调用一个函数时,就变成构造函数调用:

function Person(name) {this.name = name;
}const p = new Person('Alice');
console.log(p.name); // Alice
this 指向
构造函数调用时,this 永远指向新创建的对象
和普通函数或方法调用不同:
  • 普通函数(裸函数调用)→ this 根据严格模式决定(undefined 或 window/global)
  • 方法调用 → this 指向点左边对象
  • 构造函数 → this 永远是新对象(或被返回对象覆盖)

为什么呢, 我们看一下new调用函数时发生了什么

new 会做几件事情:
创建一个空对象(obj)
将 this 指向这个新对象
执行构造函数的代码
默认返回 this(新对象),除非显式返回对象

所以此时的this指向是固定的。

3- 函数作为对象的方法调用

当函数作为 对象的属性 被调用时,我们称它为 方法调用。示例如下:

const obj = {x: 42,foo: function() {console.log(this);}
};obj.foo(); // 方法调用

this 指向: 调用时,点前面的对象

作为对象方法调用时的典型例子

1) 对象直接调用

const obj = {name: 'Alice',greet: function() {console.log(this.name);}
};obj.greet(); // Alice// 这里 this 指向 obj

2) 多层对象

const obj = {inner: {name: 'Bob',say: function() { console.log(this.name); }}
};obj.inner.say(); // Bob// 点运算符左边是 obj.inner → this = obj.inner

3) 注意“丢失”情况

const obj = {x: 10,foo: function() { console.log(this.x); }
};const bar = obj.foo;
bar(); // undefined 或 window.x(非严格模式下) 
原因:bar 是函数的引用,不再是对象的方法调用. 这种情况就变成了 裸函数调用

总结:

在对象调用方法的情况下一定要注意对象丢失的情况。 使用函数赋值的时候,裸函数调用和对象的方法调用不能混为一谈

好, 那对象.方法的形式,是什么绑定呢。 答案是: this的隐示绑定
当我们用对象.函数的方式调用函数,此时函数中的this就已经与该对象进行了绑定。 此时就是隐示绑定。

这就是我们背诵的this的第二个绑定方式

4- 函数显示调用

不知道大家有没有见过call和apply调用函数。比较经典的:

function sum(a, b, c) { return a + b + c; }
const nums = [1, 2, 3];
console.log(sum.apply(null, nums)); // 6
// 用于计算
const arr = [3, 1, 4];
const max = Math.max.apply(null, arr); // 4
// 查找最大值

其实,函数作为所谓的一等公民,他是给我们提供了很多的方便,有些已经写好的库,我们可以直接拿过来使用,我们对指定的对象用现有的函数,这种调用方式并不少见。

此时,我们对指定的函数进行call和apply与对象进行绑定。这种方式从this的角度看,他就是this的显示绑定。我们直接明确的告诉大家,该函数是由该对象调用的。this也就是显示的绑定在这个对象上。

总结:
ok,到这里大家已经学习了this的四种绑定方式了。 如此的水到渠成,完全不用背诵各种复杂的逻辑。函数怎么调用,this就是对应的绑定。 他的值也就是对应的值。

那我们最后再看一个特殊的绑定方式。

5- 箭头函数

1) 箭头函数的基本调用(裸函数调用)

const add = (a, b) => a + b;console.log(add(2, 3)); // 5

this 指向定义时的外层作用域(词法绑定),而不是调用者

2)作为对象方法调用

const obj = {name: 'Alice',arrow: () => console.log(this.name)
};obj.arrow(); // undefined(this不是obj,而是定义时的外层 this)

箭头函数不会绑定对象
无论怎么调用,this 都不会指向调用对象
如果想访问对象属性,需要用普通函数或外部变量

3) 作为回调函数调用

setTimeout(() => {console.log('Hello');
}, 1000);

常用于回调函数中
不会创建新的 this,继承外层作用域的 this
避免了普通函数在回调中 this 指向全局或 undefined 的问题

4)与 call / apply / bind 的区别

const arrow = () => console.log(this);
arrow.call({ a: 1 }); // 依然指向定义时的 this

箭头函数 不能被 call / apply 改变 this

总结:
调用方式:基本和普通函数一样,可直接调用、作为回调或对象属性
特殊点:
  • 没有自己的 this,继承外层作用域
  • 不能被显式绑定(call/apply/bind 改变 this 无效)
  • 适合用于回调或内部函数,避免 this 指向混乱

口语化OS:

我们其实完全可以这么理解。当上下文在被调用的函数中时: 箭头函数本身就无法改变this,所以,此时的this就是被调用函数当前状态的this

这句话怎么理解呢。 就是,除了箭头函数之外的其他调用方式大家都理解了。 此时情况:
在这里插入图片描述
上下文正在debugger处。 在函数内部。 此时的this绑定的哪个就是哪个,这时候,函数内部有再多的箭头函数,都不会改变this的指向。我们就记住一句话,箭头函数无法改变this的绑定

以上就是this的五种绑定的全部内容。 今天就先到这里。如果本篇文章对大家有帮助,还望点赞关注,后续再给大家加一点this优先级的相关内容。


文章转载自:

http://iMF2BFCO.cndxL.cn
http://xvrWfUMZ.cndxL.cn
http://Onw5ikm5.cndxL.cn
http://iDPvnigj.cndxL.cn
http://nkbxIZCJ.cndxL.cn
http://5vBA912U.cndxL.cn
http://cP8F7D7c.cndxL.cn
http://yEbukhN9.cndxL.cn
http://mnpQhZjt.cndxL.cn
http://mEQxagMT.cndxL.cn
http://1fmsfvBB.cndxL.cn
http://daLW4ZHv.cndxL.cn
http://BplnSKsW.cndxL.cn
http://GCuV5j9B.cndxL.cn
http://rrg0KSOM.cndxL.cn
http://ZYDh2vpG.cndxL.cn
http://PbBGCTcx.cndxL.cn
http://H3TveP95.cndxL.cn
http://9RdQktDF.cndxL.cn
http://mwJe7ayA.cndxL.cn
http://twuqxEKY.cndxL.cn
http://RRl7wUrj.cndxL.cn
http://N1liKbVh.cndxL.cn
http://e4VlnEEZ.cndxL.cn
http://BIBpEC8z.cndxL.cn
http://8DAvFkDI.cndxL.cn
http://DQrbhzrc.cndxL.cn
http://MTWMp6Ta.cndxL.cn
http://vY8YQhWJ.cndxL.cn
http://bXw5oFQH.cndxL.cn
http://www.dtcms.com/a/381267.html

相关文章:

  • Class52 双向循环神经网络
  • STM32HAL库_cubeMX
  • Class54 编码器-解码器
  • c++多设备并发运行且互相操作 上位机软件结构
  • PCDN双跑量系统
  • Altium Designer使用精通教程 第三章(原理图绘制及编译检查)
  • Docker技术解析
  • MySQL数据库(一)—— 数据库基础与MySQL安装管理指南
  • 京东商品详情 API 全解析:合规对接与 B2C 场景实战指南
  • 高德地图从零开始:Key 申请到项目初始化全流程教程(Vue3 + AMap 2.0)
  • 从跟跑到领跑:OBOO鸥柏触摸屏的军用信息化技术自主之路
  • LLM(三)
  • u盘 修复
  • C++异常处理设计与实践:主动抛出异常的处理策略
  • 嵌入式数据结构笔记三——单向链表Ⅲ
  • Ampace厦门新能安校招/社招Verify测评演绎数字推理行测真题题库及远程助攻
  • ORM框架SQLAlchemy工具:模型类(Model Class)和实体类(Entity Class)介绍
  • CSS布局 - 定位 -- 笔记4
  • 智能过滤器系统:基于实际数据的动态Admin过滤方案
  • 发挥nano banana的最大能力
  • Nvidia GPU 明细表、架构详解
  • 达梦数据库相关操作语句
  • 拓扑排序--算法题
  • transformer 相对位置编码详解
  • 【学习K230-例程20】GT6700-TCP-Server
  • 一文理清合同金额、已确认金额、累计开票金额、最大可开票金额、未票应收金额之间的关系
  • 复杂任务拆解艺术:如何通过多次对话与提示词工程高效解决难题
  • 函数(其实写文章是为了体验和练习LateX公式)
  • 盒子模型导读
  • 《动物营养与饲料学》复习题五套(含答案)