#HolyJS18のスタンドhh.ruでの質問の分析

私たちはあなたにとって面白くて珍しいことをしようとしました。 私たちが成功することを本当に願っています。 なぜそうなのか、答えも説明もなしにあなたを去りたくありませんでした。 正しくしましょう。







そもそも、コンテストの様子を思い出していただきたいと思います。JSに関する15の質問の4ラウンド、Reactに関する15の質問のラウンドのうちの1つ、10の質問の決勝がありました。







画像







カットの下-最初の4ラウンドのタスクの分析。







これは、分析の2番目の部分です。

ここで質問に反応する







どうやってこれをやったの? 選択できるストックがあるように、約80〜90の質問を生成する必要があると判断しました。 その後、すべてをトピックに分割しました。









その後、質問は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)エラー

これは関数式(式)です。この場合、関数の名前は関数に対してローカルです。 関数を呼び出すには、 bar



ではなく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

**



-これは0.1



2乗Math.powの類似物です-0.01になりますが、JSでは(他の多くの言語と同様に) 浮動小数点数を操作する際の操作の精度に既知の問題があります0.010000000000000002



になります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(1)



が、次の行では新しい関数でそれをグラインドし、 console.log(2)



のみが残ります。 onclick



はDOMプロパティであり、常に1です

イベントは、ハングした順序で機能し、最初の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



メソッドの知識、より具体的にはwritable



設定がdefineProperty



ます。 false



設定されている場合、 defineProperty



2番目のパラメーターによって渡されるキーの値を変更することは禁止されています。 唯一の違いは、ストリクトモードがない場合、ストリクトモードを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)エラー

接尾辞形式の犯罪を使用する場合、値は増加する前に返されます。

そしてプレフィックスの後に、すなわち console.log(++5)



6





const



は上書きできません。 数値はプリミティブです。インクリメントすると、変数は新しい値で上書きされ、エラーが発生します。







セット:



このコードは何を出力しますか?



 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



はセットであり、定義上、同じ値を設定することはできません。 問題は、これらの値をどのように比較するかです。 プリミティブは値によって比較され、オブジェクトは参照によって比較されます。

それ自体はデータ型を引用せず、任意の型1e1



および0xA



値を格納できます1e1



進法に変換され、10を取得します。

そして、新しいオブジェクトは常に等しくありません: console.log({} == {})



false



を返し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]]



は、要素自体ではなく、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



を返します。 この場合、setには触れず、プロキシにアクセスすると、オブジェクトの値が置き換えられます。







配列:



このコードは何を出力しますか?



 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)未定義

1つの数値引数でArray



を作成するとき、それは配列の長さを意味します。 配列は空で作成され、すべての値はundefined



です。 存在しない配列フィールドへのアクセスを作成すると、同じことが起こります。 Array



に数値を渡すと、この要素を持つ配列が返されることに注意してください。 Array('a')



['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)null







このコードは何を出力しますか?



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





回答+解析

d){}

空のオブジェクト{}



true



空の配列[]



true



です。

空の文字列''



null



およびundefined



false





論理的または||



-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)[true、true、true]







このコードは何を出力しますか?



 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)true







このコードは何を出力しますか?



 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)true

==



参照による比較。

操作中に、 >, >=, <, <=



オペランドがプリミティブに変換され、 arrayFoo



メソッドがarrayFoo



で呼び出され、プリミティブ値arrayFoo



が返されますが、同じ配列への参照が返されます。 次に、 toString



メソッドを呼び出すことによりプリミティブ値への変換が行われます。このメソッドは、配列の文字列表現を「1,2,3,4」の形式で返し、2つの配列を辞書的に比較してtrue



を返し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)true、true、false

MDNによる包括的な説明:

このメソッドの動作( Object.is



についてObject.is



)は、 ===



演算子と同じではありません。 ===



演算子(および==



演算子)は、数値-0



+0



等しいとNumber.NaN



Number.NaN



の値はそれ自体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



まで。

let



const



はポップアップせず、ブロック内にスコープを持ちます。 {}



限定されます。







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



キャストしfalse



。これは0









このコードは何を出力しますか?



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





回答+解析

c) '、1'

オブジェクトに対してtoString



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 [オブジェクトオブジェクト] 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



進数の16進表記は17



です。

1e1



指数形式は1 * 10 ** 1



つまり わずか10









typeof:



このコードは何を出力しますか?



 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オブジェクトはFunction.prototypeを継承します。 Speckはこれがオブジェクトであることを明示的に決定します。







イベントループ:



約束に関する2つの質問から始めましょう。



このコードは何を出力しますか?



 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



onFulfill



およびonReject



コールバックの2つのパラメーターをonFulfill



ことにonFulfill



してonReject



。 それ以前にエラーが発生した場合、 onReject



コールバックにonReject



ます。 エラーがない場合は、次にonFulfill



then



ます。 また、 () => {}



は空のオブジェクトではなく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! RO







このコードは何を出力しますか?



 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、「promise1が解決」、「setTimeout」

最初に、すべての同期呼び出しがトリガーされ、その後、呼び出しスタックが空になると、キューに入れられたもの(非同期タスク)が呼び出されます。 最初のマイクロタスク-約束とmutation observer



。 現在のタスクの最後に、すべてのマイクロタスクが実行されます。このマイクロタスクに関連して、イベントループをブロックできます。ブラウザでタスクが完了すると、レンダリングが行われます。 この後、マクロタスク-タイムアウトが実行されます。

これは非常に単純化された例です。詳細については、ミハイル・バシュロフのスピーチを見ることをお勧めします







そして最後の質問は約束と待つ



このコードは何を出力しますか?



 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







仕様によると、 then



追加されたプロミスは最初に実行され、 then



のみ続行する必要があります

非同期関数の実行。 スペック 。 これがなぜそうなのかをさらに詳しく理解するには、 v8.devの優れた記事を読むことをお勧めします。








All Articles