#HolyJS18展台hh.ru上的问题分析

我们试图为您做一些有趣而又不寻常的事情。 我真的希望我们成功。 我们不想让您无法回答,也没有解释原因。 让我们做对。


首先,我想提醒您比赛是如何进行的,共进行了4轮有关JS的15个问题,进行了1轮非竞争性的关于React的15个问题,最后10个问题。


图片


根据削减-前4轮任务的分析。


这是我们分析的第二部分。
在这里回答问题


我们都是怎么做到的? 我们决定需要产生大约80-90个问题,以便有可供选择的股票。 之后,我们将所有内容划分为主题:


  • 浏览器事件
  • 各种API(Array,Set,defineProperty等),
  • 专心
  • 使用分数
  • 吊装
  • 事件循环
  • 类型转换
  • 类型
  • 逻辑(具有逻辑AND和OR)

之后,问题被分配了4轮。 我们试图使所有巡回赛的复杂性保持不变,为此,我们进行了多次访问,通过了这些测试,并确定了哪些问题更容易解决,哪些问题更难解决,并用更合适的问题代替了悬而未决的问题。 在每个回合中,我们针对某个特定主题回答了相同数量的问题。 结果,事实证明,在不同的旅行中存在相似但不相同的问题。


因此,对游览进行分类似乎不太方便,因为会有很多重复的解释,我建议您按主题查看。 让我们从最简单的开始。


注意事项:


控制台中将显示什么?


console.log(0,1 + 0,2); a) 0.30000000000000004 b) 0.3 c) 2 d) 0 1 2 

答案+解析

d)0 1 2
此处位于数字之间,而不位于. 如果您格式化这样的问题:
console.log(0, 1 + 0, 2); 一切都会变得清晰


控制台中将显示什么?


 (() => { 'use strict'; a = null + undefined; console.log(a); })(); a) 0 b) NaN c) null d)  

答案+解析

d)错误
a不是作为变量(不是变量声明)创建的,这里有一个隐式的this.a赋值表达式,这通常可能不是您期望的,因为 全局变量window.a将在严格模式下创建,这是禁止的。


控制台中将显示什么?


 let foo = function bar() { return 123; }; console.log( typeof bar() ); a) 'function' b) 'number' c) 'undefined' d)  

答案+解析

d)错误
这是一个函数表达式(表达式)-在这种情况下,函数的名称对于函数而言是本地的。 要调用函数,您需要调用foo而不是bar 。 如果是声明,答案将是number


有关使用分数的问题:


控制台中将显示什么?


 console.log(0.1 ** 2); a) 0.2 b) 0.01 c) 0.010000000000000002 d) NaN 

答案

c)0.010000000000000002


控制台中将显示什么?


 console.log(0.1 + 0.2); a) 0.30000000000000004 b) 0.3 c) 2 d) NaN 

答案+解析

a)0.30000000000000004
** -这是Math.pow平方0.1的类似物-应该为0.01 ,但在JS(与许多其他语言一样)中, 使用浮点数时存在运算准确性的已知问题。 这将是0.010000000000000002这是由于以下事实:在二进制系统中获得了无限大的分数,因为 在JS中,始终为一个数字精确分配64位-所有数字始终为双精度浮点数。 添加时发生相同的事情。


我们转向一些更复杂的问题。


浏览器中的事件:


元素上有一个事件处理程序,该处理程序中的哪些值将始终相同?


 elem.onclick = function(event) { } a) event.target  event.currentTarget b) event.target  this c) event.currentTarget  this d)     

答案+解析

c)event.currentTarget和这个
this -总是指向一个元素
currentTarget事件挂起的元素
target-发生事件的元素


单击div,此代码将输出什么?


 div.onclick = function() { console.log(1) }; div.onclick = function() { console.log(2) }; div.addEventListener('click', function() { console.log(3) }); a) 1 b) 1 3 c) 2 3 d) 3 

答案+解析

c)2 3
onclick将添加console.log(1)处理函数,但是在下一行中,我们使用新功能对其进行了研磨,仅保留console.log(2)onclick是DOM属性;它始终是一个
事件将按照其挂起的顺序工作,将先显示2,然后显示3。
如果我们多次执行addEventListener ,那么它们每个都会工作,因为 处理程序将事件添加到队列中。


有关各种API的问题部分


defineProperty:


此代码将输出什么?


 (() => { const obj = { key: 1 }; Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: false, value: 2 }); console.log(obj.key); obj.key = 3; console.log(obj.key); })(); a) 1, 2 b) 2, 2 c) 2, 3 d)  

答案

b)2、2


此代码将输出什么?


 (() => { 'use strict'; const obj = { key: 1 }; Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: false, value: 2 }); console.log(obj.key); obj.key = 3; console.log(obj.key); })(); a) 1, 2 b) 2, 2 c) 2, 3 d) 2,  

答案

d)2,错误


此代码将输出什么?


 (() => { const obj = { key: 1 }; Object.defineProperty(obj, 'key', { enumerable: false, configurable: false, writable: true, value: 2 }); console.log(obj.key); obj.key = 3; console.log(obj.key); })(); a) 1, 2 b) 2, 2 c) 2, 3 d)  

答案+解析

c)2、3
在上述所有问题中,都会defineProperty方法的知识, definePropertywritable设置。 如果将其设置为false则禁止更改作为第二个参数传递给defineProperty的键的值。 唯一的区别是,如果没有严格模式- use strict严格模式use strict引擎将假装一切正常,但不会更改值,并且在严格模式下会出现错误。


增量:


此代码将输出什么?


 let x = 5; console.log(x++); a) 5 b) 6 c) '5++' d)  

答案

a)5


此代码将输出什么?


 const a = 5; console.log(a++); a) 5 b) 6 c) '5++' d)  

答案

d)错误
当使用后缀形式的incrimination时,该值在增加之前返回。
并在前缀之后,即 console.log(++5)将输出6
const不能被覆盖; Number是基元,当其递增时,该变量将被新值覆盖,并且会出现错误。


设置:


此代码将输出什么?


 const a = [...new Set([1, 1, 2, , 3, , 4, 5, 5])]; console.log(a); a) [1, 1, 2, , 3, , 4, 5, 5] b) [1, 2, undefined, 3, 4, 5] c) [1, 1, 2, undefined, 3, undefined, 4, 5, 5] d)  

答案

b)[1、2,未定义,3、4、5]


此代码将输出什么?


 let set = new Set([10, '10', new Number(10), 1e1, 0xA]); console.log(set.size); a) 5 b) 3 c) 2 d) 1 

答案

b)3


此代码将输出什么?


 let obj = {}; let set = new Set([obj, obj, {}, {}, {...{}}, {...obj}]); console.log(set.size); a) 6 b) 5 c) 2 d) 1 

答案

b)5
Set是一个集合;根据定义,其中不能有相同的值。 问题是如何比较这些值。 原始对象按值进行比较,对象按引用进行比较。
它本身不引用数据类型,可以存储任何类型的值1e10xA将转换为十进制并得到10
而且新对象总是不相等: console.log({} == {})将返回false因为 将在内存的不同位置以新方式创建对象,并且它们的链接将不相等。


此代码将输出什么?


 console.log(Infinity / Infinity); a) NaN b) 1 c) Error d) Infinity 

答案

a)NaN
不可能将无穷大分为无穷大和从无穷大中减去无穷大,因为 从数学的角度来看,获得了不确定性,乘以Infinity并且0错误不会引起数学运算时,会发生相同的事情-将存在NaN


有关点差的问题:


此代码将输出什么?


 const a = { ...{ a: 1, b: 2, c: 3 }, ...{ a: 2, c: 4, d: 8 } }; console.log(a); a) { a: 2, b: 2, c: 4, d: 8 } c) { a: 1, b: 2, c: 3, d: 8 } c) { a: 1, b: 2, c: 3, a: 2, c: 4, d: 8 } d)  

答案

a){a:2,b:2,c:4,d:8}


此代码将输出什么?


 const a = [...[1, 2], ...[[3, 4]], ...[5, 6]]; console.log(a); a) [1, 2, 3, 4, 5, 6] b) [1, 2, [3, 4], 5, 6] c) [[1, 2], [[3, 4]], 5, 6] e)  

答案+解析

b)[1、2,[3、4],5、6]
Spread运算符用于将对象或数组解析为多个部分。 它在...之后从实体获取值,并将其复制到创建的值。 值得注意的是,对于一个数组和一个对象,它打开到1级,即 ...[[1]]将返回包含一个元素的数组,而不是元素本身。 对象中不能有重复的值,因此,以后公开的值将被以前公开的值覆盖。 这可用于指定默认设置。


 const fn = (actualProps) => ({ ...defaultProps, ...actualProps }) 

