• 作者:陈大鱼头
  • github: KRISACHAN
  • 链接:github.com/YvetteLau/S…
  • 背景:最近高级前端工程师 刘小夕github 上开了个每个工作日布一个前端相关题的 repo,怀着学习的心态我也参与其中,以下为我的回答,如果有不对的地方,非常欢迎各位指出。

例子

<script>// 浏览器正常情况下console.log(this === window) // true
</script>
<script>// 函数调用a = 10;function fn1 () {console.log(this.a)}fn1() // 10b = 2console.log(this.b) //2function fn2 () {this.b = 3}fn2()console.log(this.b) // 3
</script>
<script>// 方法调用function test () {console.log(this.x)}x = 2var o = {}o.x = 1o.m = testo.m() // 1
</script>
<script>// 构造函数调用x = 2function test () {this.x = 1}var o = new test()console.log(x) // 2
</script>
<script>// apply调用x = 0function test () {console.log(this.x)}var o = {}o.x = 1o.m = testo.m.apply(o) // 1
</script>
<script>// 函数 apply调用var zz = {};zz.a = 1000;a = 10;function fn1 () {console.log(this.a)}fn1.apply(zz) // 1000b = 2console.log(this.b) //2function fn2 () {this.b = 3}fn2.apply(zz)console.log(this.b) // 2
</script>
<script>// 函数 apply调用var qqq = {a: 1}var ttt = {a: 2}var mmm = {a: 3}function fq () {console.log(this)}fq.bind(qqq).bind(ttt).bind(mmm)() // {a: 1}
</script>
<script>// forEachvar arr = [1, 2, 3, 4]var newarr = [5, 6, 7, 8]var newnewarr = [9, 10, 11, 12]arr.forEach(function (e, i, a) {console.log(this) // newarr}, newarr)arr.forEach((e, i, a) => {console.log(this) // window}, newarr)
</script>
<script>// 立即执行函数(function () {console.log(this) // window})()var o = {};o.x = 999;(function () {console.log(this) // {x:999}}).apply(o);(() => {console.log(this) // window})();(() => {console.log(this) // window}).apply(o)
</script>
<script>'use strict'console.log(this === window) // true
</script>
<script>'use strict'var k = {a: 1,b: 2,c: 3}const fn1 = function () {console.log(this)}fn1() // undefinedfn1.apply(k) // {a: 1, b: 2, c: 3}k.m = fn1k.m() // {a: 1, b: 2, c: 3, m: ƒ}
</script>
<script>'use strict'const o = {a: 1,b: 2,c: 3}const fn2 = () => {console.log(this)}fn2() // windowfn2.apply(o) // windowo.m = fn2o.m() // window
</script>
<script>'use strict'const oo = {d: function () {console.log(this)},e: () => {console.log(this)}}const ooo = {a: 1,b: 2,c: 3}oo.d() // {d: ƒ, e: ƒ}oo.e() // windowoo.d.apply(ooo) // {a: 1, b: 2, c: 3}oo.e.apply(ooo) // windowvar xxx = oo.dvar yyy = oo.exxx() // undefinedyyy() // window
</script>
<script>'use strict'// forEachvar arr = [1, 2, 3, 4]var newarr = [5, 6, 7, 8]var newnewarr = [9, 10, 11, 12]arr.forEach(function (e, i, a) {console.log(this) // newarr}, newarr)arr.forEach((e, i, a) => {console.log(this) // window}, newarr)
</script>
复制代码

总结

上面简单列了 window 下的几种情况,但其实在node下的情况也类似。 其实法则总结起来就是下面几点:

  1. 无论是否在严格模式下,在全局执行环境中(在任何函数体外部) this 都指向全局对象。
  2. 简单函数调用, this 在一般模式下指向全局对象;严格模式下 this 默认为 ndefined
  3. call , bind, apply在非箭头函数下修改 this 值;箭头函数下无法修改(由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数),不管call , bind, apply多少次,函数的 this 永远由第一次的决定。
  4. 当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。
  5. 如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。
  6. 当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

在ECMA内, this 会调用 原生方法 ResolveThisBinding() 原生方法ResolveThisBinding使用正在运行的执行上下文的LexicalEnvironment确定关键字this的绑定。 ResolveThisBinding执行以下步骤:

  1. 设置 envRecGetThisEnvironment()
  2. 返回 envRec.GetThisBinding()

原生方法GetThisEnvironment找到当前提供关键字 this 绑定的环境记录。 GetThisEnvironment 执行以下步骤:

  1. 设置 lex 为​​正在运行的执行上下文的 LexicalEnvironment
  2. 重复以下行为: a. 设置 envReclex 的 环境记录; b. 设置 existsenvRec.HasThisBinding() c. 如果 exists 为真,返回出 envRec d.设置 outerlex 的外部环境参考值。 e. 断言: outer 不是 null f. 设置 lexouter

注意:步骤2中的循环必须终止,因为列表的环境总是以全局环境这个绑定。

