JS烧脑面试题奖励
2、1
分析
首先基本类型数据是传值的,所以在执行B函数时,B的参数A收到的值是1,相当于函数内部的变量。当这个作用域中存在与上一级作用域同名的变量时,上一级变量是无法访问的,所以无论A在函数中如何修改,都不会影响上一级,所以函数内部打印的A是2,外部打印的A仍然是1。
回答
报告错误
分析
为一个函数的多个参数设置默认值,其实和顺序定义变量是一样的,所以会有一个临时死区的问题,就是前面定义的变量不能引用后面没有定义的变量,但是后者可以访问前面的。
回答
10、20
分析
回答
未定义、{n: 2}
分析
很抱歉我的无能,但我在这个问题上一错再错。
无论如何,根据互联网上的大多数解释,因为。运算符具有最高优先级,a.x将首先执行。这时A和b***一起指向的{n: 1}就变成了{n: 1,x: undefined},然后代码会按照串接操作从右向左执行,a.x = an: 2}。因为从一开始就执行了a.x,所以实际上相当于:({n: 1,x: undefined})。x = b.x = a = {n: 2}。
回答
[]
分析
这个问题比较简单,arr[10]=10,所以索引3到9是未定义的,打印出来的arr[3]确实是未定义的。但是,这实际上涉及到ECMAScript版本中不同对应方法行为不同的问题。ES6之前的遍历方法会跳过数组中未赋值的位置,也就是空格,但是增加了ES6。
回答
再见,杰克
分析
回答
NaN、13、NaN、1、1[对象对象]、1 、[对象对象]
分析
这个问题明显是+号的行为:
1.如果一个操作数是字符串,则将另一个操作数转换为字符串以执行串联。
2.如果一个操作数是一个对象,则调用对象的valueOf方法被转换为原始值;如果没有这样的方法或者调用后仍然是非原始值,则调用toString方法。
3.在其他情况下,两个操作数都将被转换为用于加法的数字。
回答
456
分析
对象有两种方法设置和引用属性,obj.name和obj['name'],字符串,数字,变量可以用方括号设置成表达式等。,但最终结果是一个字符串。对于上面的B和C,两者都是对象,所以会调用toString()方法将其转换成字符串,这与数组不同,与内容无关。结果是[object Obejct]。
回答
25、20、20、25
分析
这个问题考查了这一点所指向的问题:
1.逗号运算符会返回表达式中的最后一个值,这里是inner.func对应的函数,注意函数本身,然后执行函数,这个函数不是通过对象的方法调用的,而是在全局环境中调用的,所以这个指向窗口,打印出来的当然是窗口下的out。
2.这显然是由对象的方法调用的,所以这指向对象。
3.加个括号看起来有点混乱,但实际上(inner.func)和inner.func是完全相等的,所以还是作为一个对象的方法来调用。
4.赋值表达式类似于逗号表达式,都是返回值本身,所以也是相对于全局环境中的调用函数。
回答
1、2、3
分析
此题考查变量解构与赋值问题。数组解构和赋值对应位置,而对象和变量、属性同名,顺序任意。
回答
[4, 5, 3]
分析
你从来没有用赋值方法合并过数组吗?assign方法可用于处理数组,但数组将被视为一个对象。例如,目标数组将被视为属性为0、1和2的对象,因此源数组的属性0和1的值将覆盖目标对象的值。
回答
四
分析
这个问题考察了自增运算符的前缀版本和后缀版本,以及switch的语法。自增运算符的后缀版本只会在语句求值后出现,所以X仍然会匹配值为1的case分支,所以很明显匹配到1的分支。这时x++生效,X变成2,然后执行++x,变成3。因为没有break语句,所以
回答
真实、真实
分析
2.typeof使用函数时返回' function ',class只是es6添加的新语法糖,本质上是函数,所以两者是相等的。
回答
真、假
分析
1.没什么好说的。对于数值类型,typeof返回“$ number”。
2.这个问题考察的是运算符的优先级,符合逻辑!的优先级高于同余= =,所以先执行!!Typeof count,结果为真,然后执行true === 'number ',结果当然为假。可以点击这里查看优先级列表:点击我[1]。
回答
2、2
分析
回答
1
分析
这个问题考察的是范围的问题。作用域实际上是一组寻找变量的规则。每个函数在执行的时候都会创建一个执行上下文,这个执行上下文会关联一个变量对象,也就是它的作用域,这个作用域存储了函数可以访问的所有变量。此外,当上下文中的代码被执行时,它将创建一个范围链。如果在当前范围内没有找到标识符,它将继续沿着外部范围搜索。上到顶层全局作用域,因为js是词法作用域,所以在代码编写阶段就已经确定了作用域,换句话说,是在函数定义的时候确定的,而不是在执行的时候,所以函数A是在全局作用域中定义的。虽然它在函数B中被调用,但它只能访问全局范围,而不能访问函数B的范围..
回答
不明确的
分析
这个问题考察的是这个的指向问题。执行arrow函数时,上下文不会绑定this,所以其中的this依赖于this的外层。当执行函数时,外层是全局作用域,因此它指向窗口。窗口对象下没有name属性,所以是未定义的。
回答
{a: {b: 1}}
分析
这个问题很简单,因为assign方法执行的是浅拷贝,所以源对象的A属性会直接覆盖目标对象的A属性。
回答
未定义、1、2
分析
回答
不明确的
分析
回答
打印出arr数组本身
分析
函数是作为一个对象的方法调用的,这个指向对象,数组显然是对象,但是我们都习惯了对象引用属性的方法:obj.fn,但其实obj['fn']引用也是可以的。
回答
1,b函数本身,b函数本身
分析
2.和第一个问题类似,只是B没有赋值操作,那么执行这两行就相当于没有操作,B当然是函数。
回答
2、4、1、1、2、3、3
分析
1.执行Foo函数的静态方法,打印出2。
2.执行getName。当前的getName是打印出4的函数。
3.执行Foo函数,修改全局变量getName,赋给一个打印1的函数,然后返回这个。因为它是在全局环境中执行的,所以它指向窗口,并且因为getName已经被修改,所以它打印1。
4.因为getName没有被重新赋值,所以重新执行后仍然打印出1。
5.new运算符是用来调用函数的,所以new Foo.getName()等价于new (Foo.getName)(),所以new是Foo的静态方法getName,打印2。
6.因为点运算符(。)与new具有相同的优先级,它是从左向右执行的,相当于(new Foo())。getName()。在Foo上调用new将返回一个新创建的对象,然后执行该对象的getName方法。对象本身没有这个方法,所以会从Foo的原型对象中搜索并找到,所以会打印出3。
7.和上一个问题一样,点运算符(。)和new的优先级一样,new是用来调用函数的,所以new new Foo()。getName()等效于new ((new Foo())。getName)(),而括号里的是前面的问题,所以Foo原型上的方法终于找到了,不管是直接调用还是通过new。
回答
是马修,来自英国
我是鲍勃,来自英国
分析
Object.create方法会创建一个对象,并将其__proto__属性指向传入对象,于是p1和p2的原型对象指向同一个对象,然后给p1添加一个name属性,再调用p1的setCountry方法,后者本身没有这样的方法。所以它会沿着原型链搜索,在它的原型,也就是person对象上找到这个方法。执行此方法将为address对象的country属性设置传入的值。p1本身没有address属性,但是和name属性不同的是,address属性是在prototype对象上找到的,而且因为是引用值,因此,它的country属性会被成功修改,然后对p2的操作也是一样的。然后,因为原型中的引用值将被所有实例共享,所以p1和p2引用的地址也是同一个对象。如果修改了一个实例,就会反映到所有实例中,所以p2的修改会覆盖p1的修改,国家的最终值会是英格兰。
回答
2、3、5、4、1
分析
这道题明显是考察事件周期的知识点。
Js是单线程语言,但是为了在不阻塞代码的情况下执行一些异步任务,避免在等待期间浪费资源,js有一个事件循环机制。单线程是指执行js的线程,称为主线程,还有网络请求线程、定时器等其他线程。当主线程运行时,它会生成一个执行堆栈,如果堆栈中的代码调用异步api,它会将事件添加到事件队列中。只要异步任务有结果,就会把相应的回调放到任务队列中。当执行堆栈中的代码被执行时,它将读取任务队列中的任务,并将其放入主线程中执行。当执行栈为空时,会再次检查,以此类推,也就是所谓的事件循环。
异步任务分为宏任务(如setTimeout、setInterval)和微任务(如promise),它们会分别进入不同的队列。当执行堆栈为空时,将首先检查微任务队列。如果有微任务,所有的微任务会一次性执行,然后在宏任务队列中检查。如果有,就拿出一个任务给主线程执行,执行完之后再检查微任务队列,以此类推。
回到这个问题,首先,整个代码作为一个宏任务开始执行。当它遇到setTimeout时,相应的回调会进入宏任务队列,然后是promise。承诺的回调是同步代码,所以会打印出2,在for循环结束后会调用resolve,所以then的回调会放在微任务队列中,然后打印出3,最后打印出5。此时,当前执行堆栈将为空。然后先检查微任务队列找到一个任务,再取出来放到主线程中执行,打印出4。最后检查宏任务队列,把定时器的回调放到主线程中执行,打印出1。
回答
1、7、6、8、2、4、9、11、3、10、5、12