JavaScript23道 面试题

mac2024-04-15  32

1.num的值是什么?

const num = parseInt("7*6",10); A: 42B: “42”C: 7D: NaN

答案:C

只返回了字符串中第一个字母,设定了进制后(也就是第二个参数,指定需要解析的数字是什么进制:二进制、八进制、十进制、十六进制等等…),parseInt检查字符串中的字符是否合法,一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。

*就是不合法的数字字符。所以只解析到"7",并将其解析为十进制的7,num的值即为7


2.下面代码的输出是什么?

let person = { name:"Lydia" }; const members = [person]; person = null; console.log(members); A: nullB: [null]C: [{ }]D: [{ name:“Lydia” }]

答案:D

首先我们声明了一个拥有 name属性的对象person。

然后我们又声明了一个变量 members. 将首个元素赋值为变量 person。当设置两个对象彼此相等时,它们会通过 引用 进行交互。但是当你将引用从一个变量分配至另一个变量时,其实只是执行了一个 复制 操作。(注意一点,他们的引用 并不相同!) 接下来我们让 person等于 null。 我们没有修改数组第一个元素的值,而只是修改了变量 person的值,因为元素(复制而来)的引用与 person不同。members的第一个元素仍然保持着对原始对象的引用。当我们输出 members数组时,第一个元素会将引用的对象打印出来。


3.下面代码的输出是什么?

function Car(){ this.make = "AAA"; return { make:"BBB" }; } const myCar = new Car(); console.log(myCar.make); A: “AAA”B: “BBB”C: ReferenceErrorD: TypeError

答案:B

返回属性的时候,属性的值等于 返回的 值,而不是构造函数中设定的值。我们返回了字符串 "BBB",所以 myCar.make等于 "BBB".


4.下面代码的输出是什么?

(() => { let x = (y = 10); })(); console.log(typeof x); console.log(typeof y); A: “undefined”,“number”B: “number”,“number”C: “object”,“number”D: “number”,undefined

答案:A

let x=y=10; 是下面这个表达式的缩写:

y = 10; let x = y;

我们设定 y等于 10时,我们实际上增加了一个属性 y给全局对象(浏览器里的 window, Nodejs里的 global)。在浏览器中, window.y等于 10.

然后我们声明了变量 x等于 y,也是10.但变量是使用 let声明的,它只作用于 块级作用域, 仅在声明它的块中有效;就是案例中的立即调用表达式(IIFE)。使用typeof操作符时, 操作值 x没有被定义:因为我们在 x声明块的外部,无法调用它。这就意味着 x未定义。未分配或是未声明的变量类型为 "undefined". console.log(typeofx)返回 "undefined".

而我们创建了全局变量 y,并且设定 y等于 10.这个值在我们的代码各处都访问的到。y已经被定义了,而且有一个 "number"类型的值。console.log(typeofy)返回"number".


5.下面代码的输出是什么?

class Dog { constructor(name){ this.name = name } } Dog.prototype.bark = function(){ console.log(`Woof I am ${this.name}`); }; const pet = new Dog("Mara"); pet.bark(); delete Dog.prototype.bark; pet.bark(); A: “Woof I am Mara”,TypeErrorB: “Woof I am Mara”,“Woof I am Mara”C: “Woof I am Mara”,undefinedD: TypeError,TypeError

答案:A

我们可以用 delete关键字删除对象的属性,对原型也是适用的。删除了原型的属性后,该属性在原型链上就不可用了。在本例中,函数 bark在执行了 deleteDog.prototype.bark后不可用, 然而后面的代码还在调用它。

当我们尝试调用一个不存在的函数时 TypeError异常会被抛出。在本例中就是 TypeError:pet.barkisnotafunction,因为 pet.bark是 undefined.


6.下面代码的输出是什么?

const set = new Set([1,1,2,3,4]); console.log(set); A: [1,1,2,3,4]B: [1,2,3,4]C: {1,1,2,3,4}D: {1,2,3,4}

答案:D

Set对象手机 独一无二 的值:也就是说同一个值在其中仅出现一次。

我们传入了数组 [1,1,2,3,4],他有一个重复值 1.以为一个集合里不能有两个重复的值,其中一个就被移除了。所以结果是 {1,2,3,4}.


