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

【JavaScript】【分享】关于this

前言

本文旨在总结实践中关于this关键字的应用经验,期待读者在评论区留言指正与补充,以促进共同学习与进步。

方向

  1. 宿主环境为浏览器(网页),创建一个html文件用浏览器打开即可。如下:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>关于this</title></head><body><script>// 代码</script></body>
</html>
  1. 严格模式和非严格模式。
  2. 普通函数和箭头函数。
  3. bind,call,apply。
  4. new关键字。

1.为什么要用this?

看下面例子:

      Object.prototype.eat = function () {console.log(this.name);};const peach = {name: "peach",};  peach.eat();

原型最常被用作方法的容器。相似的对象都有相似的方法,所以将所有方法挂载到同一个共享原型上。那么,原型上的函数如何知道自己在执行的时候应该作用于哪个对象呢?这就要用到this了。
再看一个例子:

function eat() {console.log(this.name);}
const peach = {name: "peach",
};
const plum = {name: "plum",
};
eat.call(peach); // peach
eat.call(plum); // plum

这段代码可以在不同的上下文对象(peach和plum)中重复使用函数eat(),不用针对每个对象编写不同版本的函数。

情况一

看下面例子:

function fruit_shop() {console.log(this);
}
fruit_shop() // window
"use strict"
function fruit_shop() {
console.log(this);
}
fruit_shop() // undefined
function fruit_shop() {console.log(this);
}
(function () {"use strict";fruit_shop(); // window
})();
function fruit_shop_eat() {console.log(this);function eat_plum() {console.log(this);}eat_plum();
}
const fruit_shop = {name: "welcome to 1 of xiao wu fruit shop",
};
fruit_shop_eat.call(fruit_shop); // fruit_shop  window

小结

this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息。this就是这个记录的一个属性,会在函数执行的过程中用到。

将上面列子换成箭头函数在来看下结果

const fruit_shop = () => {console.log(this);
};
fruit_shop(); // window
"use strict"
const fruit_shop = () => {console.log(this);
};
fruit_shop(); // window
const fruit_shop = () => {console.log(this);
};
(() => {"use strict";fruit_shop(); // window
})();
const fruit_shop_eat = () => {console.log(this);const eat_plum = () => {console.log(this);};eat_plum();
};
const fruit_shop = {name: "welcome to 1 of xiao wu fruit shop",
};
fruit_shop_eat.call(fruit_shop); // window  window

额外的例子

const fruit_shop_eat = () => {console.log(this);return () => {console.log(this);};
};
const fruit_shop = {name: "welcome to 1 of xiao wu fruit shop",
};
const eat = fruit_shop_eat.call(fruit_shop); // window
eat(); //   window
function fruit_shop_eat() {console.log(this);return () => {console.log(this);};
}
const fruit_shop = {name: "welcome to 1 of xiao wu fruit shop",
};
const eat = fruit_shop_eat.call(fruit_shop); // fruit_shop
eat(); // fruit_shop

小结

ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)。而是根据当前的词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。这其实和ES6之前代码中的self = this机制一样。

情况二

看下面例子:

function eat() {console.log(this.name);
}
const peach = {name: "peach",eat,
};
peach.eat(); // peach

小结

调用位置会使用peach上下文来引用函数,当eat()被调用时,它的前面加上了对peach的引用。当函数引用有上下文对象时,会把函数调用中的this绑定到这个上下文对象。因此this.name和peach.name是一样的。

看下面例子:

function eat() {console.log(this.name);
}const peach = {name: "peach",eat,
};const fruit_shop = {name: "fruit shop",peach,
};
fruit_shop.peach.eat(); // peach

小结

对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。

看下面例子:

function eat() {console.log(this);
}
const peach = {name: "peach",eat,
};
const eat_fresh = peach.eat;
eat_fresh(); // window
console.log(eat_fresh === eat); // true

小结

peach.eat和eat_fresh引用的是eat函数本身,eat_fresh不是一个对象属性。在非严格模式下指向window。

情况三

使用apply,bind,call方法