如果有的话,所有默认值都将被传递的值覆盖。


此代码将输出什么?


 console.log(parseInt(' -10,3   ')); a) -10,3 b) -10 c) TypeError d) NaN 

答案+解析

b)-10
关于MDN的详尽描述:
如果parseInt函数遇到的字符不是指定数字系统中的数字,则它将跳过此字符和所有后续字符(即使它们合适),并返回从该字符之前的字符串部分转换而来的整数。 parseInt切除数字的小数部分。 一行的开头和结尾都可以有空格。


此代码将输出什么?


 const t = { a: 6, b: 7 }; const p = new Proxy(t, { get() { return 12; }, }); console.log(pa); pa = 18; console.log(pa); console.log(ta); a)  b) 12 18 18 c) 12 18 6 d) 12 12 18 e) 6 18 6 

答案+解析

d)12 12 18
Proxy拦截所有对该对象的调用。 在这种情况下,无论我们访问对象的哪个字段,我们都只代理get方法,并且始终返回12 。 在这种情况下,我们不会触摸设置,并且在访问代理时,对象中的值将被替换。


数组:


此代码将输出什么?


 let arr = []; arr[1] = 1; arr[5] = 10; console.log(arr.length); a) 1 b) 5 c) 6 d) 10 

答案

c)6


此代码将输出什么?


 let arr = new Array(3); console.log(arr[1]); a) undefined b) 1 c) 3 d)  

答案+解析

a)未定义
当我们用一个数字参数创建一个Array时,它表示数组的长度。 数组创建为空,所有值均未undefined 。 如果您创建对不存在的数组字段的访问,也会发生同样的事情。 值得注意的是,如果您将数字传递给Array ,则将返回包含此元素的数组,即 Array('a')将返回['a']


逻辑运算&&||==等:


此代码将输出什么?


 console.log([] && 'foo' && undefined && true && false); a) [] b) 'foo' c) undefined d) true 

答案

c)未定义


此代码将输出什么?


 console.log(0 || 1 && 2 || 3); a) 0 b) 1 c) 2 d) 3 

答案

c)2


此代码将输出什么?


 console.log(0 || '' || 2 || undefined || true || false); a) 0 b) false c) 2 d) true 

答案

c)2


此代码将输出什么?


 console.log(2 && '1' && null && undefined && true && false); a) 2 b) false c) undefined d) null 

答案

d)空


此代码将输出什么?


 console.log([] && {} || null && 100 || ''); a) true b) 100 c) '' d) {} 

答案+解析

d){}
空数组[]true空对象{}true
空字符串''nullundefinedfalse
逻辑或|| -返回左操作数,如果为true,则返回右操作数。
逻辑&& -返回左操作数,如果为false,否则返回右操作数。


有时可以在代码中找到它,在默认参数出现之前,他们经常这样写-如果函数中没有参数,那么我们采用默认参数:


 function f(userParams) { var params = userParams || defaultParams; } 

现在React经常检查条件是否成立,然后我们渲染一些东西:


 { isDivVisible && <div>bla-bla</div> } 

数组比较:


此代码将输出什么?


 const arrayFoo = [1, 2, 3, 4]; const arrayBaz = [1, 2, 3, 4]; console.log(arrayFoo == arrayBaz && arrayFoo == arrayBaz); a) false b) true c) undefined d)  

答案

a)错误


此代码将输出什么?


 console.log([null, 0, -0].map(x => 0 <= x)); a) [false, true, false] b) [false, true, true] c) [false, false, false] d) [true, true, true] 

答案

d)[正确,正确,正确]


此代码将输出什么?


 const arrayFoo = [1, 2, 3, 4]; const arrayBaz = [1, 2, 3, 4]; console.log(arrayFoo >= arrayBaz && arrayFoo <= arrayBaz); a) true b) false c) undefined d)  

答案

a)正确


此代码将输出什么?


 const foo = [1, 2, 3, 4]; const baz = '1,2,3,4'; console.log(foo >= baz && foo <= baz); a) false b) true c) undefined d)   

答案+解析

b)正确
==通过引用进行比较。
在操作>, >=, <, <=操作数转换为基元,并在arrayFoo上调用valueOf方法,该方法应返回基元值arrayFoo ,但它返回对同一数组的引用。 接下来,通过调用toString方法进行到原始值的转换,该方法将以“ 1,2,3,4”的形式返回数组的字符串表示形式,在字典上比较两个数组并返回true


