00:00
好,我是上硅谷H5学科的熊健,在程序员节日到来之际呢,我给大家分享一道面试题,来,我们来看题目。题目呢是一个JS的一个综合面试题,它呢考点非常多,我们来一个看啊,首先来读一下题目,它呢定义了一个函数叫fo函数,里面有些代码我们来看啊,然后接着呢,再给这个函数啊添加了一个方法叫做get name值为这个。那又给fo的显示圆形上也添加了一个方法,叫做这个方法二是三好,接着呢,下面这两个来看啊,它们在全局中啊,定义那个变量,它的值呢,是一个方法变量名叫get name,也说明那个函数,哎,它也是get name,值呢不太一样。好了,那最后呢,我们就要去想办法去求出啊以下这些输出结果。那么大家可以先思考一下,最终这个输出结果呢,是不是?
01:04
正确的。好,那我们呢,接下来呢,就来去揭晓答案,来看一看到底这个过程中发生了什么,以及啊,这下面到底输出的值又是多少呢?我们来一个个看啊,首先呢,我们要做这个题目之前啊,我们得去做一个事,咱们这变量和函数呢,它存在一个我们称之为变量提升和函数提升的,所以说啊,在真正的代码执行的过程中呢,我们会发现这些函外关键字声明的变量呢,它会被提升上去,以及用方可省关键字声明的这个函数呢,它也会被提升,那我们就来写一下这个提升最后变成的代码是怎么样的。我们先把原代码给注释一份来,复制一份来过来。我们来看啊,首先呢,遇到方式关键字的呢,它会将这个代码呢进行整体提升啊,假设上面呢,就是我提升的代码,哎,这一块呢,就是提升代码好,那么接下来呢,它遇到哇关键字声明的变量,会将这个变量啊进行提升,但是注意就是变量的值呢,它并不会动。
02:16
所以说呢,我们可以把它介词为啊,把这个袜袜name呢放到上面啊,下面这个袜子呢,相当于是没了。好,接下来又遇到这个方程,这个函数呢,这个函数呢,是个整体的提升,所以呢,它都放在上面。好,那么做完这些呢,我们会发现这个变量提升跟函数的提升的名字冲突了,那这时候会怎么做呢?诶,它呢,一旦这两个冲突,它呢,会优先考虑保留的是我这个函数的这个值低,所以说呢,上面这个呢,会被忽略掉,忽略掉。好,那么接下来呢,还不够啊,因为当我JS引擎做完变量提升和函数提升的时候啊,那接下来又会去接着向下去执行代码哈,哎,此时啊,它就会来到32行,大家注意32行的话呢,它会给找到一个get name的变量找谁。
03:13
诶,就会来到28行,找到它,将它进行了重新赋值,也就是说啊,最终最终我的这个函数get name变量对应的这个函数呢,并不是这个A5,而是最终的在这下面进行重复值的二,四。哎,这一点很关键,把这一点搞懂了,后面的就不会出错了,后面就后面我们来看。好,接下来来看啊,首先我们来看第一个点name好,它呢就会去找fo这个函数,然后找到这个get name方法,哎,就找到了这个,只有这个能找到好,所以说它最终啊会调用这个函数,输出的值是二。好,接下来呢,再看它呢,会去找到一个全局,找一个get name的方法,诶发现啊,咱们这get name现在已经变成了它了,那调用这个函数呢,会输出。
04:09
四会输出四好,接下来呢,这个可能就比较麻烦了啊,来仔细看它呢,有个这样的关系,Fo函数调用点get name,那这就奇怪了,我到底该执行哪一边呢?哎,这里呢,实际上涉及到一个运算符的一个优先关系,那么呢,点运算符优先级应该是最高的,但是呢,我前面这个函数呢,并不能点运算服器电路,所以说呢,它先实行的是fo这个函数。啊先直线F函数,也就是说意味着啊,它执行的顺序啊,其实是这样的。然后呢,这个fo函数的整体先执行,再去定get name方法。好了,那么当它执行f fo函数啊,就是全局去找到这个f fo函数,找到这个接着执行里面的代码,哎,此时此刻大家注意,那这里面呢,要去定义的一个get name,诶,这个get name有用what去定义吗?
05:10
没有没有的话呢,它呢就会去找这个变量,那么这里面呢,就涉及到变量的查找规则,它呢是沿着作用力链找的。好,那这全局中有哪些作用域呢?我们简化一下啊,我们就不一个画了,我们就考虑函数,首先全局有个作用域,这叫全局作用域,Fo函数呢也有个作用域,叫做fo函数的作用域,好它呢首先会算自生长,自身呢并没有定义这个该内方法,所以说最终啊,它来全局,全局啊去这个变量发现啊,在这个32行是不是找到了。啊找到了,所以说呢,会将这个guess name这个函数啊给重新复制为。所以说啊,当它执行的fo函数的调用之后啊,它最终呢,这个全局的这个s name方法,它就变成了这一个方法。
06:08
就不再是之前的了,那么这里面就注意好,当这个fod函数掉之后啊,它最终返回的值啊是this。那么这里面呢,又涉及到啊,C指向的一个问题。我们会说fo函数的调用呢,实际上呢是window.fo函数的调用,实际上呢,是在window的一个方法通过window去调用的,所以说呢,咱们这这子呢,就指向于当前调用函数的这个对象,也就是这个window。所以说呢,最终的返回值啊,它呢会上window上去找。啊,整个这个值呢。哎,不是啊,整个这个值呢,它是等于window啊,我们写错了,实际上就变成了window.get name这个方法。啊,也就是说最终呢,它会隐蔽成这个。
07:00
好,演变成这个之后呢,它会加括号调用,调用之后呢,我们会去知道啊window呢,它会向全局去找get name,此时全局的get name呢,已经变成了这一个,所以说最终输出的结果啊,是一。啊,这个要特别注意输入一,因为ofo函数调用,它返回的是this,而this指向的是window,所以说这个东西呢,就近似于window.get name掌握的就是当前的这个函数。好,那这个搞懂了之后呢,我们再下下去看这里面呢,他又去调这该内,诶这时候又是调该内,它又是按全局中去找到这个S内方法,然后呢,执行这个函数,所以说这时候啊,它输出的结果呢,也是一。也是一好,那么下面这个就麻烦了啊,稍微麻烦一点,它呢也有个点有new,那到底是做些什么事呢。哎,这里呢,我们也说啊,点的优先级关系是最高的,所以说呢,这里面呢,实际上呢,它是这样执行的。
08:06
先执行的是点。然后再去做这个new函数调用,那么fo.get name最终的结果是多少呢?我们来看点get name是不是来到一个这样的方式啊?所以说呢,最终呢,实际上呢,它是又一个这样的一个函数,用这个函数,然后去产生一个实际对象,那我们知道,当我们new这样函数调用的时候呢,它会去执行这个函数,所以最终的结果呢,会等于输出二。那师说,当然因为六关键字的原因,它还会生成一个实际对象,哎,只不过这实际对象呢,咱们并没用上而已,所以说呢,我们不用考虑它了,不用考虑好这是这一个,这里面呢,大家注意,就是这里面的运算级,运算符的优先级关系,它先执行的是这一个。然后呢,当你去一个函数的时候呢,它会去执行这个函数,哎,其实就是这个括号调用,它会执行这个函数,接着产生实际对象,但是注意就是此时此刻呢,实际对象呢,并没有实际用途,我们并没用,所以说呢,不用去考虑它。
09:13
好,那么接下来下一个题。下个题就麻烦了,哎,他在这里加了个括号。那么这里面就涉及到到底是我这个系执行还是哪个系执行呢?哎,首先呢,我们也说啊,由于都是点优先级的啊,运算符优先级关系最高,但是呢,注意我这个括号呢,并不能点去调用,所以说呢,它呢会先将前面的整体的值先求出来,求出来之后啊再去点get name方法。所以呢,这里面实际上它的做法呢,就是一个函数,然后接着呢,再去点方法。好了,在这里面我们就知道啊,这个newo呢,New关键字呢,它最终会生成一个实际对象,比如说在这里面呢,它实际上就生成一个小写的fo,哎,假设这个就是它实际项,那就点S。
10:09
好了,那么这里面就涉及到一个考点,咱们实例对象上如何去找到对应的属性。那么我们会说实际对象找属性呢,是沿着影视圆形链,也是我们所说的圆形链去查找它呢,首先会上自身的找啊,如果自身找不到的话呢,会沿着这个影视圆心,也就是说下划线下划线pro下划线下划线这个属性就找,如果还找不到的话呢,会接着再去考这个影视原系列影视原形属性,那最终呢,会来到大写object的影视原形属性上。啊,如果没有的话呢,大小object的圆形对象上的已是原属性,那么如果还没有的话呢,就会把返回and find,那么在这里面呢,它的自身属机上呢,我们会发现并没有我们想要的get name方法,但是呢,它的第一层的原型上有也说它的实例对象的已是圆心属性呢,指向其构造函数的显示圆心属性,比如指向其啊构造函数的显示圆心属性,所以说呢,在这里面他找到了get内方法,所以在这里面呢,它输出的值啊是三。
11:20
因为fo.get name呢,最终呢,就会找到当前的这个函数,然后调用它就会输出三。好,最后下面还有一个,那下面这个呢,实际上跟之前这个是比较相近的,它呢相当于我们把它拆解一下啊,它呢相当于是先执行的是new调用去执行这个,其实呢,发现new fo调用之后呢,遇到这个点,所以说再执行这个点s name。在执行点开内,接着呢,最后呢,再去扭这个生成的最终的值,然后去new这个函数调用。好,那么我们来一个看啊,首先UFO同样的,它找到的是这个fo。
12:01
函数。所以呢,它最终都会变成。你有一个函数的方法。然后呢,Fo呢,最终返回值呢,又是那个三。比如说最终呢,它会变成一个这样的样子啊。二楼的职位。三那这个呢,又回到了我们之前的这一个,它呢最终呢会去执行这个函数,也就是说最终输出的值啊,其实就是三这个负数的值,三也会去生成一个实际对象,哎,只不过这个实际对象呢,我们并没用上,所以说呢,我们不去探讨。那么最后呢,我们看啊,最终呢,它输出的结果呢,就是2411233那。那么我们先将这个给注释掉,然后将前面的与最初的这个代码将它打开,这时候我们来看一下结果是不是我们所说的241233打开。
13:03
二。四。一。1233,哎没有问题,比如说最终啊,我们的答案呢,是没有问题的,那我们回过头来再来看一下,咱们呢,整个这个面试题呢,它考点有很多啊,所以说我们来看第一个呢,就考的其实我们的变量提升和函数提升,那这一块呢,我们要知道。变量提升呢,只是变量声明的提升,它呢值呢默认是按find,而函数呢是整体的提升,嗯,到我们这还要注意就是变量和函数如果冲突的话呢,它只会保留函数的定义。那么在这里面呢,就涉及到最终啊,这个get name的值啊,它就不一样。那么第二个呢,就是考的Z次指向的问题,它呢Z呢,如果是直接调用的话呢,实际上它就是通过window d fo去调用,那它这个Z呢,就指向当前调用着。
14:02
这个对象就是window。好,那么第三个呢,它又考了咱们变量的一个查找规则啊,变量查找规则呢,就是这在fo里面呢,执行了这个东西。那么变量查找规则呢,它是沿着作用域链去查找的啊,首先在当前作用域找,如果找到呢就做,如果没找到呢,会上向上涨啊,最终呢,会来到全局上,然后修改全局的相关一些代码。好,然后呢,第四个呢,就考着一些。预算符的一些优先级,优先级关系,比如说呢,当你遇到点的时候呢,点的优先级啊,它是最高的最高的,但是这里要注意就是如果前面是个括号的话呢,它是没办法直接运算的,所以说它会将前面这一块整体呢进行运算。好,那么最后一个呢,就是考的一些实例对象查找属性的一些规则,像o.get啊,它会去上影视,也就是我们所说圆形列啊,也叫隐式圆形列,上这个圆形列上找,最终呢,它在啊我构造函数的显示圆形属性上找到了我对应的这个该name方法,从而去执行。
15:15
好,那么以上呢,就是咱们这个面试题的解析。
我来说两句