如果你、喜欢探讨技术,或者对本文有任何的意见或建议,你可以扫描下方二维码,关注微信公众号“鱼头的Web海洋”,随时与鱼头互动。欢迎!衷心希望可以遇见你。

前端进阶之如何正确判断this的指向?相关推荐

  1. 前端进阶垫脚石-前端工程化

    什么是前端工程化 前端工程化,就是降本提效的体现 广义上,前端工程化包含一切以降低成本.提高效率.保障质量为目的的手段 通过一系列的规范.流程.工具达到研发提效.自动化.保障质量.服务稳定.预警监控等 ...

  2. LEARN_前端进阶_深浅拷贝原理

    详细解析赋值.浅拷贝和深拷贝的区别 赋值(Copy) 赋值是将某一数组或对象赋给某个变量的过程,分类下面 2 部分: 基本数据类型:赋值,赋值之后两个变量互不影响 引用数据类型:赋址,两个变量具有相同 ...

  3. 2021年高级前端进阶之路

    YYDS 2021年高级前端进阶之路1.两边固定,中间自适应布局(1.用flex;2.用display:left;3.用相对定位和绝对定位结合)2.js判断字符串中出现次数最多的字符(1.用for循环 ...

  4. 3万6千字爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行

    3w6爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行 认识函数式编程 函数相关复习 函数是一等公民 高级函数 函数作为参数 案例 1,模拟 forEach 案例 2, ...

  5. 正确判断js数据类型 总结记录

    正确判断js数据类型 总结记录 判断js中的数据类型有一下几种方法:typeof.instanceof. constructor. prototype. 三方库. js六大数据类型 number: 数 ...

  6. fifo算法_前端进阶算法6:一看就懂的队列及配套算法题

    引言 队列这种数据结构,据瓶子君了解,前端需要了解的队列结构主要有:双端队列.滑动窗口,它们都是算法中是比较常用的数据结构. 因此,本节主要内容为: 数据结构:队列(Queue) 双端队列(Deque ...

  7. IT:前端进阶技术路线图(初级→中级→高级)之初级(研发工具/HTML/CSS/JS/浏览器)/中级(研发链路/工程化/库/框架/性能优化/工作原理)/高级(搭建/中后台/体验管理等)之详细攻略

    IT:前端进阶技术路线图(初级→中级→高级)之初级(研发工具/HTML/CSS/JS/浏览器)/中级(研发链路/工程化/库/框架/性能优化/工作原理)/高级(搭建/Node/IDE/中后台/体验管理/ ...

  8. 【2019 前端进阶之路】深入 Vue 响应式原理,活捉一个 MVVM

    作者:江三疯,专注前端开发.欢迎关注公众号前端发动机,第一时间获得作者文章推送,还有各类前端优质文章,致力于成为推动前端成长的引擎. 前言 作为 Vue 面试中的必考题之一,Vue 的响应式原理,想必 ...

  9. 综合时如何插入scan_三综合环境试验箱维修时如何做出正确判断?

    三综合环境试验箱维修时如何做出正确判断? 三综合环境试验箱在试验的过程中,可以根据需要设定不同的温度情况,以便于为各种测试要求提供便利的条件.在测试一些材料结构或复合材料的时候,主要是利用其在瞬间高温 ...

最新文章

  1. tar.xz、tar.bz2 压缩包解压方式
  2. google nexus5 root 安装Xposed框架教程
  3. 使用 cglib_java动态代理(JDK和CGLIB原理解析与使用)
  4. php+redis+设置前缀,spring使用Redis自定义前缀后缀名(去掉SimpleKey []+自定义)
  5. matlab 求向量的交集_从零开始的matlab学习笔记——(16)函数绘图
  6. 宝塔面板如何部署Java项目教程【新版】
  7. Appium自动化测试-iOS
  8. WEB安全——文件上传
  9. 手把手教您编写第一个单片机程序
  10. 运维工程师面试题及答案(网络运维工程师面试题)
  11. 【总结】计算机网络常用协议总结------结合cpri
  12. 交换机解决电脑IP地址冲突
  13. 初学JAVA GUI
  14. C# NModbus4 TCP 主从站通信样例
  15. 翻过这座山之自定义mybatis框架
  16. GRPC的四种数据流以及案例
  17. 信号与系统_系统频率响应
  18. go语言ORM框架ent使用教程
  19. c++ abs 取绝对值函数
  20. BOJ1293 小马过河 dp

热门文章

  1. MySQL - MySQL不同存储引擎下索引的实现
  2. 白话Elasticsearch39-深入聚合数据分析之案例实战_搜索+聚合: 统计指定品牌下每个颜色的销量
  3. 二、八、十、十六进制及小数间的转换
  4. python 包管理工具poetry
  5. 机器学习:论相关(一)
  6. php disable classes,PHP安全配置基础教程(3)
  7. js 判断变量是否有值返回bool_有没有办法可以获得javascript函数返回值里的bool值,代码如下:...
  8. 开关磁阻电机调速控制的仿真研究
  9. 3-1 Point类的构造函数_JAVA
  10. 第十天2017/04/21(3、泛型编程:STL)