此代码将输出什么?


 console.log(+0 == -0); console.log(+0 === -0); console.log(Object.is(+0, -0)); a) true, false, false b) true, true, false c) false, true, true d) false, false. false 

答案+解析

b)正确,正确,错误
MDN的综合说明:
此方法的行为(谈论Object.is )与===运算符不同。 运算符=== (以及运算符== )认为数值-0+0相等,并且值Number.NaN不等Number.NaN自身。


有关吊装的问题:


此代码将输出什么?


 console.log(str); const str = 'HeadHunter'; a) 'HeadHunter' b) undefined c)  

答案

c)错误


此代码将输出什么?


 var arrayFunction = []; for (let i = 0; i <= 10; i++) { arrayFunction.push(() => i); } console.log(arrayFunction[3]()); a) 4 b) 0 c) 11 d) 3 

答案

d)3


此代码将输出什么?


 console.log(str); var str = 'HeadHunter'; a) 'HeadHunter' b) undefined c) null c)   

答案

b)未定义


此代码将输出什么?


 console.log(foo); var foo; foo = foo ? 1 : 0; console.log(foo); a)  b) undefined 0 c) '' 1 d) 0 0 

答案

b)未定义0


函数调用会起作用吗?


 getCompanyName(); function getCompanyName() { return 'HeadHunter'; } a)  b) ,     . c)  

答案

a)是的


此代码将输出什么?


 var arrayFunction = []; for (var i = 0; i <= 10; i++) { arrayFunction.push(() => i); } console.log(arrayFunction[3]()); a) 4 b) 0 c) 11 d) 3 

答案+解析

c)11


弹出函数声明,但没有表达式。
弹出var ,但直到undefined初始化为止。
letconst不会弹出并在块中具有作用域,即 限于{}


为了使循环与var一起正常工作var您需要使用闭包,值将保存在其中。
(这曾经是采访的经典任务,但现在我们可以接受了)


 var arrayFunction = []; for (var i = 0; i <= 10; i++) { (function(i) { arrayFunction.push(() => i); })(i); } console.log(arrayFunction[3]()); 

此代码将输出什么?


 console.log(true + false); a) true b) false c) 1 d) 0 

答案+解析

c)1
所有运算符都不是字符串, +导致数字。 原来是1 + 0


此代码将输出什么?


 console.log([] - 100 + ![]); a) false b) '-100' c) -100 d) NaN 

答案+解析

c)-100
将该数组强制转换为字符串,之后,由于-我们将其强制转换为数字,结果是-100 ,然后将数组强制转换为false ,这是0


此代码将输出什么?


 console.log([[], []] + 1); a) 1 b) '1' c) ',1' d) NaN 

答案+解析

c)',1'
我们在对象上toString ,而toString也将在数组的所有元素上调用。 [].toString将返回一个空字符串'' 。 事实证明, + 1答案,1


此代码将输出什么?


 console.log([] + 100 + 5); a) 105 b) '1005' c) 1005 d) NaN 

答案+解析

b)'1005'
该数组可简化为字符串,然后已经发生串联。


此代码将输出什么?


 console.log(1 + { a: 3 } + '2'); a) 6 b) '1[object Object]2' c) 3 d) NaN 

答案+解析

b)'1 [object Object] 2'
转换为字符串-只是串联而已。


此代码将输出什么?


 console.log(10.toString() + 10 + 0x1); a) '10101' b) 21 c) '10100x1' d)  

答案+解析

d)错误
对于一个数字,一个点. 表示小数部分的开头,我们希望在那里有一个数字-会有错误。
为了使此示例正常工作,您需要编写10..toString()


此代码将输出什么?


 console.log(5 + false - null + true); a) '0true' b) NaN c) 6 d)   

答案+解析

c)6
在这里,一切都减少为一个数字,结果是5 + 0 - 0 + 1


此代码将输出什么?


 console.log(true + NaN + false); a) true b) NaN c) false d) 1 

答案+解析

b)NaN
使用NaN加数字时,我们将所有内容减为一个数字-得到NaN


此代码将输出什么?


 console.log('0x1' + '1' - '1e1'); a) 17 b) 7 c) '0x111e1' d) NaN 

答案+解析

