百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

JavaScript九大面试问题集锦,助你顺利通关

bigegpt 2024-10-19 02:52 46 浏览

全文共6287字,预计学习时长20分钟或更长



人们认为JavaScript是最适合初学者的语言。一部分原因在于JavaScript在互联网中运用广泛,另一部分原因在于其自身特性使得即使编写的代码不那么完美依然可以运行:无论是否少了一个分号或是内存管理问题,它都不像许多其他语言那样严格,但在开始学习之前,要确保你已经知道JavaScript的来龙去脉,包括可以自动完成的事情和“幕后”的操作。


本文将介绍一些面试时关于JavaScript的常见问题,以及一些突发难题。当然,每次面试都是不同的,你也可能不会遇见这类问题。但是知道的越多,准备的就越充分。


第一部分:突发难题


如果在面试中突然问到下列问题,似乎很难回答。即便如此,这些问题在准备中仍发挥作用:它们揭示了JavaScript的一些有趣的功能,并强调在提出编程语言时,首先必须做出的一些决定。


了解有关JavaScript的更多功能,建议访问https://wtfjs.com。


1. 为什么Math.max()小于Math.min()?


Math.max()> Math.min()输出错误这一说法看上去有问题,但其实相当合理。


如果没有给出参数,Math.min()返回infinity(无穷大),Math.max()返回-infinity(无穷小)。这只是max()和min()方法规范的一部分,但选择背后的逻辑值得深议。了解其中原因,请看以下代码:

Math.min(1) // 1
Math.min(1, infinity)// 1
Math.min(1, -infinity)// -infinity


如果-infinity(无穷小)作为Math.min()的默认参数,那么每个结果都是-infinity(无穷小),这毫无用处! 然而,如果默认参数是infinity(无穷大),则无论添加任何参数返回都会是该数字 - 这就是我们想要的运行方式。


2. 为什么0.1+0.2不等于0.3


简而言之,这与JavaScript在二进制中存储浮点数的准确程度有关。在Google Chrome控制台中输入以下公式将得到:

0.1 + 0.2// 0.30000000000000004
 
0.1 + 0.2 - 0.2// 0.10000000000000003
 
0.1 + 0.7// 0.7999999999999999


如果是简单的等式,对准确度没有要求,这不太可能产生问题。但是如果需要测试相等性,即使是简单地应用也会导致令人头疼的问题。解决这些问题,有以下几种方案。


Fixed Point固定点


例如,如果知道所需的最大精度(例如,如果正在处理货币),则可以使用整数类型来存储该值。因此,可以存储499而非4.99美元,并在此基础上执行任何等式,然后可以使用类似result =(value / 100).toFixed(2)的表达式将结果显示给最终用户,该表达式返回一个字符串。


BCD代码


如果精度非常重要,另一种方法是使用二进制编码的十进制(BCD)格式,可以使用BCD库(https://formats.kaitai.io/bcd/javascript.html)访问JavaScript。每个十进制值分别存储在一个字节(8位)中。鉴于一个字节可以存储16个单独值,而该系统仅使用0-9位,所以这种方法效率低下。但是,如果十分注重精确度,采用何种方法都值得考量。


3. 为什么018减017等于3?


018-017返回3实际是静默类型转换的结果。这种情况,讨论的是八进制数。


八进制数简介


你或许知道计算中使用二进制(base-2)和十六进制(base-16)数字系统,但是八进制(base-8)在计算机历史中的地位也举足亲重:在20世纪50年代后期和 20世纪60年代间,八进制被用于简化二进制,削减高昂的制造系统中的材料成本。


不久以后Hexadecimal(十六进制)开始登上历史舞台:

1965年发布的IBM360迈出了从八进制到十六进制的决定性一步。我们这些习惯八进制的人对这一举措感到震惊!沃恩·普拉特(Vaughan Pratt)


如今的八进制数


但在现代编程语言中,八进制又有何作用呢?针对某些案例,八进制比十六进制更具优势,因为它不需要任何非数字(使用0-7而不是0-F)。

一个常见用途是Unix系统的文件权限,其中有八个权限变体:

4 2 1

0 - - - no permissions

1 - - x only execute

2 - x - only write

3 - x x write and execute

4 x - - only read

5 x - x read and execute

6 x x - read and write

7 x x x read, write and execute

出于相似的原由,八进制也用于数字显示器。


回到问题本身


在JavaScript中,前缀0将所有数字转换为八进制。但是,八进制中不使用数字8,任何包含8的数字都将自动转换为常规十进制数。

因此,018-017实际上等同于十进制表达式:18-15,因为017使用八进制而018使用十进制。

第二部分:常见问题



本节中,将介绍面试中一些更加常见的JavaScript问题。第一次学习JavaScript时,这些问题容易被忽略。但在编写最佳代码时,了解下述问题用处颇大。


4. 函数表达式与函数声明有哪些不同?


函数声明使用关键字function,后跟函数的名称。相反,函数表达式以var,let或const开头,后跟函数名称和赋值运算符=。请看以下代码:


// Function Declaration
function sum(x, y) {
 return x + y;
};
// Function Expression: ES5
var sum = function(x, y) {
 return x + y;
};
 
// Function Expression: ES6+
const sum = (x, y) => { return x + y };


实际操作中,关键的区别在于函数声明要被提升,而函数表达式则没有。这意味着JavaScript解释器将函数声明移动到其作用域的顶部,因此可以定义函数声明并在代码中的任何位置调用它。相比之下,只能以线性顺序调用函数表达式:必须在调用它之前解释。

如今,许多开发人员偏爱函数表达式有如下几个原因:

· 首先,函数表达式实施更加可预测的结构化代码库。当然,函数声明也可使用结构化代码库; 只是函数声明让你更容易摆脱凌乱的代码。

· 其次,可以将ES6语法用于函数表达式:这通常更为简洁,let和const可以更好地控制是否重新赋值变量,我们将在下一个问题中看到。


5. var,let和const有什么区别?


自ES6发布以来,现代语法已进入各行各业,这已是一个极其常见的面试问题。Var是第一版JavaScript中的变量声明关键字。但它的缺点导致在ES6中采用了两个新关键字:let和const。


这三个关键字具有不同的分配,提升和域 - 因此我们将单独讨论。


i) 分配


