〖大前端 - 基础入门三大核心之JS篇(51)〗- 面向对象之认识上下文与上下文规则

  • 说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费如需要项目实战或者是体系化资源,文末名片加V!
  • 作者:哈哥撩编程,十余年工作经验, 从事过全栈研发、产品经理等工作,目前在公司担任研发部门CTO。
  • 荣誉:2022年度博客之星Top4、2023年度超级个体得主、谷歌与亚马逊开发者大会特约speaker全栈领域优质创作者

  • 🏆 白宝书系列
    • 🏅 启示录 - 攻城狮的自我修养
    • 🏅 Python全栈白宝书
    • 🏅 ChatGPT实践指南白宝书
    • 🏅 产品思维训练白宝书
    • 🏅 全域运营实战白宝书
    • 🏅 大前端全栈架构白宝书


文章目录

  • ⭐认识上下文
  • ⭐上下文规则
    • 🌟上下文规则1
    • 🌟上下文规则2
    • 🌟上下文规则3
    • 🌟上下文规则4
    • 🌟上下文规则5
    • 🌟上下文规则6

⭐认识上下文

小时候学习做阅读理解时,老师经常会强调,注意上下文。比如有一个句子:这是一个好习惯,我们应该坚持。如果不结合上文的意思,根本不知道“这”指的是什么。如果结合上文,比如,随手关灯,这是一个好习惯,我们应该坚持。我们就知道此时的“这”指的是“随手关灯”,那么整个句子的语义就好理解了。

在函数中,也经常需要结合上下文来编写和理解代码。

函数中可以使用this,表示函数的上下文

与中文中的“这”类似,函数中的this具体指代什么必须通过调用函数时的“前言后语”来判断

下面看一个例子:

  • 第一种调用方式:对象打点调用自己的方法:
var xiaomumu = {name: '小沐沐',age: 2,sex: '男',hobbies: ['秋千', '滑梯'],sayHello: function () {console.log('Hello, 我是' + this.name + ',我今年' + this.age + '岁了');}
};
xiaomumu.sayHello();   // Hello, 我是小沐沐,我今年2岁了
  • 第二种调用方式:对象的方法被赋值给一个全局变量,全局变量加圆括号调用:
var xiaomumu = {name: '小沐沐',age: 2,sex: '男',hobbies: ['秋千', '滑梯'],sayHello: function () {console.log('Hello, 我是' + this.name + '我今年' + this.age + '岁了');}
};var sayHello = xiaomumu.sayHello;   // 将这个属性存入了一个全局变量(变量的名称可以和属性名相同,方便理解)
sayHello();   //Hello, 我是undefined我今年undefined岁了

这两种调用方式,this指代的对象分别是:

  • 第一种,对象打点调用方式,函数中的this指代这个打点的对象
  • 第二种,圆括号直接调用函数,函数中的this指代window对象

其实可以这么理解,第二种中,因为全局变量都是window的属性,相当于用window.sayHello()的方式调用了这个函数。所以this指代的就是window对象。

所以我们一定要记住:只有函数被调用时,我们才能知道this指代的是什么函数的上下文由函数的调用方式决定,同一个函数,用不同的形式调用它,则函数的上下文不同

⭐上下文规则

我们知道,不同的调用方式,函数的上下文就不同,那么我们怎么去判断函数的上下文呢?这就要学习各种不同的函数调用规则。

🌟上下文规则1

规则1:对象打点调用它的方法函数,则函数的上下文是这个打点的对象

下面看几个案例,练习一下:

题目一: 下面代码的运行结果是什么?

function fn() {console.log(this.a + this.b);
}
var obj = {a: 11,b: 22,fn: fn
};obj.fn();

运行结果:33

题目二: 下面代码的运行结果是什么?

var obj1 = {a: 1,b: 2,fn: function () {console.log(this.a + this.b);}
};var obj2 = {a: 3,b: 4,fn: obj1.fn
};obj2.fn();

运行结果: 7

一定要记住,谁打点调用函数,函数中的this指代的就是谁

题目三: 下面代码的运行结果是什么?

function outer() {var a = 11;var b = 22;return {a: 33,b: 44,fn: function () {console.log(this.a + this.b);}};
}outer().fn();

运行结果:77

上面的代码中,outer()返回了一个对象,相当于还是一个对象打点调用了函数,所以适用于对象打点调用函数,函数的上下文就是这个对象的规则。

题目四: 下面代码的运行结果是什么?

function fun() {console.log(this.a + this.b);
}var obj = {a: 1,b: 2,c: [{a: 3,b: 4,c: fun}]
};var a = 5;
obj.c[0].c();