b)7
第一次串联后已经有几行,我们得到: '0x11' - '1e1' 。 由于有符号-我们将所有内容都带到了数字上。
0x11十进制的十六进制数字是17
1e1指数形式与1 * 10 ** 1即 才10


类型:


此代码将输出什么?


 let foo = () => { return null; }; console.log( typeof typeof foo ); a) 'function' b) 'string' c) 'null' d)  

答案

b)“字符串”


此代码将输出什么?


 typeof function() {}.prototype; a) 'function' b) 'object' c) 'undefined' d)  

答案+解析

b)“对象”
typeof总是返回一个字符串,其优先级低于调用该函数的优先级,因此该函数将首先执行,并将typeof应用于返回的结果。 函数对象继承自Function.prototype。 Speck明确确定这是一个对象。


事件循环:


让我们从关于诺言的两个问题开始。


此代码将输出什么?


 Promise.reject() .then(() => console.log(1), () => console.log(2)) .then(() => console.log(3), () => console.log(4)); a) 1 4 b) 1 3 c) 2 3 d) 2 4 

答案

c)2 3


此代码将输出什么?


 Promise.reject('foo') .then(() => Promise.resolve('bar'), () => {}) .then((a) => {console.log(a)}) a) foo b) bar c) undefined d)  

答案+解析

c)未定义
Promise.reject返回处于拒绝状态的承诺。
应该记住, then需要两个参数,即onFulfillonReject回调。 如果在此之前发生错误,那么我们将转到onReject回调。 如果其中没有错误,则接下来是onFulfill 。 并且不要忘记() => {}返回的不是空对象,而是undefined ,为了返回一个空的对象,您应该这样写: () => ({})


任务的顺序。


此代码将输出什么?


 async function get1() { return 1; } function get2() { return 2; } (async () => { console.log(await get1()); })(); console.log(get2()); a) 1,2 b) 2,1 c) 1 d) 2 

答案

b)2.1


此代码将输出什么?


 setTimeout(() => {console.log('in timeout')}); Promise.resolve() .then(() => {console.log('in promise')}); console.log('after'); a) in timeout, in promise, after b) after, in promise, in timeout c) after, in timeout, in promise d) in timeout, after, in promise 

答案

b)在承诺之后,在超时之后


此代码将输出什么?


 let __promise = new Promise((res, rej) => { setTimeout(res, 1000); }); async function test(i) { await __promise; console.log(i); } test(1); test(2); a) 1, 2 b) 2, 1 c) 1 d) 2 

答案

a)1、2


此代码将输出什么?


 console.log('FUS'); setTimeout(() => {console.log('RO')}) Promise.resolve('DAH!').then(x => console.log(x)); a FUS RO DAH! b) FUS DAH! RO c) RO FUS DAH! d) DAH! RO FUS 

答案

b)FUS DAH! 反渗透


此代码将输出什么?


 console.log(1); setTimeout(() => console.log('setTimeout'), 0); console.log(2); Promise.resolve().then(() => console.log('promise1 resolved')); console.log(3); a) 1, 2, 3, 'setTimeout', 'promise1 resolved' b) 1, 'setTimeout', 2, 'promise1 resolved', 3 c) 1, 2, 3, 'promise1 resolved', 'setTimeout' d) 1, 2, 'promise1 resolved', 3, 'setTimeout' 

答案+解析

c)1、2、3,“已解决承诺1”,“ setTimeout”
首先,将触发所有同步调用,然后,当调用堆栈为空时,将调用队列中的内容(异步任务)。 首先,微任务-诺言和mutation observer 。 在当前任务结束时,将执行所有微任务,与此微任务相关联,您可以阻止事件循环,任务完成后,浏览器将呈现。 之后,将执行宏任务-超时。
这是一个非常简化的示例,更详细地说,我建议您看一下Mikhail Bashurov讲话


最后一个问题答应与等待


此代码将输出什么?


 const p = Promise.resolve(); (async () => { await p; console.log('1'); })(); p.then(() => console.log('2')) .then(() => console.log('3')); 

a)1 2 3
b)2 1 3
c)2 3 1
d)3 2 1


答案+解析

c)2 3 1


根据规范,必须首先执行添加的承诺,只有在此之后,您才需要继续
执行异步功能。 斑点 。 为了更详细地了解为什么这样做,建议您阅读有关v8.dev出色文章

Source: https://habr.com/ru/post/zh-CN431698/


All Articles