最基本的区别是let和var可以重新分配,而const则不能。这使得const成为不变变量的最佳选择,并且它将防止诸如意外重新分配之类的失误。注意,当变量表示数组或对象时,const确实允许变量改变,只是无法重新分配变量本身。


Let 和var都可重新分配,但是正如以下几点应该明确的那样,如果不是所有情况都要求更改变量,多数选择中,let具有优于var的显著优势。


ii)提升


与函数声明和表达式(如上所述)之间的差异类似,使用var声明的变量总是被提升到它们各自的顶部,而使用const和let声明的变量被提升,但是如果你试图在声明之前访问,将会得到一个TDZ(时间死区)错误。由于var可能更容易出错,例如意外重新分配,因此运算是有用的。请看以下代码:

var x = "global scope";
function foo() {
 var x = "functional scope";
 console.log(x);
}
foo(); // "functional scope"
console.log(x); // "global scope"


这里,foo()和console.log(x)的结果与预期一致。但是,如果去掉第二个变量又会发生什么呢?

var x = "global scope";
function foo() {
 x = "functional scope";
 console.log(x);
}
foo(); // "functional scope"
console.log(x); // "functional scope"


尽管在函数内定义,但x =“functional scope”已覆盖全局变量。需要重复关键字var来指定第二个变量x仅限于foo()。


iii) 域