运行结果:7

上面的代码中,最终调用函数的是obj.c[0]这个对象,所以函数中的this指代的就是obj.c[0]

🌟上下文规则2

规则2:圆括号直接调用函数,则函数的上下文是window对象

题目一: 下面代码的运行结果是什么?

var obj1 = {a: 1,b: 2,fn: function () {console.log(this.a + this.b);}
};
var a = 3;
var b = 4;var fn = obj1.fn;
fn();

运行结果:7

题目二: 下面代码的运行结果是什么?

function fun() {return this.a + this.b;
}
var a = 1;
var b = 2;
var obj = {a: 3,b: fun(),fun: fun
};
var result = obj.fun();
console.log(result);

运行结果:6,题目分析如下:

image-20230509165256380

这是一道非常正规的面试题,大家一定要学会分析其中的代码逻辑

🌟上下文规则3

规则3:数组(类数组对象)枚举出函数进行调用,上下文是这个数组(类数组对象)

数组[下标]()

类数组对象:所有键名为自然数序列(从0开始),且有length属性的对象

arguments对象是最常见的类数组对象,它是函数的实参列表

题目一: 下面代码的运行结果是什么?

var arr = ['A', 'B', 'C', function () {console.log(this[0]);
}];arr[3]();

运行结果: “A”

上面的代码适用规则3,this指代的就是arr这个数组

题目二: 下面代码的运行结果是什么?

function fun() {arguments[3]();
}fun('A', 'B', 'C', function () {console.log(this[1]);
});

运行结果:“B”。我们可以打印一下arguments,可以看到arguments是一个类数组对象,里面其实就是fun()函数被调用时,传入的实参:

image-20230509164048474

🌟上下文规则4

规则4:IIFE中的函数,上下文是window对象。(IIFE在以前的文中提到过,是立即可执行函数。)

(function (){

​ //立即可执行函数

})()

题目一: 下面代码的运行结果是什么?

var a = 1;
var obj = {a: 2,fun: (function () {var a = this.a;return function () {console.log(a + this.a);}})()
};
obj.fun();

运行结果:3。这是一个大厂的面试题,题目分析如下:

image-20230509165927143

🌟上下文规则5

规则5:定时器、延时器调用函数,上下文是window对象

setInterval(函数,时间);

setTimeout(函数,时间);

题目一: 下面代码的运行结果是什么?

var obj = {a: 1,b: 2,fun: function () {console.log(this.a + this.b);}
};
var a = 3;
var b = 4;setTimeout(obj.fun, 2000);

运行结果:7。因为用延时器调用的函数,适用规则5,this指代的就是window对象,即this.athis.b的值分别是3,4

题目二: 下面代码的运行结果是什么?

var obj = {a: 1,b: 2,fun: function () {console.log(this.a + this.b);}
};
var a = 3;
var b = 4;setTimeout(function () {obj.fun();    //适用规则1
}, 2000);

运行结果:3。这里要注意,延时器不是直接调用obj里的fun函数,而是一个匿名函数,这个匿名函数里又调用了obj.fun(),所以此时的this应指代的是obj这个对象,即this.athis.b的值分别是1,2

🌟上下文规则6

规则6:事件处理函数的上下文是绑定事件的DOM元素

DOM元素.onclick = function() {

};

题目一: 点击哪个盒子,哪个盒子就变红,要求使用同一个事件处理函数实现(不能用事件委托)