7.下面代码的输出是什么?

// counter.js let counter = 10; export default counter; // index.js import myCounter from './counter'; myCounter += 1; console.log(myCounter); A: 10B: 11C: ErrorD: NaN

答案:C

引入的模块是 只读 的: 你不能修改引入的模块。只有导出他们的模块才能修改其值。

当我们给 myCounter增加一个值的时候会抛出一个异常:myCounter是只读的,不能被修改


8.下面代码的输出是什么?

const name = "Lydia"; age = 21; console.log(delete name); console.log(delete age); A: false,trueB: “Lydia”,21C: true,trueD: undefined,undefined

答案:A

delete操作符返回一个布尔值:true指删除成功,否则返回 false. 但是通过 var, const或let关键字声明的变量无法用 delete操作符来删除。

name变量由 const关键字声明,所以删除不成功:返回 false. 而我们设定 age等于 21时,我们实际上添加了一个名为 age的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以 deleteage返回 true.


9.下面代码的输出是什么?

const numbers = [1,2,3,4,5]; const [y] = numbers; console.log(y); A: [ [1,2,3,4,5] ]B: [1,2,3,4,5]C: 1D: [1]

答案:C

我们可以通过解构赋值来解析来自对象的数组或属性的值,比如说:

[a,b] = [1,2]

a的值现在是 1, b的值现在是 2.而在题目中,我们是这么做的:

[y] = [1,2,3,4,5];

也就是说, y等于数组的第一个值就是数字 1.我们输出 y, 返回 1


10.下面代码的输出是什么?

const user = { name:"Lydia",age:21 }; const admin = { admin:true,...user }; console.log(admin) A: { admin:true,user:{ name:“Lydia”,age:21 } }B: { admin:true,name:“Lydia”,age:21 }C: { admin:true,user:[“Lydia”,21] }D: { admin:true }

答案:B

扩展运算符 ...为对象的组合提供了可能。你可以复制对象中的键值对,然后把它们加到另一个对象里去。在本例中,我们复制了 user对象键值对,然后把它们加入到 admin对象中。admin对象就拥有了这些键值对,所以结果为 {admin:true,name:"Lydia",age:21}.


11.下面代码的输出是什么?

const person = { name:"Lydia" }; Object.defineProperty(person,"age",{ value:21 }); console.log(person); console.log(Object.keys(person)); A: { name:“Lydia”,age:21 },[“name”,“age”]B: { name:“Lydia”,age:21 },[“name”]C: { name:“Lydia” },[“name”,“age”]D: { name:“Lydia” },[“age”]

答案:B

通过 defineProperty方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用 defineProperty方法给对象添加了一个属性之后,属性默认为 不可枚举(not enumerable). Object.keys方法仅返回对象中 可枚举(enumerable) 的属性,因此只剩下了 "name".

用 defineProperty方法添加的属性默认不可变。你可以通过 writable, configurable 和 enumerable属性来改变这一行为。这样的话, 相比于自己添加的属性, defineProperty方法添加的属性有了更多的控制权。


12.下面代码的输出是什么?

const settings = { username:"lydiahallie", level:19, health:90 }; const data = JSON.stringify(settings,["level","health"]); console.log(data); A: “{“level”:19, “health”:90}”B: “{“username”: “lydiahallie”}”C: “[“level”, “health”]”D: “{“username”: “lydiahallie”, “level”:19, “health”:90}”

答案:A

JSON.stringify的第二个参数是 替代者(replacer). 替代者(replacer)可以是个函数或数组,用以控制哪些值如何被转换为字符串。

如果替代者(replacer)是个 数组 ,那么就只有包含在数组中的属性将会被转化为字符串。在本例中,只有名为 "level"和 "health" 的属性被包括进来, "username"则被排除在外。data就等于 "{"level":19, "health":90}".

而如果替代者(replacer)是个 函数,这个函数将被对象的每个属性都调用一遍。函数返回的值会成为这个属性的值,最终体现在转化后的JSON字符串中(译者注:Chrome下,经过实验,如果所有属性均返回同一个值的时候有异常,会直接将返回值作为结果输出而不会输出JSON字符串),而如果返回值为 undefined,则该属性会被排除在外。