虽然var是function-scoped(函数作用域),但let和const是block-scoped(块作用域的:一般情况下,Block是大括号{}内的任何代码,包括函数,条件语句和循环。为了阐明差异,请看以下代码:

var a = 0;
let b = 0;
const c = 0;
if (true) {
 var a = 1;
 let b = 1;
 const c = 1;
}
console.log(a); // 1
console.log(b); // 0
console.log(c); // 0


在条件块中,全局范围的var a已重新定义,但全局范围的let b和const c则没有。一般而言,确保本地任务保持在本地执行,将使代码更加清晰,减少出错。


6. 如果分配不带关键字的变量会发生什么?


如果不使用关键字定义变量,又会如何?从技术上讲,如果x尚未定义,则x = 1是window.x = 1的简写。


要想完全杜绝这种简写,可以编写严格模式,——在ES5中介绍过——在文档顶部或特定函数中写use strict。后,当你尝试声明没有关键字的变量时,你将收到一条报语法错误:Uncaught SyntaxError:Unexpected indentifier。


7. 面向对象编程(OOP)和函数式编程(FP)之间的区别是什么?


JavaScript是一种多范式语言,即它支持多种不同的编程风格,包括事件驱动,函数和面向对象。


编程范式各有不同,但在当代计算中,函数编程和面向对象编程最为流行 - 而JavaScript两种都可执行。


面向对象编程


OOP以“对象”这一概念为基础的数据结构,包含数据字段(JavaScript称为类)和程序(JavaScript中的方法)。


一些JavaScript的内置对象包括Math(用于random,max和sin等方法),JSON(用于解析JSON数据)和原始数据类型,如String,Array,Number和Boolean。


无论何时采用的内置方法,原型或类,本质上都在使用面向对象编程。


函数编程


FP(函数编程)以“纯函数”的概念为基础,避免共享状态,可变数据和副作用。这可能看起来像很多术语,但可能已经在代码中创建了许多纯函数。


输入相同数据,纯函数总是返回相同的输出。这种方式没有副作用:除了返回结果之外,例如登录控制台或修改外部变量等都不会发生。


至于共享状态,这里有一个简单的例子,即使输入是相同的,状态仍可以改变函数的输出。设置一个具有两个函数的代码:一个将数字加5,另一个将数字乘以5。

const num = {
 val: 1
};
const add5 = () => num.val += 5;
const multiply5 = () => num.val *= 5;


如果先调用add5在调用乘以5,则整体结果为30。但是如果以相反的方式执行函数并记录结果,则输出为10,与之前结果不一致。


这违背了函数式编程的原理,因为函数的结果因Context调用方法而异。 重新编写上面的代码,以便结果更易预测:

const num = {
 val: 1
};
const add5 = () => Object.assign({}, num, {val: num.val + 5}); const multiply5 = () => Object.assign({}, num, {val: num.val * 5});


现在,num.val的值仍然为1,无论Context调用的方法如何,add5(num)和multiply5(num)将始终输出相同的结果。


8. 命令式和声明性编程之间有什么区别?


关于命令式编程和声明式编程的区别,可以以OOP(面向对象编程)和FP(函数式编程)为参考。


这两种是描述多种不同编程范式共有特征的概括性术语。FP(函数式编程)是声明性编程的一个范例,而OOP(面向对象编程)是命令式编程的一个范例。


从基本的意义层面,命令式编程关注的是如何做某事。它以最基本的方式阐明了步骤,并以for和while循环,if和switch陈述句等为特征。

const sumArray = array => {
 let result = 0;
 for (let i = 0; i < array.length; i++) {
 result += array[i]
 };
 return result;
}


相比之下,声明性编程关注的是做什么,它通过依赖表达式将怎样做抽出来。这通常会产生更简洁的代码,但是在规模上,由于透明度低,调试会更加困难。


这是上述的sumArray()函数的声明方法。

const sumArray = array => { return array.reduce((x, y) => x + y) };



9. 是什么基于原型的继承?


最后,要讲到的是基于原型的继承。面向对象编程有几种不同的类型,JavaScript使用的是基于原型的继承。该系统通过使用现有对象作为原型,允许重复运行。


即使是首次遇到原型这一概念,使用内置方法时也会遇到原型系统。 例如,用于操作数组的函数(如map,reduce,splice等)都是Array.prototype对象的方法。实际上,数组的每个实例(使用方括号[]定义,或者 -不常见的 new Array())都继承自Array.prototype,这就是为什么map,reduce和spliceare等方法都默认可用的原因。


几乎所有内置对象都是如此,例如字符串和布尔运算:只有少数,如Infinity,NaN,null和undefined等没有类或方法。


在原型链的末尾,能发现 Object.prototype,几乎JavaScript中的每个对象都是Object的一个实例。比如Array. prototype和String. prototype都继承了Object.prototype的类和方法。


要想对使用prototype syntax的对象添加类和方法,只需将对象作为函数启动,并使用prototype关键字添加类和方法:

function Person() {};
Person.prototype.forename = "John";
Person.prototype.surname = "Smith";


是否应该覆盖或扩展原型运算?


可以使用与创建扩展prototypes同样的方式改变内置运算,但是大多数开发人员(以及大多数公司)不会建议这样做。


如果希望多个对象进行同样的运算,可以创建一个自定义对象(或定义你自己的“类”或“子类”),这些对象继承内置原型而不改变原型本身。如果打算与其他开发人员合作,他们对JavaScript的默认行为有一定的预期,编辑此默认行为很容易导致出错。


总的来说,这些问题能够帮助你更好理解JavaScript,包括其核心功能和其他鲜为人知的功能 ,并且望能助你为下次的面试做好准备。

留言 点赞 关注

我们一起分享AI学习与发展的干货

欢迎关注全平台AI垂类自媒体 “读芯术”

相关推荐

得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践

一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...

warm-flow新春版:网关直连和流程图重构

本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...

扣子空间体验报告

在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...

spider-flow:开源的可视化方式定义爬虫方案

spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...

solon-flow 你好世界!

solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...

新一代开源爬虫平台:SpiderFlow

SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...

通过 SQL 训练机器学习模型的引擎

关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...

鼠须管输入法rime for Mac

鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...

Go语言 1.20 版本正式发布:新版详细介绍

Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...

iOS 10平台SpriteKit新特性之Tile Maps(上)

简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...

程序员简历例句—范例Java、Python、C++模板

个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...

Telerik UI for iOS Q3 2015正式发布

近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...

ios使用ijkplayer+nginx进行视频直播

上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...

IOS技术分享|iOS快速生成开发文档(一)

前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...

macOS下配置VS Code C++开发环境

本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...