为了账号安全,请及时绑定邮箱和手机立即绑定

一起扫荡javascript(五)——浅谈javascript的上下文

标签:
JavaScript

    相信很多小伙伴们刚入门时,踩过不少js中的this的坑。嗯,我这样写明明是对的,咋打印出来的值是undefined?我要获取这个,但是这个就是没被我获取到,好坑啊,好纠结啊。。。那到底是怎么一回事呢?为什么js要搞一个这样的东西出来?考验我们吗?你没那么重要,那是因为什么?我们一起来看看吧。

    js上下文是一种工具,一种快速访问到当前程序作用对象的工具。说this之前,我们先来了解下js中变量存储的环境,我们经常说的作用域链,指的呢就是当程序需要访问某一个变量时,它会先从当下的局域中找,找不到的话,从父作用域找,一直到global对象结束,浏览器端从window对象结束,那什么是他的父作用域?简单来说就是以函数为界,js在ES6块级作用域出来之前都是以function为界来区分局部作用域,如果说你是一个闭包,那父作用域就是包裹在外面的那个函数,一直到最终的window对象或global对象,如果这些都找不到,程序则会报空指针。

    我们在操作变量的时候,很多时候会遇到这样的情况,我想在一个闭包里取到父对象中的某个值,或者说,在A方法中调用B方法,

    比如下面这样,如果直接这样写会直接报a未定义,因为a在b函数中没有,在外部的全局作用域中也没有,a是作为hello的一个属性存在。

https://img1.sycdn.imooc.com//5c2a12e300014ac405180306.jpg

那我还是想在b中调这个方法啊,怎么办啊?简单,这样写:

https://img1.sycdn.imooc.com//5c2a1374000158e905750305.jpg

    但这样就跟css父标签写了color : #fff,子标签还是写了一个color : #fff一样,虽说没有影响展示的结果,但是非常影响程序可维护性,假如说你要改一下hello的名字,那你还得下面有hello一个个的改,想死。另外一个问题就是随着程序变复杂,一级级的原型,整条链条会变得很复杂,引用之间会变得不明朗,可能连你都不知道要变到哪,而这时候js就提供了一个非常便捷的方式——this,传递一个隐式的对象引用让代码变得更加简洁和复用。

就像这样:

https://img1.sycdn.imooc.com//5c2a145300010d9405640320.jpg

    其实this,我个人的理解,它就一个作用,获取当前程序的焦点并返回它所处的环境。这个作用非常强大,因为程序说到底,就是开一个进程,分配点内存,给它去不断的直接或间接操作内存。取值,指针偏移。

    this提供了很强大的作用的同时,也给了我们程序员特别是刚入门的有一些困惑,比如说这样:

https://img1.sycdn.imooc.com//5c2a18ac0001ce4704230244.jpg

    你觉得会输出什么,按道理来说,children()不是在parent()里面运行的啊,找a的值不应该先找parent()里的a吗,能找到啊,为啥结果是2?

    这里呢,首先我们需要要知道的是,js里的函数,它实际上是开辟的某个函数池,是在声明的时候就已经定义好了的,所以很多时候你先写函数后写函数都没有关系,因为解释器解释之初这些东西会先被提前声明,函数在被调用时,才会从函数池里暂时取出来,放到被调用的那个环境中,执行完后又回到函数池中,而js引擎干的一件事仅仅是将指针指向这个函数池中的某个函数。所以呢,看起来children是写在parent里,但是this是绑定到parent的父作用域,那就是window对象。

    这样children在window作用域执行,那this肯定是window啊。说到这,在严格模式下,this的顶层指向不是window,而是underfined,那我们可以试试看看这样改:

https://img1.sycdn.imooc.com//5c2a1ac60001dcb104570270.jpg

    你会发现程序报错了,children未定义,因为undefined下没有children这个属性,证明所言非虚。

    如果你还是有些困惑的话,我们再来看下面这个:

https://img1.sycdn.imooc.com//5c2a1dcd0001dc7d05550328.jpg

    你说会打印什么?

        按道理来说,objParent里面的fn引用了obj里的函数,不应该打印的是obj里面的a吗?怎么打印的是objParent里面的a?好奇怪的,对吧?其实就像上面说的一样,函数池,obj里的fn其实也只是一个索引,指向了函数池里的fn。

    我们一起来分析下,objParent里的fn赋值了换一个obj.fn,由于obj.fn也是一个索引,还会继续往上找,直到找到定义时的function fn,这时候其实就跟objParent去调用fn没有区别了,fn在运行时是位于objParent,所以this指向的是objParent,这就是为什么说函数的上下文是根据调用不同而不同的缘故。

    其实,说函数池是不准确的,甚至说是错误的,但相信这种函数池用时取出,不用时放回的方式你会比较好理解一些。

    好了,上面的this主要讲了隐私绑定跟动态绑定,其实this啊,还有很多其他的关注点,比如说回调this丢失,ES6的箭头函数没有this,没有原型...这里呢,要展开的话会很多,我们就暂且这样。

    
















点击查看更多内容
3人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消