美文网首页
少侠,这可能是目前为止关于this最好的文章~

少侠,这可能是目前为止关于this最好的文章~

作者: 天辰dreamer | 来源:发表于2020-02-10 16:08 被阅读0次
    image

    少侠们好~

    一段时间没见了,

    看见标题,你应该知道了这次我们的主要内容是什么。

    而且,你或许会以为我是一个标题党,

    点进来是想吐槽我,

    但这次我要告诉你,

    不是。

    我确实认为这会是目前为止关于this最好的文章。

    为什么我要这么说?

    因为迷之自信!

    关于this关键字的文章已经有很多了,少侠你可能也看过不少了,

    那么少侠请让我先来归个类,然后你用最近看的文章对号入座试试,

    不出意外,大概应该有这么几种类型的文章:

    1、分门别类细致耐心型

    这种类型的特点就是,会比较详细的给你列出各种可能遇见this的情况,告诉你每种情况的答案,

    比如:

    “作为函数调用。。。balabala”

    “作为对象方法调用。。。balabala”

    “new关键字调用。。。balabala”

    。。。。

    当然,

    如果列出的例子够详细,各种this的情况可能也不太能难住你。

    一个广场舞大妈曾告诉我,如果她跳的足够快,她的孤独就追不上她;一位拾荒大叔曾经告诉我,如果他翻垃圾翻得足够仔细,便能找回丢失的自己;一位环卫工阿姨曾经告诉我,她每天都扫这两条街,七年了,都没扫干净心中的瑕疵;一位碰瓷的大爷曾经告诉我,只要他演的够逼真,就能骗过匆匆流逝的时光.....

    2、简单粗暴不想废话型

    和第一种类型相反,这种类型的特点是一般会有一个比较简短的总结,然后通常让你记住这种特点就行了,不想过多纠结各种例子。

    比如:

    “this 永远指向最后调用它的那个对象。。。。。。balabala”

    “this是你调用一个函数时的上下文context。。。balabala”

    “。。。”

    “来,给我重复这句话3遍。。。记住了没? 好,记住了你就可以关掉这篇文章了!”

    3、小黄书优秀阅读者型

    这种类型的特点一般是作者看过《你不知道的JavaScript》书中关于this的讲解,所以通常会给你一些看着逼格比较高的术语,
    牌面看着比之前的要稍微高一些,

    比如:

    “隐式绑定。。。balabala”

    “显式绑定。。。balabala”

    “硬绑定。。。balabala”

    “。。。”

    哼,有了这本秘籍,这次一定要好好装一次逼!


    OK, 总结完毕!

    不出意外,少侠你看过的文章,基本应该属于这3种情况之一,

    那么,

    有的少侠可能要说了,

    “没错,都挺好啊,有什么问题吗?难道你这篇文章还能有什么不一样?”

    对于这种情况,

    我要说的是,

    当然不一样!比如标题看起来就要嚣张一些!

    好吧,其实刚才这几种类型的文章,确实也有很多不错的地方,一些想法也很优秀。

    但是,

    他们也忽略掉了一些问题,

    比如:

    1、为什么会有this?

    2、当我们使用this时,我们到底是想做什么?

    3、this的重要性有多大?

    4、能不能直接避免使用this?

    5、使用this有哪些隐患和注意事项?

    换句话说,

    由于过于关注了this本身的一些用法和特点,

    便不太容易从this之外的角度来看待它。

    就好比下棋一样,也许少侠你棋下得已经很好了,但是和看棋的人相比,角度肯定不一样。

    而今天,

    少侠我们要做的就是,当一个看棋者。


    为了弄清楚为什么会有this,

    我们首先要聊的,

    是对象和函数,

    对象可以看做是个简单容器,通常来说,你会使用对象储存一些数据

    image

    比如这里,我们使用一个对象储存了一个角色信息,一个叫做天辰dreamer的name信息,和一个叫做pets的数组,用来保存宠物信息。

    而函数的话,你通常会用它来执行一些操作,

    比如获取上面的用户名称,或者添加,删除一些宠物等等。

    image

    现在对象有了,函数也有了,我们就可以结合起来使用一下,用 addPets 向 user 中添加一个宠物:

    image

    好了,我们使用 addPets 成功向 user 中添加了一个宠物,也通过 getName 函数访问到了 user 的 name。

    但是,大多数情况下,如果 getName 和 addPets 函数都是和 user 相关的,

    少侠你可能会倾向于把他们放在一块儿:

    image

    我们把 getName 和 addPets 放在了 user 内部,作为了它的方法。

    并且经过我们测试,结果也是正常的,

    所以没有问题了吧?

    如果少侠你只是这样使用的话,确实没有问题,

    但是,假如你现在想增加一个新角色,除了名字,其他都一样,你可能会怎么做呢?

    你肯定不想全部都重新写一遍,因为只有名字不一样,所以你想直接复制一份user,然后改变一下name信息。

    image

    这个时候,看似好像已经成功复制了一份user,

    甚至如果少侠你打印一下user2,你也会看见它的name属性是'胖虎dreamer',

    那么问题会出现在哪呢?

    问题出现在当你使用user2上面的方法时:

    image

    造成这个情况的原因是,我们在user中getName函数内部,是在通过作用域访问user:

    image

    addPets方法也是一样,也就是说,如果我们调用user2.getPets,里面还是指向的user,

    也就是说,实际上会把宠物添加到user里面去,

    少侠你肯定不希望自己买的东西,被发送到别人家吧?

    要解决这个问题也行,比如改为每次调用方法时我们都手动传递一个user进去:

    image

    这样的话,倒是勉强能用,但某些少侠可能会说:

    “喂,天辰你傻了吧? 那照你这样,我还不如直接弄两个函数,然后传递不同的对象就行了,我都放一起了,完了还是得我手动告诉它们?”

    “对啊对啊,那我还能这样使用呢,调用 user1 的方法,但是传递user2进去,不仅如此,我还能一会儿传递user,一会儿又传递user2,怎么样
    ?怎么样?”

    image

    [图片上传失败...(image-63c6ae-1581322063794)]

    没错,作为一个 dreamer,肯定不能采用这么 low 的方式!

    所以,我们现在有点纠结,

    如果getName采用作用域的方式的话,那么它总是会访问最开始定义时的对象,

    如果getName采用动态传递对象的话,那么就得每次我们手动传递。

    更矛盾的是,既然我每次都得手动传递的话,我又干嘛要把函数放在某个对象里面呢?

    所以我们想要的是什么呢?

    我们想要的是,

    getName既能动态的切换访问的对象,也不需要每次手动指定。

    比如说我在user上调用它,它就访问user,而我在user2上调用它,它就访问user2.

    换句话说,一次定义,到处使用。

    有办法吗?

    有!

    这就是我们今天的主角,this,需要做的事。

    image

    beng ~,

    神奇的事情发生了~

    当我们在 user上面调用 getName时,getName 内部的 this 指向了 user ,

    而当我们在 user2 内部调用时,getName 内部的 this 又神奇的指向了 user2 ,

    如果我们需要的话,我们也可以再复制一份user3:

    image

    还是一样的效果,

    甚至我们也可以单独把 getName 放在外面:

    image

    好了,现在少侠你知道了为什么需要 this 了吧?

    也知道了为什么会动态的变来变去了吧?

    那么,如果直接调用带有 this 的函数会是什么情况呢?

    比如:

    image

    getThis 的结果会是什么呢?

    现在我们已经的是,

    假如把 getThis 放在 user上,然后通过 user 调用,它会是 user, 如果通过 user2 调用,它会是 user 2,但是这里既没有 通过 user调用,也没有通过 user2 调用,那么结果应该是什么呢?

    在查找答案之前,我们可以先假设2种情况,

    1、既然它没有显式的通过对象调用,我们给这种单独调用的情况,默认通过一个对象来调用,比如全局对象,window 等等。

    这样 this 就会是 window对象。

    2、既然它没有显式地通过对象调用 getThis,那么就当做找不到对象好了。

    这样的话,this 就是 undefined

    少侠你认为哪一种是对的呢?

    答案是两种都对,它们都是 JavaScript 目前的处理方式,只不过,一个是普通模式,一个是严格模式:

    image

    好了,少侠,

    这就是 关于 this 的故事了,

    1. 你通过哪个对象调用带有 this 的函数,它里面的 this 就指向谁。
    2. 如果没有通过任何对象调用,this 就会是全局对象或是 undefined。
    3. 之所以会有这么奇怪的现象,是因为只有这样,你才能在不同对象之间复用方法函数和数据。
    4. 如果你希望在一开始就确定访问哪个对象的话,你应该使用词法作用域。

    如果之前的 this 让少侠你感到奇怪的话,现在你应该理解它了,它实际上是和词法作用域相互补充的。

    根本没有什么奇怪的地方,那就是 this 自己想要做的。


    关于 this 的陷阱(part 1):

    1、不要直接传递一个对象方法给回调函数,因为你不知道它会怎么调用这个函数。

    比如它万一把你的函数放在另外一个对象上再调用呢?

    (通常不会这么奇怪,但就算直接调用,由于没有通过对象调用,所以结果会和上面一样)

    image

    所以,把带有 this 的函数直接当做回调函数时,你没办法确定它会被怎么调用,所以,里面的 this 也是不能确定的,

    其中一种解决办法是,用一个外部函数包裹它,然后在这个函数内部,显式调用它:

    image

    当然,

    通过 bind 之类的方式也可以完成,

    不过,由于这里我们还没有遇见它,

    所以就先不考虑它了~

    2、还记得数组也是对象吗?所以下面的情况也是成立的~

    image

    3、箭头函数没有自己的 this

    上面的规则只适用于普通函数, ES6 新增加的箭头函数没有自己的 this,它会使用外部最近的一个普通函数的 this,一直往上找,如果一直没有普通函数,最后会是全局对象。

    image

    少侠你可以看到, getUser2 是一个箭头函数,所以它会找寻外部最近的一个普通函数的 this, 而它外部最近的一个普通函数是 getUser ,所以它会使用 getUser 内部的 this,

    假如外部没有普通函数函数:

    image

    user 就在全局环境下,而 getUser 外部再没有其他函数了,所以就会访问到全局对象 window。

    有没有觉得挺奇怪?

    别急,以后你就会明白了~


    完全OK~

    恭喜少侠你又成功发现并阅读完了一篇文章,

    希望它能够对你有所帮助,

    然后,

    我们还有一些开始的问题还没有回答,也有一些内容没有说到,

    比如 new 关键字,call, apply, bind,

    或者再进一步的原型链,class 等等~

    实际上,简单聊一下它们不会花费太多的时间,

    但是,关于它们,其实还有很多更有趣的东西,

    所以,

    江湖路远,下次有缘再见了,少侠~


    一些你可能关心的问题:

    1、开头花里胡哨的,结果5个问题就回答了一个,哼,标题党,是不是太敷衍了?

    主要是发现全部一次写完的话,确实会很长很长,虽然有些东西是长一点比较好,但是文章就还是短一些吧。。。

    2、对,还有,你开头举的几个例子是什么意思?瞧不起我们吗!!!

    没有没有,主要是想夸你们,夸你们性格细致有耐心,单纯直接没有心机,并且热爱学习爱看书,对,反正都是夸奖~

    3、为什么箭头函数不单纯当做普通函数的简写呢? 为什么要格外改变内部的 this 指向呢? 显得好奇怪,有什么实际的用途吗?

    我就知道你们一些人虽然知道箭头函数 this 指向不太对,但是可能不太清楚为什么要这样做,

    这样的特性在某些地方确实有特殊用途,能帮助避开一些坑,不过这里就先不说了,哈哈哈哈哈哈~

    4、call,apply 这些不说吗?还有 new 关键字呢? 原型链呢?

    这些以后都会提到的,但顺序可能会和少侠你预想的不一样,

    少侠你可能以为顺序会是,call,apply,bind,new 关键字,原型链。。。balabala。。。

    不过,

    要不我们试试反过来看怎么样?


    声明:本文仅限于潇洒有趣又很酷的天辰dreamer装逼使用,未经允许,禁止以任何形式转载~

    image

    相关文章

      网友评论

          本文标题:少侠,这可能是目前为止关于this最好的文章~

          本文链接:https://www.haomeiwen.com/subject/ulgaxhtx.html