译者按:
从各个平台精选整理出26道由浅入深的题目助你面试
为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。
根据Stack Overflow 2018年年度调查报告,JavaScript已经连续6年保持最常用的编程语言的记录。对于一个全栈工程师,JavaScript可以说是一项必备语言,在面试中总会被问到。我整理了一下FullStack.Cafe上所有常见的JavaScript面试问题供大家参考:
Q1: JavaScript中类型转换是怎样的?
话题: JavaScript
难度: 0
在JavaScript中,在两个不同类型之间的转换叫做
coercion
。在JavaScript中有两种形式:显示转换和隐式转换。
下面是一个显示转换的例子:
var a = "42" ;var b = Number ( a );a; b;
下面是一个隐式转换的例子:
var a = "42" ;var b = a * 1 ; a; b;
来源: FullStack.Cafe
Q2: JavaScript中的作用域是怎样的?
话题: JavaScript
难度: ⭐
在JavaScript中,每一个函数都有各自的作用域(
scope
)。作用域可以理解为是一个变量的集合以及相应的如何访问它的规则。只有在函数内部的变量才可以访问到该函数域的变量。
在同一个作用域内部,变量名必须要唯一。作用域可以嵌套。在最内部的作用域中,可以访问任何外部的作用域中的变量。
Q3: 请解释JavaScript中的相等判断
话题: JavaScript
难度: ⭐
JavaScript中的相等判断有严格判断和带隐式转换的判断两种:
var a = "42" ;var b = 42 ;a == b; a === b;
一些简单的规则:
如果两边都是布尔类型的值,使用
===
;
如果两边是0,
""
,
[]
,使用
===
;
所有其它类型,使用
==
是安全的。而且在很多情况下会简化代码、增加可读性。
Q4: 请解释什么叫做回调函数并提供一个简单的例子
话题: JavaScript
难度: ⭐⭐
回调函数是一个函数,它被作为参数传入另一个函数,当某些操作结束后,该函数被调用。下面是一个简单的例子,当数组被修改后,调用回调函数打印一行日志。
function modifyArray (arr, callback ) { arr.push(100 ); callback(); } var arr = [1 , 2 , 3 , 4 , 5 ];modifyArray(arr, function ( ) { console .log("array has been modified" , arr); });
Q5: “use strict”到底有何用处?
话题: 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 ; }
Q6: 请解释Null和Undefined
话题: JavaScript
难度: ⭐⭐
JavaScript和TypeScript有两个最基本的类型
null
和
undefined
。它们的含义是不同的:
如果还没有被初始化,则是
undefined
;
如果不可用,则可以用
null
来表示;
Q7: 请实现如下函数
话题: JavaScript
难度: ⭐⭐
var addSix = createBase(6 );addSix(10 ); addSix(21 );
addSix
是一个函数,也就是说createBase函数的返回是一个函数。
function createBase (baseNumber ) { return function (N ) { return baseNumber + N; } } var addSix = createBase(6 );addSix(10
); addSix(21 );
Q8: 请解释JavaScript中的值和类型
话题: JavaScript
难度: ⭐⭐
下面是JavaScript内置的可用类型:
string
number
boolean
null和undefined
object
symbol (ES6的新语法)
Q9: 请解释事件冒泡以及如何阻止它?
话题: JavaScript
难度: ⭐⭐
事件冒泡的概念是指:在最内层的元素上绑定的事件被触发后,会按照嵌套的层次由内向外逐步触发。因此,点击某个孩子节点可能会触发父节点的事件。
一个阻止事件冒泡的办法就是使用
event.stopPropagation()
,在IE<9的浏览器上使用
event.cancelBubble()
。
来源:https://github.com/kennymkchan
Q10. 请解释JavaScript中的let关键字
话题: JavaScript
难度: ⭐⭐
ES6允许你使用let关键字来申明块作用域(
{...}
)的变量。
来源: github.com/getify
Q11: 如何检查一个数字是否是整数?
话题: JavaScript
难度: ⭐⭐
一个最简单的方法是判断除以1的余数是否为0.
function isInt (num ) { return num % 1 === 0 ; } console .log(isInt(4 )); console .log(isInt(12.2 )); console .log(isInt(0.3 ));
来源: coderbyte.com
Q12: 什么叫IIFEs(Immediately Invoked Function Expressions)?
话题: JavaScript
难度: ⭐⭐
IIFE叫做立即执行表达式,顾名思义,该表达式一被创建就立即执行。
(function IIFE ( ) { console .log( "Hello!"
); })();
该方法常用语避免污染全局的命名空间,因为所以在IIFE中使用的变量外部都无法访问。
来源: stackoverflow.com
Q13: 如果比较JavaScript中的两个对象?
话题: JavaScript
难度: ⭐⭐
两个非基本类型的值,比如对象(包括函数和数组)都是通过引用的形式来访问。如果直接通过
==
和
===
来判断,那么只会简单的判断其引用地址是否相同,而不是它们实际对应的值。
如果数组和字符串做比较,那么数组会通过逗号拼接转换为字符串。通过等号判断的时候,两个相同的数组不会相等,但是和相同数据的字符串比较反而相等。
var a = [1 ,2 ,3 ];var b = [1 ,2 ,3 ];var c = "1,2,3" ;a == c; b == c; a == b;
如果要深度比较,可以使用第三方库,比如
deep-equal
或则你自己实现一个比较算法。
Q14: 请解释ES5和ES6的不同点
话题: JavaScript
难度: ⭐⭐⭐
接下来介绍它们主要的区别:
const greetings = (name ) => { return `hello ${name} ` ; }
甚至:
const greetings = name => `hello ${name} ` ;
const NAMES = [];NAMES.push("Jim" ); console .log(NAMES.length === 1 ); NAMES = ["Steve" , "John" ];
function multiply (a, b = 2 ) { return a * b; } multiply(5 );
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' ;
来源: Bulby.io
Q15: 请解释
undefined
和
not defined
的区别
话题: JavaScript
难度: ⭐⭐⭐
在JavaScript中,如果你尝试使用不存在的还未申明的变量,JavaScript会抛出错误
var name is not defined
。但是如果你用
typeof
来查看其类型,会返回
undefined
。
我们先来澄清一下声明和定义的区别:
var x
是一个声明,因为你并没有定义其具体的值,你只是声明其存在性。
var x = 1
同时兼具声明和定义,我们也可以叫它初始化。在JavaScript中,每一个变量和函数声明都会被提升到顶部。
如果我们访问一个声明了但是未定义的变量,会返回
undefined
。
var x; if (typeof x === 'undefined' )
访问一个未声明未定义的变量,会返回not defined错误。
来源: stackoverflow.com
Q16: 匿名函数和命名函数的区别?
话题: JavaScript
难度: ⭐⭐⭐
var foo = function ( ) { }; var x = function bar ( ) { }; foo(); x();
译者补充:匿名函数如果不赋值给某个变量,则无法被调用了;命名函数再次被赋值不是多此一举么。
Q17: JavaScript中闭包是什么?请提供一个例子
话题: JavaScript
难度: ⭐⭐⭐⭐
闭包是一个定义在其它函数(父函数)里面的函数,它拥有对父函数里面变量的访问权。闭包拥有如下三个作用域的访问权:
var globalVar = "abc" ;(function outerFunction (outerArg ) { var outerFuncVar = 'x' ; (function innerFunction (innerArg ) { var innerFuncVar = "y" ; console .log( "outerArg = " + outerArg + "\n" + "outerFuncVar = " + outerFuncVar + "\n" + "innerArg = " + innerArg + "\n" + "innerFuncVar = " + innerFuncVar + "\n" + "globalVar = " + globalVar); })(5 ); })(7 );
innerFunction
是一个闭包,定义在
outerFunction
中,它可以访问
outerFunction
作用域的所有变量。当然,它还可以访问全局变量。
输出结果如下:
outerArg = 7
outerFuncVar = x innerArg = 5 innerFuncVar = y globalVar = abc
来源: github.com/ganqqwerty
Q18: 在JavaScript中如何创建私有变量?
话题: JavaScript
难度: ⭐⭐⭐⭐
你可以通过在函数中声明变量来创建私有变量。因为在函数中,外部无法直接访问。
function func ( ) { var priv = "secret code" ; } console .log(priv);
为了访问该变量,可以构造一个帮助函数来返回该值。
function func ( ) { var priv = "secret code" ; return function ( ) { return priv; } } var getPriv = func();console .log(getPriv());
来源:coderbyte.com
Q19: 请解释原型模式(Prototype Design Pattern)
话题: JavaScript
难度: ⭐⭐⭐⭐
原型模式会创建一个新的对象,但不是创建一个未初始化的对象,而是通过拷贝原型链上的值或则被拷贝对象的值来完成初始化。传统的语言很少使用原型模式,但是JavaScript作为一个基于原型的语言,使用原型模式来创建新的对象。
来源: dofactory.com
Q20: 判断给定的字符串是否同态(isomorphic)
话题: JavaScript
难度: ⭐⭐⭐⭐
首先介绍什么叫做同态:两个字符串,如果A字符串中的每一个字符都可以在B字符串中找到唯一对应,并且顺序一一对应;如果存在这样的函数,那么A和B同态。
paper
和
title
同态
egg
和
sad
不同态
dgg
和
add
同态
isIsomorphic("egg" , 'add' ); isIsomorphic("paper" , 'title' ); isIsomorphic("kick" , 'side' ); function isIsomorphic (firstString, secondString ) { 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 (letterMap[letterA] === undefined ) { letterMap[letterA] = letterB; } else if