本文共 11061 字,大约阅读时间需要 36 分钟。
译者按: 从各个平台精选整理出26道由浅入深的题目助你面试
为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。
根据Stack Overflow 2018年年度调查报告,JavaScript已经连续6年保持最常用的编程语言的记录。对于一个全栈工程师,JavaScript可以说是一项必备语言,在面试中总会被问到。我整理了一下上所有常见的JavaScript面试问题供大家参考:
话题: JavaScript
难度: 0
在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 herea; // "42"b; // 42 -- the number!
来源:
话题: JavaScript
难度: ⭐
在JavaScript中,每一个函数都有各自的作用域(scope
)。作用域可以理解为是一个变量的集合以及相应的如何访问它的规则。只有在函数内部的变量才可以访问到该函数域的变量。
在同一个作用域内部,变量名必须要唯一。作用域可以嵌套。在最内部的作用域中,可以访问任何外部的作用域中的变量。
话题: JavaScript
难度: ⭐
JavaScript中的相等判断有严格判断和带隐式转换的判断两种:
===
,比较的时候不会隐式转换类型;==
,比较的时候会隐式转换类型。var a = "42";var b = 42;a == b; // truea === b; // false
一些简单的规则:
===
;""
,[]
,使用===
;==
是安全的。而且在很多情况下会简化代码、增加可读性。话题: JavaScript
难度: ⭐⭐
回调函数是一个函数,它被作为参数传入另一个函数,当某些操作结束后,该函数被调用。下面是一个简单的例子,当数组被修改后,调用回调函数打印一行日志。
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);});
话题: JavaScript
难度: ⭐⭐
use strict
放在文件的顶部或则函数的第一行来启动更加严格的检查来避免失误引起的错误。比如,下面的代码会抛出错误:
function doSomething(val) { "use strict"; x = val + 10;}
因为x没有定义,如果使用了use strict
,x是不会被当做全局的变量来看待。下面的代码修复了这个BUG:
function doSomething(val) { "use strict"; var x = val + 10;}
话题: JavaScript
难度: ⭐⭐
JavaScript和TypeScript有两个最基本的类型null
和undefined
。它们的含义是不同的:
undefined
;null
来表示;话题: JavaScript
难度: ⭐⭐
var addSix = createBase(6);addSix(10); // returns 16addSix(21); // returns 27
addSix
是一个函数,也就是说createBase函数的返回是一个函数。
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);
话题: JavaScript
难度: ⭐⭐
下面是JavaScript内置的可用类型:
话题: JavaScript
难度: ⭐⭐
事件冒泡的概念是指:在最内层的元素上绑定的事件被触发后,会按照嵌套的层次由内向外逐步触发。因此,点击某个孩子节点可能会触发父节点的事件。
一个阻止事件冒泡的办法就是使用event.stopPropagation()
,在IE<9的浏览器上使用event.cancelBubble()
。
来源:
话题: JavaScript
难度: ⭐⭐
ES6允许你使用let关键字来申明块作用域({...}
)的变量。
来源:
话题: JavaScript
难度: ⭐⭐
一个最简单的方法是判断除以1的余数是否为0.
function isInt(num) { return num % 1 === 0;}console.log(isInt(4)); // trueconsole.log(isInt(12.2)); // falseconsole.log(isInt(0.3)); // false
来源:
话题: JavaScript
难度: ⭐⭐
IIFE叫做立即执行表达式,顾名思义,该表达式一被创建就立即执行。
(function IIFE(){ console.log( "Hello!" );})();// "Hello!"
该方法常用语避免污染全局的命名空间,因为所以在IIFE中使用的变量外部都无法访问。
来源:
话题: JavaScript
难度: ⭐⭐
两个非基本类型的值,比如对象(包括函数和数组)都是通过引用的形式来访问。如果直接通过==
和===
来判断,那么只会简单的判断其引用地址是否相同,而不是它们实际对应的值。
如果数组和字符串做比较,那么数组会通过逗号拼接转换为字符串。通过等号判断的时候,两个相同的数组不会相等,但是和相同数据的字符串比较反而相等。
var a = [1,2,3];var b = [1,2,3];var c = "1,2,3";a == c; // trueb == c; // truea == b; // false
如果要深度比较,可以使用第三方库,比如deep-equal
或则你自己实现一个比较算法。
话题: JavaScript
难度: ⭐⭐⭐
接下来介绍它们主要的区别:
const greetings = (name) => { return `hello ${name}`;}
甚至:
const greetings = name => `hello ${name}`;
const
代表了constant reference
。也就是说,你可以修改其指向的对象的值。但是你不能修改其reference的值。const NAMES = [];NAMES.push("Jim");console.log(NAMES.length === 1); // trueNAMES = ["Steve", "John"]; // error
let
允许允许开发者将变量的作用域限定在块级别。不会像var
一样变量提升。// Basic syntaxfunction multiply (a, b = 2) { return a * b;}multiply(5); // 10
ES6开始支持定义类(使用class
关键字),构造函数(使用constructor
关键字),和extend
关键字来实现继承。
for...of
语句用来迭代访问一个对象的所有属性。
const obj1 = { a: 1, b: 2 }const obj2 = { a: 2, c: 3, d: 4}const obj3 = {...obj1, ...obj2}
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';
来源:
undefined
和not defined
的区别话题: JavaScript
难度: ⭐⭐⭐
在JavaScript中,如果你尝试使用不存在的还未申明的变量,JavaScript会抛出错误var name is not defined
。但是如果你用typeof
来查看其类型,会返回undefined
。
我们先来澄清一下声明和定义的区别:var x
是一个声明,因为你并没有定义其具体的值,你只是声明其存在性。
var x; // declaring xconsole.log(x); //output: undefined
var x = 1
同时兼具声明和定义,我们也可以叫它初始化。在JavaScript中,每一个变量和函数声明都会被提升到顶部。
如果我们访问一个声明了但是未定义的变量,会返回undefined
。
var x; // Declarationif(typeof x === 'undefined') // Will return true
访问一个未声明未定义的变量,会返回not defined错误。
console.log(y); // Output: ReferenceError: y is not defined
来源:
话题: JavaScript
难度: ⭐⭐⭐
var foo = function() { // anonymous function assigned to variable foo // ..};var x = function bar(){ // named function (bar) assigned to variable x // ..};foo(); // actual function executionx();
译者补充:匿名函数如果不赋值给某个变量,则无法被调用了;命名函数再次被赋值不是多此一举么。
话题: 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
作用域的所有变量。当然,它还可以访问全局变量。
输出结果如下:
outerArg = 7outerFuncVar = xinnerArg = 5innerFuncVar = yglobalVar = abc
来源:
话题: 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
来源:
话题: JavaScript
难度: ⭐⭐⭐⭐
原型模式会创建一个新的对象,但不是创建一个未初始化的对象,而是通过拷贝原型链上的值或则被拷贝对象的值来完成初始化。传统的语言很少使用原型模式,但是JavaScript作为一个基于原型的语言,使用原型模式来创建新的对象。
来源:
话题: JavaScript
难度: ⭐⭐⭐⭐
首先介绍什么叫做同态:两个字符串,如果A字符串中的每一个字符都可以在B字符串中找到唯一对应,并且顺序一一对应;如果存在这样的函数,那么A和B同态。
paper
和title
同态egg
和sad
不同态dgg
和add
同态isIsomorphic("egg", 'add'); // trueisIsomorphic("paper", 'title'); // trueisIsomorphic("kick", 'side'); // falsefunction isIsomorphic(firstString, secondString) { // Check if the same length. 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;}
来源:
Transpiling
代表了什么意思?话题: JavaScript
难度: ⭐⭐⭐⭐
Transpiling
是transforming + compiling
的合成词。对于一些新的语法,浏览器还不支持。最好的办法就是将其变换到旧的等价的代码,这个过程通常叫做transpiling
。
典型的,你可以在build
的过程中加入transpiler
,就如同code linter
和minifier
一样。
已经有很多知名的transpilers可供使用:
来源:
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
来源:
话题: JavaScript
难度: ⭐⭐⭐⭐
var arr = [1, 2, 3, 4, 5];var avg = arr.average();console.log(avg);
JavaScript是一个基于原型的语言。也就是说对象之间通过原型链接,并继承其函数。为了给Array对象添加函数,我们可以修改其原型定义Array prorotype
。
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
来源:
话题: JavaScript
难度: ⭐⭐⭐⭐
提升(hoisting)是指JavaScript的解释器将所有的变量和函数声明都提升到该作用域的顶部,有两种提升类型:
在一个作用域中通过声明的变量和函数在整个作用域中都可以使用。
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
虽然foo()
函数在后面定义,但是在前面也可以调用。
话题: JavaScript
难度: ⭐⭐⭐⭐
0.1 + 0.2 === 0.3
不要惊讶,其结果是false。因为浮点数在系统内的精确度问题,0.1+0.2的结果并不是0.3,而是0.30000000000000004。
要避免这个问题的方法是指定返回结果的小数位数。来源:
话题: JavaScript
难度: ⭐⭐⭐⭐⭐
Module pattern的一个变种是Revealing Module Pattern
。该设计模式的目的是做到很好的代码隔离,只是将需要对外公开的变量和函数暴露出来。一个直接的实现如下所示:
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
来源:
专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用!
转载时请注明作者以及本文地址: