当前位置: 首页 > 科技观察

九道JavaScript面试题合集,助你顺利过关!

时间:2023-03-16 15:00:16 科技观察

JavaScript被认为是最适合初学者的语言。这部分是由于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)//1Math.min(1,infinity)//1Math.min(1,-infinity)//-infinityif-infinity(无限小)asMath.min(),那么每一个结果都是-infinity(无限小),没用!但是,如果默认参数是无穷大(infinity),那么无论添加什么参数,返回的都将是那个数字——这就是我们想要的操作方式。2.为什么0.1+0.2不等于0.3简单来说,这与JavaScript以二进制存储浮点数的准确度有关。在GoogleChrome控制台中输入以下公式将得到:0.1+0.2//0.300000000000000040.1+0.2-0.2//0.100000000000000030.1+0.7//0.7999999999999999如果它是一个简单的方程式,对精度没有要求,这不太可能导致问题。但是,如果需要进行相等性测试,即使是一个简单的应用程序也会导致令人头疼的问题。要解决这些问题,有以下选项。(1)FixedPoint例如,如果你知道你需要的最大精度(例如,如果你正在处理货币),你可以使用整数类型来存储值。因此,可以存储499美元而不是4.99美元,并在此基础上执行任何方程式,然后可以使用类似result=(value/100).toFixed(2)的表达式将结果显示给最终用户,它返回一个细绳。(2)BCD代码如果精度很重要,另一种方法是使用二进制编码的十进制(BCD)格式,可以使用BCD库在JavaScript中访问它(https://formats.kaitai.io/bcd/javascript.html).每个十进制值单独存储在一个字节(8位)中。这是低效的,因为一个字节可以存储16个单独的值,而系统只使用0-9位。但是,如果精度最重要,那么任何一种方法都值得考虑。3、为什么018减去017等于3?018-017返回的3其实是silent类型转换的结果。在这种情况下,我们谈论的是八进制数。(1)八进制数简介大家可能知道计算中使用二进制(base-2)和十六进制(base-16)数制,但八进制(base-8)在计算机历史上也占有重要地位:在晚期1950年代和60年代,八进制被用来简化二进制,降低昂贵制造系统的材料成本。不久之后,Hexadecimal(十六进制)开始走上历史舞台:1965年发布的IBM360从八进制到十六进制迈出了决定性的一步。我们这些习惯八进制的人对这一举动感到震惊!作者VaughanPratt(2)今天的八进制数但是八进制在现代编程语言中有什么作用?在某些情况下,八进制比十六进制更有优势,因为它不需要任何非数字(使用0-7而不是0-F)。一个常见的用途是Unix系统上的文件权限,其中有八种权限变体:4210---没有权限1--x只执行2-x-只写3-xx只写和执行4x--只读取5x-x读取和执行6xx-读取和写入7xxx读取、写入和执行出于类似原因,八进制也用于数字显示。(3)回到问题本身在JavaScript中,前缀0将所有数字都转换为八进制。但是,数字8不用于八进制,任何包含8的数字都会自动转换为常规十进制数。因此,018-017实际上等价于十进制表示:18-15,因为017是八进制,018是十进制。第二部分:常见问题在本节中,将介绍一些在面试中常见的JavaScript问题。这些问题在初学JavaScript时很容易被忽略。但是,在写***代码的时候,知道下面的问题还是很有用的。4.函数表达式与函数声明有何不同?函数声明使用关键字function后跟函数名称。相反,函数表达式以var、let或const开头,后跟函数名称和赋值运算符=。请看下面的代码://FunctionDeclarationfunctionsum(x,y){returnx+y;};//FunctionExpression:ES5varsum=function(x,y){returnx+y;};//FunctionExpression:ES6+constsum=(x,y)=>{returnx+y};在实践中,关键区别在于函数声明被提升,而函数表达式则没有。这意味着JavaScript解释器将函数声明移至其范围的顶部,因此可以定义函数声明并从代码中的任何位置调用它。相比之下,函数表达式只能按线性顺序调用:在调用它之前必须对其进行解释。出于以下几个原因,如今许多开发人员更喜欢函数表达式:首先,函数表达式实现了更可预测的结构化代码库。当然,函数声明也适用于结构化代码库;只是函数声明让你更容易摆脱混乱的代码。其次,可以对函数表达式使用ES6语法:这通常更简洁,并且let和const可以更好地控制是否重新分配变量,正如我们将在下一个问题中看到的那样。5.var、let、const有什么区别?自ES6发布以来,现代语法进入了各行各业,这也成为了一道极其常见的面试题。var是最新版JavaScript中的变量声明关键字。但它的缺点导致在ES6中采用了两个新的关键字:let和const。这三个关键字具有不同的分配、促销和域-因此我们将分别讨论它们。(1)赋值最基本的区别是let和var可以重新赋值,而const不可以。这使得const成为不可变变量的最佳选择,并且可以防止意外重新分配等失误。注意,当变量表示数组或对象时,const确实允许变量发生变化,只是变量本身不能被重新赋值。let和var都是可重新赋值的,但正如以下几点应该清楚的那样,在大多数(如果不是所有)需要更改变量的情况下,let比var具有显着优势。(2)提升类似于函数声明和表达式的区别(如上),用var声明的变量总是被提升到它们各自的顶部,而用const和let声明的变量被提升,但是如果你试图访问之前该声明将出现TDZ(时间死区)错误。算术很有用,因为var更容易出错,例如意外重新分配。请看下面的代码:varx="globalscope";functionfoo(){varx="functionalscope";console.log(x);}foo();//"functionalscope"console.log(x);//"globalscope"这里,foo()和console.log(x)的结果符合预期。但是如果删除第二个变量会发生什么?varx="globalscope";functionfoo(){x="functionalscope";console.log(x);}foo();//"functionalscope"console.log(x);//"functionalscope"虽然在函数内部定义,x="functionalscope"已经覆盖了全局变量。需要重复关键字var以指定第二个变量x仅限于foo()。(3)Domain尽管var是function-scoped(函数作用域),但let和const是block-scoped(块作用域:一般来说,Block是花括号{}内的任何代码,包括函数、条件语句和循环。为了说明区别,看下面代码:vara=0;letb=0;constc=0;if(true){vara=1;letb=1;constc=1;}console.log(a);//1console.log(b);//0console.log(c);//0在条件块中,全局作用域vara被重新定义,但全局作用域letb和constc没有。一般来说,确保本地任务保持执行locally会导致更干净的代码和更少的错误。6.如果你分配一个没有关键字的变量会发生什么?如果你定义一个没有关键字的变量会怎样?从技术上讲,如果x尚未定义,那么x=1是window的简写.x=1。要完全消除这种简写,可以写严格模式,-在ES5中引入-在文档顶部或特定函数中写上usestrict。之后,当你尝试声明一个没有k的变量时关键字,您将收到一个语法错误:UncaughtSyntaxError:Unexpectedidentifier。7.面向对象编程(OOP)和函数式编程(FP)有什么区别?JavaScript是一种多范式语言,这意味着它支持多种不同的编程风格,包括事件驱动、函数式和面向对象。编程范式各不相同,但在当代计算中,函数式编程和面向对象都是可执行的。(1)面向对象编程OOP是一种基于“对象”概念的数据结构,包括数据域(在JavaScript中称为类)和程序(在JavaScript中称为方法)。一些JavaScript的内置对象包括Math(用于random、max和sin等方法)、JSON(用于解析JSON数据)和原始数据类型,如String、Array、Number和Boolean。无论何时使用内置方法、原型或类,本质上都是在使用面向对象编程。(2)函数式编程FP(FunctionalProgramming)基于“纯函数”的概念,避免共享状态、可变数据和副作用。这可能看起来有很多术语,但您的代码中可能已经创建了很多纯函数。给定相同的输入,纯函数总是返回相同的输出。这样就没有副作用:除了返回结果之外什么也不会发生,例如登录到控制台或修改外部变量。至于共享状态,这里有一个简单的例子,即使输入相同,状态也可以改变函数的输出。设置一个具有两个函数的代码:一个将数字加5,另一个将数字乘以5。constnum={val:1};constadd5=()=>num.val+=5;constmultiply5=()=>num.val*=5;如果先调用add5,再乘以5,则整体结果为30。但如果我们以相反的方式执行函数并记录结果,则输出为10,与之前的结果不一致。这违背了函数式编程的原则,因为函数的结果会根据调用该方法的上下文而变化。重写上面的代码,使结果更可预测:constnum={val:1};constadd5=()=>Object.assign({},num,{val:num.val+5});constmultiply5=()=>Object.assign({},num,{val:num.val*5});现在,num.val的值仍然是1,无论Context调用什么方法,add5(num)和multiply5(num)总是输出相同的结果。8.命令式编程和声明式编程有什么区别?关于命令式编程和声明式编程的区别,可以参考OOP(面向对象编程)和FP(函数式编程)。这两个是概括性术语,描述了许多不同编程范例的共同特征。FP(函数式编程)是声明式编程的一个例子,而OOP(面向对象编程)是命令式编程的一个例子。从根本上讲,命令式编程关注的是如何做某事。它阐明了最基本的步骤以及for和while循环、if和switch语句等功能。constsumArray=array=>{letresult=0;for(leti=0;i{returnarray.reduce((x,y)=>x+y)};9.什么是基于原型的继承?***,我想说的是基于原型的继承。有几种不同类型的面向对象编程,而JavaScript使用基于原型的继承。该系统允许通过使用现有对象作为原型来重新运行。即使你第一次接触到原型的概念,在使用内置方法时也会遇到原型系统。例如,操作数组的函数(如map、reduce、splice等)是Array.prototype对象的方法。事实上,数组的每个实例(使用方括号[]或-uncommonlynewArray()定义)都继承自Array.prototype,这就是为什么像map、reduce和spliceare这样的方法在默认情况下都可用。几乎所有内置对象都是如此,例如字符串和布尔运算:只有少数,例如Infinity、NaN、null和undefined等没有类或方法。在原型链的末尾,可以找到Object.prototype。几乎JavaScript中的每个对象都是Object的实例。例如,Array.prototype和String.prototype都继承了Object.prototype的类和方法。要使用原型语法向对象添加类和方法,只需将对象作为函数启动并使用原型关键字添加类和方法:functionPerson(){};Person.prototype.forename="John";Person.prototype.surname="史密斯";原型操作应该被覆盖还是扩展?可以像创建扩展原型一样更改内置操作,但大多数开发人员(和大多数公司)不建议这样做。如果你想让多个对象执行相同的操作,你可以创建一个自定义对象(或定义你自己的“类”或“子类”)继承内置原型而不改变原型本身。如果你打算与其他开发人员合作,他们对JavaScript的默认行为有一定的期望,而编辑这种默认行为很容易导致错误。总的来说,这些问题将帮助你更好地理解JavaScript,包括它的核心特性和其他鲜为人知的特性,并希望能帮助你为下一次面试做准备。