13.下面代码的输出是什么?

let num = 10; const increaseNumber = () => num++; const increasePassedNumber = number => number++; const num1 = increaseNumber(); const num2 = increasePassedNumber(num1); console.log(num1); console.log(num2); A: 10,10B: 10,11C: 11,11D: 11,12

答案:A

一元操作符 ++先返回 操作值, 再累加 操作值。num1的值是 10, 因为 increaseNumber函数首先返回 num的值,也就是 10,随后再进行 num的累加。

num2是 10因为我们将 num1传入 increasePassedNumber. number等于 10( num1的值。同样道理, ++先返回 操作值, 再累加 操作值。) number是10,所以num2也是 10.


14.下面代码的输出是什么?

const value = { number:10 }; const multiply = (x = { ...value } => { console.log(x.number *= 2) }); multiply(); multiply(); multiply(value); multiply(value); A: 20,40,80,160B: 20,41,20,40C: 20,20,20,40D: NaN,NaN,20,40

答案:C

在ES6中,我们可以使用默认值初始化参数。如果没有给函数传参,或者传的参值为 "undefined" ,那么参数的值将是默认值。上述例子中,我们将 value 对象进行了解构并传到一个新对象中,因此 x的默认值为 {number:10} 。

默认参数在调用时才会进行计算,每次调用函数时,都会创建一个新的对象。我们前两次调用multiply函数且不传递值,那么每一次 x的默认值都为{number:10},因此打印出该数字的乘积值为 20。

第三次调用 multiply时,我们传递了一个参数,即对象 value。*=运算符实际上是 x.number=x.number*2的简写,我们修改了 x.number的值,并打印出值 20。

第四次,我们再次传递 value对象。x.number之前被修改为 20,所以 x.number*=2打印为40


15.下面代码的输出是什么?

[1,2,3,4].reduce((x,y) => console.log(x,y)) A: 1 2 , 3 3 , 6 4B: 1 2 , 2 3 , 3 4C: 1 undefined , 2 undefined , 3 undefined , 4 undefinedD: 1 2 , undefined 3 , undefined 4

答案:D

reducer函数接收4个参数:

Accumulator (acc) (累计器)Current Value (cur) (当前值)Current Index (idx) (当前索引)Source Array (src) (源数组)

reducer 函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。

reducer 函数还有一个可选参数 initialValue, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供 initialValue,则将使用数组中的第一个元素。

在上述例子, reduce方法接收的第一个参数(Accumulator)是 x, 第二个参数(Current Value)是 y。

在第一次调用时,累加器 x为 1,当前值 “y”为 2,打印出累加器和当前值:1和2。

例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回undefined。在下一次调用时,累加器为undefined,当前值为“3”, 因此 undefined和 3被打印出。

在第四次调用时,回调函数依然没有返回值。累加器再次为 undefined ,当前值为“4”。undefined和 4被打印出。


16.使用哪个构造函数可以成功继承 Dog类?