<html lang="en">
<head><style>div {width: 200px;height: 200px;float: left;border: 1px solid #000;margin-right: 10px;}</style>
</head>
<body><div id="box1"></div><div id="box2"></div><div id="box3"></div><script>function setColorToRed(o) {this.style.backgroundColor = 'red';}var box1 = document.getElementById('box1');var box2 = document.getElementById('box2');var box3 = document.getElementById('box3');box1.onclick = function () {setColorToRed(box1);}box1.onclick = setColorToRed;box2.onclick = setColorToRed;box3.onclick = setColorToRed;</script>
</body>
</html>

运行结果:点击哪个盒子,哪个盒子就变红。这里的this指代的就是绑定事件的DOM元素;注意区分this和e.target的不同

题目二: 点击哪个盒子,哪个盒子在2000毫秒后就变红,要求使用同一个事件处理函数实现(不能用事件委托)

题目分析:这个题目其实就是上个题目+一个延时器,但是需要注意的是加上延时器后,this指代的可能会不一样,所以需要使用一个程序猿非常常用的技术:备份上下文

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 200px;height: 200px;float: left;border: 1px solid #000;margin-right: 10px;}</style>
</head>
<body><div id="box1"></div><div id="box2"></div><div id="box3"></div><script>function setColorToRed(o) {//备份上下文var self = this;  // 通常使用self来备份上下文,也有使用that或_this的,这个技术非常的常用!setTimeout(() => {self.style.backgroundColor = 'red';}, 2000);}var box1 = document.getElementById('box1');var box2 = document.getElementById('box2');var box3 = document.getElementById('box3');box1.onclick = function () {setColorToRed(box1);}box1.onclick = setColorToRed;box2.onclick = setColorToRed;box3.onclick = setColorToRed;</script>
</body>
</html>

注意:程序员在书写this的时候通常会看一下这个this到底指代什么,需不需要备份

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

web漏洞原理与防御策略,web漏洞怎么挖掘

目录 Web安全的重要性 ​编辑常见的Web漏洞类型及其原理&#xff1a; 1、跨站脚本攻击&#xff08;XSS&#xff09;: 2、SQL注入: 3、跨站请求伪造&#xff08;CSRF&#xff09;: 4、远程文件包含&#xff08;RFI&#xff09;和本地文件包含&#xff08;LFI&#xff09;:…

ONLYOFFICE协作空间2.0:文档协作更便捷

〇、前言 大家好我是陈橘又青&#xff0c;在之前的文章中&#xff0c;我向大家介绍了ONLYOFFICE&#xff1a;免费、开源、跨平台的办公神器&#xff0c;想必大家都已经了解到了ONLYOFFICE在企业办公、文档处理工作中的方便快捷。ONLYOFFICE 2.0版本也已于近日更新。 今天就来跟…

市场全局复盘 20231211

昨日回顾&#xff1a; SELECT TOP 10000 CODE,成交额排名,净流入排名,代码,名称,DDE大单金额,涨幅,所属行业,主力净额,DDE大单净量,CONVERT(DATETIME, 最后涨停时间, 120) AS 最后涨停时间 FROM dbo.全部&#xff21;股20231208_ALL WHERE 连板天 > 1AND DDE大单净量 > …

ArcGIS无法绘制一个或多个图层

背景&#xff1a;在导入一份数据时候&#xff0c;arcmap出现无法绘制一个或多个图层的错误&#xff0c;...点数少于要素所要求的的数量&#xff0c;查阅了半天资料发现是制作数据时候拓扑关系错误造成&#xff0c;现将处理方法详细记录如下&#xff1a; 1.原数据&#xff1a; …

NSSCTF Crypto靶场练习,21-30wp

文章目录 [AFCTF 2018]你能看出这是什么加密么[LitCTF 2023]你是我的关键词(Keyworld)[NSSCTF 2022 Spring Recruit]classic[SWPUCTF 2021 新生赛]crypto4[LitCTF 2023]家人们&#xff01;谁懂啊&#xff0c;RSA签到都不会 (初级)[SWPUCTF 2021 新生赛]crypto5[LitCTF 2023]Is …

使用Microsoft Dynamics AX 2012 - 7. 库存管理

库存和仓库管理的主要职责是按数量和价值控制物料库存。若要完成此任务&#xff0c;您只能通过过帐库存交易记录来更改Dynamics AX中的库存&#xff0c;而这些交易记录之前需要在凭证中注册。 因此&#xff0c;库存中的当前数量始终是物料出库和入库交易记录的总和。大多数交易…

ChatGPT能帮助--掌握各种AI绘图工具,随意生成各类型性图像

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…

google突然就发布了Gemini

一天就被刷屏了。 google发布Gemini多模态大模型&#xff0c;还发布了一个几分钟的视频&#xff0c;我相信看完视频都会说一句&#xff1a;NB。 视频可以去B站或者其他地方搜 Gemini。 感觉机器不仅有脑子了&#xff0c;还长眼睛了。 Gemini是原生多模态大模型&#xff0c;…

数据库系列之简要对比下GaussDB和OpenGauss数据库

GaussDB作为一款企业级的数据库产品&#xff0c;和开源数据库OpenGauss之间又是什么样的关系&#xff0c;刚开始接触的时候是一头雾水&#xff0c;因此本文简要对比下二者的区别&#xff0c;以加深了解。 1、GaussDB和OpenGauss数据库简要对比 GaussDB是华为基于PostgreSQL数据…

PyQt6 表单布局Form Layout (QFormLayout)

锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计43条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版…

ERROR: [BD 41-237] Bus Interface property FREQ_HZ does not match between

在自定义IP出现以上错误时可以通过双击模块clk属性 如果是灰色无法二次编辑时&#xff0c;在封装IP时&#xff0c;选择以下菜单