资讯专栏INFORMATION COLUMN

每日前端进阶第一题:如何正确判断this的指向?

Miyang / 2153人阅读

摘要:作者陈大鱼头链接背景最近高级前端工程师刘小夕在上开了个每个工作日布一个前端相关题的,怀着学习的心态我也参与其中,以下为我的回答,如果有不对的地方,非常欢迎各位指出。当一个函数用作构造函数时使用关键字,它的被绑定到正在构造的新对象。


作者:陈大鱼头

github: KRISACHAN

链接:github.com/YvetteLau/S…

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

今天我们分享的是第一题:如何正确判断this的指向?

例子
<script>
    // 浏览器正常情况下
    console.log(this === window) // true
script>
<script>
    // 函数调用
    a = 10;
    function fn1 () {
        console.log(this.a)
    }
    fn1() // 10

    b = 2
    console.log(this.b) //2
    function fn2 () {
        this.b = 3
    }
    fn2()
    console.log(this.b) // 3
script>
<script>
    // 方法调用
    function test () {
        console.log(this.x)
    }
    x = 2
    var o = {}
    o.x = 1
    o.m = test
    o.m() // 1
script>
<script>
    // 构造函数调用
    x = 2
    function test () {
        this.x = 1
    }
    var o = new test()
    console.log(x) // 2
script>
<script>
    // apply调用
    x = 0
    function test () {
        console.log(this.x)
    }
    var o = {}
    o.x = 1
    o.m = test
    o.m.apply(o) // 1
script>
<script>
    // 函数 apply调用
    var zz = {};
    zz.a = 1000;

    a = 10;
    function fn1 () {
        console.log(this.a)
    }
    fn1.apply(zz) // 1000

    b = 2
    console.log(this.b) //2
    function 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>
    // forEach
    var 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() // undefined
    fn1.apply(k) // {a: 1, b: 2, c: 3}
    k.m = fn1
    k.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() // window
    fn2.apply(o) // window
    o.m = fn2
    o.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() // window
    oo.d.apply(ooo) // {a: 1, b: 2, c: 3}
    oo.e.apply(ooo) // window

    var xxx = oo.d
    var yyy = oo.e

    xxx() // undefined
    yyy() // window
script>
<script>
    "use strict"
    // forEach
    var 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下的情况也类似。 其实法则总结起来就是下面几点:

    无论是否在严格模式下,在全局执行环境中(在任何函数体外部) this 都指向全局对象。

    简单函数调用, this 在一般模式下指向全局对象;严格模式下 this 默认为 ndefined

    call , bind, apply在非箭头函数下修改 this 值;箭头函数下无法修改(由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数),不管call , bind, apply多少次,函数的 this 永远由第一次的决定。

    当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。

    如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。

    当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

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

    设置 envRecGetThisEnvironment()

    返回 envRec.GetThisBinding()

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

    设置 lex 为​​正在运行的执行上下文的 LexicalEnvironment

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

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



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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/6906.html

相关文章

  • 前端知识点(二)

    摘要:在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行时。 1、元素上下垂直居中的方式有哪些? 元素水平垂直居中的方式有哪些? absolute加margin方案 fixed 加 margin 方案 display:table 方案 行内元素line-height方案 flex 弹性布局方案 transform 未知元素宽高解决方案 absolute加mar...

    zacklee 评论0 收藏0
  • 前端知识点(二)

    摘要:在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行时。 1、元素上下垂直居中的方式有哪些? 元素水平垂直居中的方式有哪些? absolute加margin方案 fixed 加 margin 方案 display:table 方案 行内元素line-height方案 flex 弹性布局方案 transform 未知元素宽高解决方案 absolute加mar...

    lbool 评论0 收藏0
  • 前端知识点(二)

    摘要:在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行时。 1、元素上下垂直居中的方式有哪些? 元素水平垂直居中的方式有哪些? absolute加margin方案 fixed 加 margin 方案 display:table 方案 行内元素line-height方案 flex 弹性布局方案 transform 未知元素宽高解决方案 absolute加mar...

    Alex 评论0 收藏0
  • JS每日一题:深拷贝与浅拷贝区别?如何实现一个深拷贝

    摘要:期深拷贝与浅拷贝的区别如何实现一个深拷贝在回答这个问题前,我们先来回顾一下中两大数据类型基本类型引用类型基本类型基本类型就是值类型存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配引用类型引用类型存放在堆内存中的对象,变量实际保 20190311期 深拷贝与浅拷贝的区别?如何实现一个深拷贝 在回答这个问题前,我们先来回顾一下JS中两大数据类型 基本类型 Undefined...

    MiracleWong 评论0 收藏0
  • daily-question-02(前端每日一题02)

    摘要:静态作用域与动态作用域静态作用域函数的作用域基于函数创建的位置。采用的是词法作用域,也称为静态作用域。可以劫持整个对象,并返回一个新的对象。防误触延缓执行立即执行节流所谓节流,就是指连续触发事件但是在秒中只执行一次函数。 在这里记录着每天自己遇到的一道印象深刻的前端问题,以及一道生活中随处可见的小问题。 强迫自己形成积累的习惯,鞭挞自己不断前行,共同学习。 Github 地址 2019...

    lk20150415 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<