フロントエンド開発スクール採用面接の質問整理【1】 - JavaScript
前に書かれている:
インタビューの質問はすべて整理され、GitHub で共有されています。スターへようこそ。
アドレス: https://github.com/shadowings-zy/front-end-school-recruitment-question
1. JavaScriptの基礎
Q: js の基本的なデータ型を紹介しますか?
基本タイプ (値タイプ): 文字列、数値、ブール、Null、未定義、シンボル、BigInt。
数値の種類には整数と浮動小数点数があり、整数の精度は 2^53、浮動小数点値の最高精度は小数点以下 17 桁です。
また、NAN はデジタル型に属し、非数値を表すことにも注意してください。つまり、1/0=NAN、NAN/1=NAN です。
無限大は、プラスまたはマイナス記号を付けて、範囲を超える数値を表します。
未定義: 変数は宣言されていますが、値が含まれていないことを示します。
null: 変数が空であることを示します。
参照タイプ: オブジェクト、配列、関数 (実際、これらはすべてオブジェクトであり、すべて参照です)。
データカプセル化オブジェクト: Object、Array、Boolean、Number、String
その他のオブジェクト: Function、Arguments、Math、Date、RegExp、Error
基本型はスタック メモリに保存され、参照型はヒープ メモリに保存されます。
Q: js でオブジェクトの型を判断するにはどうすればよいですか?
typeof を使用して、JavaScript 基本オブジェクトのタイプを決定します。
typeof 'John' // 返回 string
typeof 3.14 // 返回 number
typeof NaN // 返回 number
typeof false // 返回 boolean
typeof [1, 2, 3, 4] // 返回 object
typeof {
name: 'John', age: 34 } // 返回 object
typeof new Date() // 返回 object
typeof function () {
} // 返回 function
typeof myCar // 返回 undefined (如果 myCar 没有声明)
typeof null // 返回 object
コンストラクターを使用するとコンストラクターの型を返すことができ、コンストラクターの名前によって型を判断できます。
"John".constructor // 返回函数 String() {[native code]}
(3.14).constructor // 返回函数 Number() {[native code]}
false.constructor // 返回函数 Boolean() {[native code]}
[1,2,3,4].constructor // 返回函数 Array() {[native code]}
{
name:'John', age:34}.constructor // 返回函数 Object() {[native code]}
new Date().constructor // 返回函数 Date() {[native code]}
function () {
}.constructor // 返回函数 Function() {[native code]}
次のような参照型を検出するには、instanceof を使用します。
console.log(person instanceof Object) // 变量 person 是 Object 吗?
console.log(colors instanceof Array) // 变量 colors 是 Array 吗?
console.log(pattern instanceof RegExp) // 变量 pattern 是 RegExp 吗?
Q: js のプロトタイプチェーンをどのように理解していますか?
オブジェクトが存在する限り、プロトタイプが存在し、プロトタイプもオブジェクトであるため、オブジェクトが定義されている限り、そのプロトタイプが見つかるなど、一連のオブジェクトが形成されます。この構造はプロトタイプチェーンと呼ばれます。
各オブジェクトは、その内部にあるプロパティ、つまりプロトタイプ (プロトタイプ) を初期化します。オブジェクトのプロパティにアクセスするとき、そのプロパティがオブジェクトに存在しない場合は、プロトタイプにアクセスしてプロパティを見つけます。プロトタイプは自分自身のプロトタイプを持っているので、このように探し続けます。これが通常プロトタイプチェーンの概念と呼ばれるものです。
系:instance.constructor.prototype =instance.proto
Q: js の function.call と function.apply の違いは何ですか?
function.apply(thisObj, [argArray])
function.call(thisObj, arg1, arg2, …, argN);
apply: オブジェクトのメソッドを呼び出して、現在のオブジェクトを別のオブジェクトに置き換えます。例: B.apply(A, argument); つまり、A オブジェクトは B 関数を適用します、つまり、B コンテキストを初期コンテキストから A コンテキストに変更します。
call: オブジェクトのメソッドを呼び出し、現在のオブジェクトを別のオブジェクトに置き換えます。例: B.call(A, args1, args2); つまり、A オブジェクトは B オブジェクトのメソッドを呼び出します。
Q: js のスコープをどのように理解しますか?
グローバル スコープ: 最外層に記述されたオブジェクト、または内部層に記述されたが var で宣言されていない変数。スコープはグローバルです。次に例を示します。
var outerVar = "outer";
function fn() {
innerVar = “inner”;
console.log(outerVar);
}
fn(); //result:outer
console.log(innerVar); //result:inner
関数スコープ: 関数内で var を使用して宣言された変数を書き込みます。次に例を示します。
function fn() {
var innerVar = 'inner'
}
console.log(innerVar) // ReferenceError: innerVar is not defined
スコープ チェーン: 内部関数は、外部関数の変数へのアクセスをチェーンできます。次に例を示します。
name = 'aaa'
function b() {
var name = 'bbb'
function c() {
var name = 'ccc'
console.log(name) //ccc
}
function d() {
console.log(name) //bbb
}
c()
d()
}
b()
console.log(name) //aaa
Q: js のクロージャーとは何ですか?
クロージャはjsのスコープ機能を利用し、戻り値が関数となる関数を使用することで、内部の関数が外部関数の変数にアクセスできるようにします。外部関数を呼び出すときに、戻り値関数を呼び出して外部関数の変数を変更できます。
クロージャは、別の関数のスコープ内の変数にアクセスできる関数です。
機能:
1. グローバル変数のオブジェクトを減らすことができ、これまでのようにグローバル変数が大きくなりすぎて保守が困難になることを防ぎます
2. 頻繁な変更を防ぎます。
3. 関数内の変数を読み取り、これらの変数の値が常にメモリに保持されるようにします。
例えば:
const add = function () {
let counter = 0
return function () {
counter++
return counter
}
}
const x = add()
console.log(x()) // 计数器为 1
console.log(x()) // 计数器为 2
console.log(x()) // 计数器为 3
2. JavaScript フロー制御
Q: js での Promise の使用法について教えてください。
Promise オブジェクトは、外部の影響を受けない非同期操作を表し、次の 3 つの状態があります:
Pending // 進行中、未完了
Resolved // Completed、別名 Fulfilled
Rejected // Failed
Promise オブジェクトは、次の 4 つのメソッドを提供します。
then // 非同期操作が完了したときにメソッドを呼び出す
catch // 非同期操作が失敗したときにメソッドを呼び出す
all // すべての関数の操作が完了した後にメソッド Race を呼び出す
// メソッドを呼び出す最初のものが完了または失敗した後
例えば:
function read(time) {
console.log('正在阅读')
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('阅读完毕')
time = time + 1
resolve(time)
}, 2000)
})
return p
}
function write(time) {
console.log('正在写作')
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('写作完毕')
time = time + 1
resolve(time)
}, 2000)
})
return p
}
function rest(time) {
console.log('正在休息')
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('休息完毕')
time = time + 1
resolve(time) //把promise的状态设置为resolved,成功
}, 2000)
})
return p
}
function badDream(time) {
console.log('正在做梦')
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('做了噩梦')
time = time + 1
reject(time) //把promise的状态设置为rejected,失败
}, 2000)
})
return p
}
read(0)
.then(function (data) {
return write(data)
})
.then(function (data) {
return badDream(data)
})
.then(function (data) {
return rest(data)
})
.then(function (data) {
console.log(data)
})
.catch(function (data) {
//处理失败的方法
console.log('第' + data + '步出错')
})
const p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p1完成')
resolve(11)
}, 1000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p2完成')
resolve(22)
}, 2000)
})
const p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p3完成')
resolve(33)
}, 3000)
})
//all,所有函数都执行结束后,回调方法
Promise.all([p1, p2, p3]).then(function (data) {
console.log('全部完成', data)
})
//race,第一个函数执行结束后,回调方法
Promise.race([write(1), rest(2)]).then(function (results) {
console.log('准备工作完毕:')
console.log(results)
})
Q: js での async と await の使用法について教えてください。プロミスとの違いは?
async は、関数が非同期関数であることを示すキーワードとして関数の前に置かれます。
async は非同期を意味するため、非同期関数は、関数の実行が次のコードの実行をブロックしないことを意味します。
async は Promise オブジェクト (console.log(timeout()) など) を返し、resolve が hello world を返す場合、reject が例外をスローする場合は Promise オブジェクトを取得します。
しかし、これが重要ではなく、async の最大の利点は、その中で await を使用できることで、Promise の then チェーンをより簡潔に処理できることです。
async に await がない場合、実際には、解決が戻り値を返す Promise オブジェクトと同等になります。
await 式は、現在の非同期関数の実行を一時停止し、Promise が処理されるのを待ちます。Promise が正常に履行された場合、コールバックのsolve 関数パラメータが await 式の値として使用され、async 関数が実行され続けます。Promise が例外を処理する (拒否される) 場合、await 式は Promise の例外理由をスローします。また、await 演算子の後の式の値が Promise でない場合は、値そのものが返されます。
async と await を組み合わせると、Promise の then チェーンをより直感的に処理できます。
例:
Promise の書き方:
doSomething()
.then(function (res) {
return doNext(res)
})
.then(function (nextRes) {
return doFinalThing(nextRes)
})
.then(function (finalResult) {
console.log('Got the final result: ' + finalResult)
})
.catch(failureCallback)
async/awaitの書き方:
try {
const result = await doSomething()
const nextRes = await doNext(result)
const finalResult = await doFinalThing(newResult)
console.log('Got the final result: ' + finalResult)
} catch (error) {
failureCallback(error)
}
3. JavaScript の共通データ構造
Q: よく使用される Array API について教えてください。
Array の API の焦点は、API が何のためにあるのかを知ることではなく、それを使用できるようにすることです。
push(a) // 末尾添加,返回数组长度
unshift(a) // 首位添加,返回数组长度
shift() // 删除第一个元素,并返回删除的元素
pop() // 删除最后一个元素,并返回删除的元素
join(a) // 把数组中的所有元素放到一个字符串中,分隔符为a
concat(a, b) // 将b连接到a后面
sort() // 数组排序
reverse() // 数组倒序
isArray(a) // a是否为数组
slice(a, b) // 根据输入的开始点和末尾点,截取出新的数组(包括前不包括后)
splice(a, b, c) // 从a位置开始,删除b长度的数组,插入c
indexOf(a) // 从前向后寻找值等于a的项,返回index
lastIndexOf(a) // 从后向前寻找等于a的项,返回index
every(function(item, index, array)) // 对数组每一项运行一次某函数,若函数每一项都为true,返回true
some(function(item, index, array)) // 对数组每一项运行一次某函数,若函数某一项为true,返回true
filter(function(item, index, array)) // 对数组每一项运行一次某函数,返回返回值为true的项的数组
map(function(item, index, array)) // 对数组每一项运行一次某函数,返回返回值的数组
forEach(function(item, index, array)) // 对数组每一项运行一次某函数,无返回值
reduce(function(prev, cur, index, array)) //接收四个参数:前一个值、当前值、项的索引和数组对象,这个函数的任意返回值会作为第一个参数传给下一项。
Q: 配列/オブジェクトを走査する for in と for of の違いは何ですか?
配列の場合: for in は配列インデックス値 (添字) を出力し、for of は配列要素を出力します。
オブジェクトの場合: for in はオブジェクトのキー値を出力し、for of はオブジェクトの値の値を出力します。
Q: 配列のフラット化を実装するコードは何ですか?
const arr = [1, 3, [3, 4, [5, 6]]]
// 第一种方案:用现成api,不兼容低版本的浏览器
const arr1 = arr.flat(Infinity)
// 第二种方案:原生循环递归实现
function flat2(arr) {
const result = []
arr.forEach((item) => {
if (Array.isArray(item)) {
result.push(...flat(item))
} else {
result.push(item)
}
})
return result
}
const arr2 = flat2(arr)
// 第三种方案:使用解构和递归实现
function flat3(arr) {
const result = [].concat(...arr.map((x) => (Array.isArray(x) ? flat(x) : x)))
return result
}
const arr3 = flat3(arr)
Q: ディープコピーオブジェクトを実現するコードは何ですか?
// 对象中如果均为基本类型
JSON.parse(JSON.stringify(obj))
// 对象中如果既有基本类型,还有Array和Object
function deepCopy(data) {
let output
if (data === null || !(typeof data === 'object')) {
output = data
} else {
output = data.constructor.name === 'Array' ? [] : {
}
for (let key in data) {
output[key] = deepCopy(data[key])
}
}
return output
}
Q: "test" と new String("test") の違いは何ですか?また、{} と new Object() の違いは何ですか?
「test」は文字列型の定数であり、new String() は文字列オブジェクトを作成します。
const obj1 = new String('abc') // 类型为object
const obj2 = 'abc' // 类型为string
obj1 == obj2 // true
obj1 === obj2 // false
{} と new Object() は両方とも、それ自体でオブジェクトを作成し、そのオブジェクトへの参照を返します。
const obj1 = new Object('abc') // 类型为object
const obj2 = {
} // 类型为obejct
obj1 == obj2 // false
obj1 === obj2 // false
4、DOM/BOM API
Q: addEventListener の使用方法は? onxxx との違いは何ですか?
onxxx は DOM0 の標準であり、すべてのブラウザでサポートされており、DOM オブジェクトにイベント名を直接登録します。
例えば:
document.getElementById('click').onclick = function (event) {
console.log(event.target)
}
addEventListener は DOM2 の標準であり、IE8 以降のブラウザでサポートされており、キャプチャ ステージ、ターゲット ステージ、バブリング ステージの 3 つのステージに分かれています。
各イベントは、まずルートからターゲット要素に渡され、次にルートに戻ります。
Q: イベント プロキシとは何を指しますか?
イベントプロキシとは、複数の要素(liなど)にイベントを追加するために、その要素の親要素にイベントを追加し、イベントが発生した際にイベント対象を捕捉し、対象を判定して対応するイベントを実行することを指しますe.target
。
Q: js を使用して Cookie にアクセスするにはどうすればよいですか? jsでCookieへのアクセスを禁止したい場合はどうすればよいでしょうか?
Cookie を表示するには、document.cookie を使用します。Cookie の保存形式は、key=value;key=value;
次の形式の文字列です。
ヘッダーに HttpOnly を設定すると、js が Cookie にアクセスするのを防ぐことができます。
Q: js を使用してブラウザの表示可能領域を計算するにはどうすればよいですか?
// 获取浏览器窗口的可视区域的宽度
const width = document.documentElement.clientWidth || document.body.clientWidth
// 获取浏览器窗口的可视区域的高度
const height = document.documentElement.clientHeight || document.body.clientHeight