我希望知道的 26 个 JavaScript 面试问题
根据 Stack Overflow 2018 年度调查,JavaScript 连续六年成为最常用的编程语言。坦白说,JavaScript 是全栈开发者技能的基石,在任何开发者面试中都不可或缺。继续阅读FullStack.Cafe整理的 JavaScript 面试常见问题及答案,助你找到下一份理想的工作。
Q1:JavaScript 中的强制转换是什么?
主题:JavaScript
难度:
在 JavaScript 中,两种不同的内置类型之间的转换称为coercion
。JavaScript 中的强制转换有两种形式:显式和隐式。
下面是一个显式强制转换的例子:
var a = "42";
var b = Number( a );
a; // "42"
b; // 42 -- the number!
下面是一个隐式强制转换的例子:
var a = "42";
var b = a * 1; // "42" implicitly coerced to 42 here
a; // "42"
b; // 42 -- the number!
🔗来源: FullStack.Cafe
Q2:JavaScript 中的作用域是什么?
主题:JavaScript
难度:⭐
在 JavaScript 中,每个函数都有自己的作用域。作用域本质上是变量的集合,以及如何通过名称访问这些变量的规则。只有函数内部的代码才能访问该函数作用域内的变量。
变量名在同一作用域内必须是唯一的。一个作用域可以嵌套在另一个作用域内。如果一个作用域嵌套在另一个作用域内,则最内层作用域内的代码可以访问任一作用域的变量。
🔗来源: FullStack.Cafe
Q3:解释 JavaScript 中的相等性
主题:JavaScript
难度:⭐
JavaScript 既有严格比较,也有类型转换比较:
- 严格比较(例如 ===)检查值相等而不允许强制
- 抽象比较(例如 ==)检查值是否相等,允许强制
var a = "42";
var b = 42;
a == b; // true
a === b; // false
一些简单的相等规则:
- 如果比较中的任一值(又名边)可以是
true
或false
值,==
则避免使用===
。 - 如果比较中的任一值可以是这些特定值(
0
、""
或[]
--空数组),则应避免==
使用===
。 - 在其他所有情况下,您都可以安全地使用
==
。它不仅安全,而且在很多情况下,它还能简化您的代码,提高可读性。
🔗来源: FullStack.Cafe
Q4:解释一下什么是回调函数,并提供一个简单的例子。
主题:JavaScript
难度:⭐⭐
函数callback
是作为参数传递给另一个函数的函数,在某些操作完成后执行。下面是一个简单的回调函数示例,它在某些操作完成后将日志记录到控制台。
function modifyArray(arr, callback) {
// do something to arr here
arr.push(100);
// then execute the callback function that was passed
callback();
}
var arr = [1, 2, 3, 4, 5];
modifyArray(arr, function() {
console.log("array has been modified", arr);
});
🔗资料来源: coderbyte.com
Q5:“use strict” 起什么作用?
主题:JavaScript
难度:⭐⭐
字面use strict
量位于 JavaScript 程序或函数的顶部,如果错误地创建了全局变量,它会抛出错误,从而帮助你编写更安全的 JavaScript 代码。例如,以下程序将抛出错误:
function doSomething(val) {
"use strict";
x = val + 10;
}`
它会抛出一个错误,因为x
没有定义,并且它被设置为全局范围内的某个值,这是不允许的,use strict
下面的小改动修复了抛出的错误:
function doSomething(val) {
"use strict";
var x = val + 10;
}
🔗资料来源: coderbyte.com
Q6:解释 JavaScript 中的 Null 和 Undefined
主题:JavaScript
难度:⭐⭐
JavaScript(以及 TypeScript 的扩展)有两种底层类型:null
和undefined
。它们分别代表不同的含义:
- 有些 东西 还 没有 被 初始化 :
undefined
. - 某些内容当前不可用:
null
。
🔗来源: FullStack.Cafe
Q7:编写一个函数可以让你做到这一点。
主题:JavaScript
难度:⭐⭐
var addSix = createBase(6);
addSix(10); // returns 16
addSix(21); // returns 27
你可以创建一个闭包,这样即使在内部函数返回后,传递给函数的值仍然有效createBase
。返回的内部函数是在外部函数中创建的,因此它就是一个闭包,并且可以访问外部函数中的变量,在本例中就是变量baseNumber
。
function createBase(baseNumber) {
return function(N) {
// we are referencing baseNumber here even though it was declared
// outside of this function. Closures allow us to do this in JavaScript
return baseNumber + N;
}
}
var addSix = createBase(6);
addSix(10);
addSix(21);
🔗资料来源: coderbyte.com
Q8:解释 JavaScript 中的值和类型
主题:JavaScript
难度:⭐⭐
JavaScript 具有类型化的值,而不是类型化变量。以下是可用的内置类型:
string
number
boolean
null
和undefined
object
symbol
(ES6 新手)
🔗来源: FullStack.Cafe
Q9:解释事件冒泡以及如何防止它
主题:JavaScript
难度:⭐⭐
事件冒泡的概念是指事件在尽可能深的元素上触发,并按嵌套顺序在父元素上触发。因此,当点击子元素时,可能会触发父元素的处理程序。
防止事件冒泡的一种方法是在 IE <9 上使用event.stopPropagation()
或。event.cancelBubble
🔗来源: https://github.com/kennymkchan
Q10:JavaScript 中的 let 关键字是什么?
主题:JavaScript
难度:⭐⭐
除了在函数级别创建变量声明之外,ES6 还允许您使用let
关键字将变量声明为属于单个块({ .. } 对)。
🔗来源: github.com/getify
Q11:如何检查一个数字是否是整数?
主题:JavaScript
难度:⭐⭐
检查数字是小数还是整数的一个非常简单的方法是看除以 1 时是否有余数。
function isInt(num) {
return num % 1 === 0;
}
console.log(isInt(4)); // true
console.log(isInt(12.2)); // false
console.log(isInt(0.3)); // false
🔗资料来源: coderbyte.com
Q12:什么是 IIFE(立即调用函数表达式)?
主题:JavaScript
难度:⭐⭐⭐
它是一个立即调用函数表达式(Immediately-Invoked Function Expression,简称 IIFE)。它在创建后立即执行:
(function IIFE(){
console.log( "Hello!" );
})();
// "Hello!"
这种模式通常用于尝试避免污染全局命名空间,因为 IIFE 内部使用的所有变量(就像在任何其他正常函数中一样)在其范围之外是不可见的。
🔗来源: stackoverflow.com
Q13:如何在 JavaScript 中比较两个对象?
主题:JavaScript
难度:⭐⭐⭐
两个非原始值,如通过引用保存的对象(包括函数和数组),因此==
和===
比较将仅检查引用是否匹配,而不是有关底层值的任何内容。
例如,arrays
默认情况下,只需用逗号 ( ,
) 连接所有值即可强制转换为字符串。因此,两个内容相同的数组不会==
相等:
var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";
a == c; // true
b == c; // true
a == b; // false
对于深度对象比较,请使用外部库deep-equal
或实现您自己的递归相等算法。
🔗来源: FullStack.Cafe
Q14:你能解释一下 ES5 和 ES6 之间的区别吗
主题:JavaScript
难度:⭐⭐⭐
-
ECMAScript 5(ES5):ECMAScript 的第 5 版,于 2009 年标准化。该标准已在所有现代浏览器中得到相当完整的实现
-
ECMAScript 6(ES6)/ ECMAScript 2015(ES2015):ECMAScript 的第 6 版,于 2015 年标准化。该标准已在大多数现代浏览器中部分实现。
以下是 ES5 和 ES6 之间的一些主要区别:
- 箭头函数和字符串插值:考虑:
const greetings = (name) => {
return `hello ${name}`;
}
甚至:
const greetings = name => `hello ${name}`;
- Const。Const 在其他语言中的作用在很多方面类似于常量,但也有一些注意事项。Const 代表对值的“常量引用”。因此,使用 const,你实际上可以改变变量所引用对象的属性。你只是无法更改引用本身。
const NAMES = [];
NAMES.push("Jim");
console.log(NAMES.length === 1); // true
NAMES = ["Steve", "John"]; // error
- 块级作用域变量。新的 ES6 关键字
let
允许开发人员在块级别上限定变量的作用域。Let
不会以同样的方式提升var
。 - 默认参数值:默认参数允许我们使用默认值来初始化函数。当参数省略或未定义时,将使用默认值——这意味着 null 是有效值。
// Basic syntax
function multiply (a, b = 2) {
return a * b;
}
multiply(5); // 10
-
类定义和继承
ES6 引入了对类(class
关键字)、构造函数(constructor
关键字)和extend
继承关键字的语言支持。 -
for-of 运算
符 for...of 语句创建一个对可迭代对象进行迭代的循环。 -
扩展运算符
用于对象合并
const obj1 = { a: 1, b: 2 }
const obj2 = { a: 2, c: 3, d: 4}
const obj3 = {...obj1, ...obj2}
- Promise提供了一种处理异步操作结果和错误的机制。您可以使用回调实现相同的功能,但 Promise 通过方法链和简洁的错误处理提高了代码的可读性。
const isGreater = (a, b) => {
return new Promise ((resolve, reject) => {
if(a > b) {
resolve(true)
} else {
reject(false)
}
})
}
isGreater(1, 2)
.then(result => {
console.log('greater')
})
.catch(result => {
console.log('smaller')
})
- 模块导出和导入考虑模块导出:
const myModule = { x: 1, y: () => { console.log('This is ES5') }}
export default myModule;
并导入:
import myModule from './myModule';
🔗来源: Bulby.io
Q15:解释 JavaScript 中“undefined”和“notdefined”之间的区别
主题:JavaScript
难度:⭐⭐⭐
在 JavaScript 中,如果你尝试使用一个不存在且未声明的变量,JavaScript 将抛出错误var name is not defined
,脚本随后将停止执行。但如果你使用typeof undeclared_variable
,它将返回undefined
。
在开始进一步讨论之前,让我们先了解声明和定义之间的区别。
var x
是一个声明,因为您尚未定义它所具有的值,但您声明了它的存在以及内存分配的必要性。
var x; // declaring x
console.log(x); //output: undefined
var x = 1
既是声明又是定义(也可以说我们正在进行初始化),这里变量 x 的声明和赋值都是内联发生的,在 JavaScript 中,每个变量声明和函数声明都会带到其当前声明范围的顶部,然后按顺序进行赋值,这个术语被称为hoisting
。
一个已声明但未定义的变量,当我们尝试访问它时,将导致undefined
。
var x; // Declaration
if(typeof x === 'undefined') // Will return true
当我们尝试引用一个既未声明也未定义的变量时,就会产生这样的结果
not defined
。
console.log(y); // Output: ReferenceError: y is not defined
🔗来源: stackoverflow.com
Q16:匿名函数和命名函数有什么区别?
主题:JavaScript
难度:⭐⭐⭐
考虑:
var foo = function() { // anonymous function assigned to variable foo
// ..
};
var x = function bar(){ // named function (bar) assigned to variable x
// ..
};
foo(); // actual function execution
x();
🔗来源: FullStack.Cafe
Q17:JavaScript 中的“闭包”是什么?请举例说明。
主题:JavaScript
难度:⭐⭐⭐⭐
闭包是在另一个函数(称为父函数)内部定义的函数,并且可以访问在父函数范围内声明和定义的变量。
闭包可以访问三个范围内的变量:
- 变量在其自己的范围内声明
- 在父函数作用域中声明的变量
- 全局命名空间中声明的变量
var globalVar = "abc";
// Parent self invoking function
(function outerFunction (outerArg) { // begin of scope outerFunction
// Variable declared in outerFunction function scope
var outerFuncVar = 'x';
// Closure self-invoking function
(function innerFunction (innerArg) { // begin of scope innerFunction
// variable declared in innerFunction function scope
var innerFuncVar = "y";
console.log(
"outerArg = " + outerArg + "\n" +
"outerFuncVar = " + outerFuncVar + "\n" +
"innerArg = " + innerArg + "\n" +
"innerFuncVar = " + innerFuncVar + "\n" +
"globalVar = " + globalVar);
// end of scope innerFunction
})(5); // Pass 5 as parameter
// end of scope outerFunction
})(7); // Pass 7 as parameter
innerFunction
是定义在内部的闭包outerFunction
,可以访问在 outerFunction 作用域中声明和定义的所有变量。此外,在函数内部定义的闭包还可以访问在 中声明的变量global namespace
。
上述代码的输出为:
outerArg = 7
outerFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc
Q18:如何在 JavaScript 中创建私有变量?
主题:JavaScript
难度:⭐⭐⭐⭐
要在 JavaScript 中创建无法更改的私有变量,您需要将其创建为函数内的局部变量。即使函数执行完毕,函数外部也无法访问该变量。例如:
function func() {
var priv = "secret code";
}
console.log(priv); // throws error
要访问变量,需要创建一个返回私有变量的辅助函数。
function func() {
var priv = "secret code";
return function() {
return priv;
}
}
var getPriv = func();
console.log(getPriv()); // => secret code
🔗资料来源: coderbyte.com
Q19:解释原型设计模式
主题:JavaScript
难度:⭐⭐⭐⭐
原型模式会创建新对象,但它不会创建未初始化的对象,而是返回使用从原型(或样本)对象复制的值进行初始化的对象。原型模式也称为属性模式。
原型模式的一个实用示例是,使用与数据库中默认值匹配的值来初始化业务对象。原型对象保存着默认值,这些默认值会被复制到新创建的业务对象中。
传统语言很少使用原型模式,但 JavaScript 作为一种原型语言,在构建新对象及其原型时使用了这种模式。
🔗资料来源: dofactory.com
Q20:检查给定的字符串是否同构
主题:JavaScript
难度:⭐⭐⭐⭐
两个字符串同构是指字符串 A 中所有出现的字符都可以替换为另一个字符,从而得到字符串 B。字符的顺序必须保持不变。字符串 A 中的每个字符与字符串 B 中的每个字符必须存在一一映射。
paper
并title
返回 true。egg
并sad
会返回 false。dgg
并add
返回 true。
isIsomorphic("egg", 'add'); // true
isIsomorphic("paper", 'title'); // true
isIsomorphic("kick", 'side'); // false
function isIsomorphic(firstString, secondString) {
// Check if the same lenght. If not, they cannot be isomorphic
if (firstString.length !== secondString.length) return false
var letterMap = {};
for (var i = 0; i < firstString.length; i++) {
var letterA = firstString[i],
letterB = secondString[i];
// If the letter does not exist, create a map and map it to the value
// of the second letter
if (letterMap[letterA] === undefined) {
letterMap[letterA] = letterB;
} else if (letterMap[letterA] !== letterB) {
// Eles if letterA already exists in the map, but it does not map to
// letterB, that means that A is mapping to more than one letter.
return false;
}
}
// If after iterating through and conditions are satisfied, return true.
// They are isomorphic
return true;
}
🔗来源: https://github.com/kennymkchan
Q21:“Transpiling”一词代表什么?
主题:JavaScript
难度:⭐⭐⭐⭐
目前没有办法对语言中新增的语法进行 polyfill。因此,更好的选择是使用一个工具,将新代码转换为旧代码的对应形式。这个过程通常被称为转译 (transpiling),即转换 + 编译。
通常,你会将转译器插入到构建过程中,类似于代码检查器或压缩工具。
市面上有很多优秀的转译器可供选择:
- Babel:将 ES6+ 转译为 ES5
- Traceur:将 ES6、ES7 及更高版本转换为 ES5
🔗资料来源: 你不知道的 JS,正在更新
Q22:“this”关键字如何工作?提供一些代码示例。
主题:JavaScript
难度:⭐⭐⭐⭐
在 JavaScript 中,this始终指的是我们正在执行的函数的“所有者”,或者更确切地说,指的是函数作为其方法的对象。
考虑:
function foo() {
console.log( this.bar );
}
var bar = "global";
var obj1 = {
bar: "obj1",
foo: foo
};
var obj2 = {
bar: "obj2"
};
foo(); // "global"
obj1.foo(); // "obj1"
foo.call( obj2 ); // "obj2"
new foo(); // undefined
🔗资料来源: quirksmode.org
Q23:如何将自己的方法添加到 Array 对象中,以便以下代码能够正常工作?
主题:JavaScript
难度:⭐⭐⭐⭐
var arr = [1, 2, 3, 4, 5];
var avg = arr.average();
console.log(avg);
JavaScript 不是基于类的语言,而是基于原型的语言。这意味着每个对象都链接到另一个对象(即它的原型),并继承其方法。你可以沿着每个对象的原型链一直追溯到null
没有原型的对象。我们需要为全局对象添加一个方法Array
,我们将通过修改 来实现Array prototype
。
Array.prototype.average = function() {
// calculate sum
var sum = this.reduce(function(prev, cur) { return prev + cur; });
// return sum divided by number of elements
return sum / this.length;
}
var arr = [1, 2, 3, 4, 5];
var avg = arr.average();
console.log(avg); // => 3
🔗资料来源: coderbyte.com
Q24:JavaScript 中的提升是什么?
主题:JavaScript
难度:⭐⭐⭐⭐
提升是 JavaScript 解释器将所有变量和函数声明移至当前作用域顶部的操作。提升有两种类型:
- 变量提升——罕见
- 函数提升——更常见
无论(或函数声明)出现在作用域内的何处var
,该声明都被视为属于整个作用域并且可以在整个作用域的任何地方访问。
var a = 2;
foo(); // works because `foo()`
// declaration is "hoisted"
function foo() {
a = 3;
console.log( a ); // 3
var a; // declaration is "hoisted"
// to the top of `foo()`
}
console.log( a ); // 2
🔗来源: FullStack.Cafe
Q25:以下代码将输出什么?
主题:JavaScript
难度:⭐⭐⭐⭐
0.1 + 0.2 === 0.3
false
由于浮点数在内部表示某些数字时存在错误,因此输出结果会令人意外。结果0.1 + 0.2
并不美观,0.3
而是0.30000000000000004
因为计算机内部无法表示正确的数字。解决这个问题的一个方法是在对十进制数进行运算时对结果进行四舍五入。
🔗资料来源: coderbyte.com
Q26:描述揭示模块模式设计模式
主题:JavaScript
难度:⭐⭐⭐⭐⭐
模块模式的一个变体称为“揭示模块模式”。其目的是保持封装性,并揭示对象字面量返回的某些变量和方法。直接实现如下:
var Exposer = (function() {
var privateVariable = 10;
var privateMethod = function() {
console.log('Inside a private method!');
privateVariable++;
}
var methodToExpose = function() {
console.log('This is a method I want to expose!');
}
var otherMethodIWantToExpose = function() {
privateMethod();
}
return {
first: methodToExpose,
second: otherMethodIWantToExpose
};
})();
Exposer.first(); // Output: This is a method I want to expose!
Exposer.second(); // Output: Inside a private method!
Exposer.methodToExpose; // undefined
它的一个明显缺点是无法引用私有方法
🔗来源: scotch.io
文章来源:https://dev.to/fullstackcafe/top-26-javascript-interview-questions-i-wish-i-knew-26k1感谢🙌的阅读,祝你面试顺利!
如果喜欢,请分享给你的开发者同事!
更多 FullStack 面试问答,请访问👉 www.fullstack.cafe