class Dog { constructor(name){ this.name = name } }; class Labrador extends Dog { //1 constructor(name,size){ this.size = size } //2 constructor(name,size){ super(name); this.size = size; } //3 constructor(size){ super(name); this.size = size; } //4 constructor(name,size){ this.name = name; this.size = size; } }; A: 1B: 2C: 3D: 4

答案:B

在子类中,在调用 super之前不能访问到 this关键字。如果这样做,它将抛出一个 ReferenceError:1和4将引发一个引用错误。

使用 super关键字,需要用给定的参数来调用父类的构造函数。父类的构造函数接收 name参数,因此我们需要将 name传递给 super。

Labrador类接收两个参数, name参数是由于它继承了 Dog, size作为 Labrador类的额外属性,它们都需要传递给 Labrador的构造函数,因此使用构造函数2正确完成。


17.下面代码的输出是什么?

//index.js console.log('running index.js'); import { sum } from './sum.js'; console.log(sum(1,2)); //sum.js console.log('running sum.js'); export const sum = (a,b) => a + b; A: running index.js , running sum.js , 3B: running sum.js , running index.js , 3C: running sum.js , 3 , running index.jsD: running index.js , undefined , running sum.js

答案:B

import命令是编译阶段执行的,在代码运行之前。因此这意味着被导入的模块会先运行,而导入模块的文件会后执行。

这是CommonJS中 require()和import之间的区别。使用 require(),您可以在运行代码时根据需要加载依赖项。如果我们使用 require而不是 import, running index.js, running sum.js, 3会被依次打印。


18.下面代码的输出是什么?

console.log(Number(2) === Number(2)) console.log(Boolean(false) === Boolean(false)) console.log(Symbol('foo') === Symbol('foo')) A: true , true , falseB: false , true , falseC: true , false , trueD: true , true , true

答案:A

每个 Symbol都是完全唯一的。传递给 Symbol的参数只是给 Symbol的一个描述。Symbol的值不依赖于传递的参数。当我们测试相等时,我们创建了两个全新的符号:第一个 Symbol('foo'),第二个 Symbol('foo'), 这两个值是唯一的,彼此不相等,因此返回 false。


19.下面代码的输出是什么?

const name = "Lydia Hallie" console.log(name.padStart(13)) console.log(name.padStart(2)) A: “Lydia Hallie” , “Lydia Hallie”B: " Lydia Hallie" , " Lydia Hallie" ( “[13x whitespace]Lydia Hallie”, “[2x whitespace]Lydia Hallie”)C: " Lydia Hallie" , “Lydia Hallie” ( “[1x whitespace]Lydia Hallie”, “Lydia Hallie”)D: “Lydia Hallie” , “Lyd”

答案:C

使用 padStart方法,我们可以在字符串的开头添加填充。传递给此方法的参数是字符串的总长度(包含填充)。字符串 Lydia Hallie的长度为 12, 因此 name.padStart(13)在字符串的开头只会插入1( 13-12=1)个空格。

如果传递给 padStart方法的参数小于字符串的长度,则不会添加填充。


20.下面代码的输出是什么?

console.log("🥑"+"💻"); A: 🥑💻B: 257548C: A string containing their code pointsD: Error

答案:A

使用 +运算符,您可以连接字符串。上述情况,我们将字符串 “🥑”与字符串 ”💻“连接起来,产生 ”🥑💻“。


21.如何能打印出 console.log语句后注释掉的值?

console.log(String.raw`Hello\nworld`) A: Helloworld!B: Hello worldC: Hello\nworldD: ==Hello\n == world

答案:C

String.raw函数是用来获取一个模板字符串的原始字符串的,它返回一个字符串,其中忽略了转义符( \n,\v,\t等)。但反斜杠可能造成问题,因为你可能会遇到下面这种类似情况:

const path = `C:\Documents\Projects\table.html` String.raw`${path}`

这将导致 C:DocumentsProjects able.html 直接使用 String.raw

String.raw`C:\Documents\Projects\table.html`

它会忽略转义字符并打印:C:\Documents\Projects\table.html 上述情况,字符串是 Hello\nworld被打印出


22.下面代码的输出是什么?

async function getData(){ return await Promise.resolve("I made it!"); } const data = getData(); console.log(data); A: “I made it!”B: Promise { <resolved> : “I made it!” }C: Promise{ <pending> }D: undefined

答案:C

异步函数始终返回一个promise。await仍然需要等待promise的解决:当我们调用 getData()并将其赋值给 data,此时 data为 getData方法返回的一个挂起的promise,该promise并没有解决。

如果我们想要访问已解决的值 "I made it!",可以在 data上使用.then()方法: data.then(res=>console.log(res)) 这样将打印 "I made it!"


23.下面代码的输出是什么?

function addToList(item,list){ return list.push(item) } const result = addToList("apple",["banana"]); console.log(result); A: [‘apple’,‘banana’]B: 2C: trueD: undefined

答案:B

push()方法返回新数组的长度。一开始,数组包含一个元素(字符串 "banana"),长度为1。在数组中添加字符串 "apple"后,长度变为2,并将从 addToList函数返回。

push方法修改原始数组,如果你想从函数返回数组而不是数组长度,那么应该在push item之后返回list。

最新回复(0)