function fruit_shop() {console.log(this); 
}
const fruit_shop_bind = fruit_shop.bind({});
fruit_shop_bind(); // {}
fruit_shop.apply({}); // {}
fruit_shop.call({}); // {}
const fruit_shop = () => {console.log(this);
};
const fruit_shop_bind = fruit_shop.bind({});
fruit_shop_bind(); // window
fruit_shop.apply({}); // window
fruit_shop.call({}); // window

小结
Function 实例的 apply() ,bind(),call()方法会以给定的 this 值。三种方法不适应于箭头函数(this 的值将保持为闭合词法上下文的值)。

情况四

看下以下例子:

function FruitShop() {this.peach = "peach"console.log(this);
}
new FruitShop(); // FruitShop
function FruitShop() {this.peach = "peach";
}    
console.log(new FruitShop().peach); // peach

小结

该情况需要清楚使用new关键字会发生什么:

  1. 创建一个空的简单 JavaScript 对象。为方便起见,我们称之为 newInstance。
  2. 如果构造函数的 prototype 属性是一个对象,则将 newInstance 的 [[Prototype]] 指向构造函数的 prototype 属性,否则 newInstance 将保持为一个普通对象,其 [[Prototype]] 为 Object.prototype。
  3. 使用给定参数执行构造函数,并将 newInstance 绑定为 this 的上下文(换句话说,在构造函数中的所有 this 引用都指向 newInstance)。
  4. 如果构造函数返回非原始值,则该返回值成为整个 new 表达式的结果。否则,如果构造函数未返回任何值或返回了一个原始值,则返回 newInstance。(通常构造函数不返回值,但可以选择返回值,以覆盖正常的对象创建过程。)

总结

以上是我个人实践的总结,难免有疏漏或偏差之处,诚邀各位在评论区不吝赐教,让我们一起在交流中学习成长。

主要文献

  1. 《JavaScript高级程序设计(第4版)》;
  2. 《JavaScript语法简明手册》;
  3. 《你不知道的JavaScript(上卷)》 ;
  4. mdn web docs - this
  5. mdn web docs - new
  6. mdn web docs - apply
  7. mdn web docs - bind
  8. mdn web docs - call

相关文章:

  • CSS实现一个雨滴滑落效果
  • 新奇css模板
  • Java/Golang:活用interface,增加程序扩展性
  • 堆和栈的空间利用率
  • 2024下《系统集成项目管理工程师》50个高频考点汇总!值得收藏
  • 怎么建设高性能多核DSP+FPGA实验室?一起来河北工程大学看看
  • HTML中Canvas关键知识点总结
  • 一场决定未来的战役,又是梦想起航的地方
  • 【玄机-应急平台】第六章 流量特征分析-蚂蚁爱上树
  • kubernetes负载均衡---MetalLB
  • STM32项目分享:智能家居语音系统
  • python基于flask写后端接口、python接收请求、python作为服务端提供接口、python接收json数据或数组
  • JVM学习-JVM运行时参数
  • 24.6.2(动态开点线段树)
  • 股票数据集1-纳斯达克NASDAQ 100简介
  • Fundebug计费标准解释:事件数是如何定义的?
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • js
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • Nodejs和JavaWeb协助开发
  • Python语法速览与机器学习开发环境搭建
  • Vultr 教程目录
  • 大型网站性能监测、分析与优化常见问题QA
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 详解移动APP与web APP的区别
  • 学习笔记:对象,原型和继承(1)
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • NLPIR智能语义技术让大数据挖掘更简单
  • UI设计初学者应该如何入门?
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #Java第九次作业--输入输出流和文件操作
  • #php的pecl工具#
  • (10)STL算法之搜索(二) 二分查找
  • (4)Elastix图像配准:3D图像
  • (vue)el-tabs选中最后一项后更新数据后无法展开
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (四) Graphivz 颜色选择
  • .apk 成为历史!
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET Core Web APi类库如何内嵌运行?
  • .NET Core 和 .NET Framework 中的 MEF2
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET Remoting学习笔记(三)信道
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • .net知识和学习方法系列(二十一)CLR-枚举
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @31省区市高考时间表来了,祝考试成功
  • @Bean注解详解
  • @Transaction注解失效的几种场景(附有示例代码)