面试题带解析

事件传播的三个阶段是什么?

  • A: Target > Capturing > Bubbling
  • B: Bubbling > Target > Capturing
  • C: Target > Bubbling > Capturing
  • D: Capturing > Target > Bubbling

答案及解析

答案及解析

答案 : D 解析 : 在捕获(capturing)阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标(target)元素后,冒泡(bubbling)才开始。

写出执行结果,并解释原因

+true;
!"Lydia";
  • A: 1 and false
  • B: false and NaN
  • C: false and false

答案及解析

答案 : A 解析 : 一元操作符加号尝试将 boolean 转为 number。true 转换为 number 为 1,false 为 0。 字符串 'Lydia' 是一个真值,真值取反那么就返回 false。

写出执行结果,并解释原因

const bird = {
  size: 'small'
}

const mouse = {
  name: 'Mickey',
  small: true
}
  • A: mouse.bird.size是无效的
  • B: mouse[bird.size]是无效的
  • C: mouse[bird["size"]]是无效的
  • D: 以上三个选项都是有效的

答案及解析

答案 : A 解析 :

  1. 所有对象的 keys 都是字符串(在底层总会被转换为字符串)
  2. 使用括号语法时[],首先看到第一个开始括号 [ 并继续前进直到找到结束括号 ]。
  3. mouse[bird.size]:首先计算 bird.size,得到 small, mouse["small"] 返回 true。 //使用点语法
  4. mouse 没有 bird 属性,返回 undefined,也就变成了 undefined.size。是无效的,并且会抛出一个错误类似 Cannot read property "size" of undefined。

当我们这么做时,会发生什么?

function bark() {
  console.log('Woof!')
}

bark.animal = 'dog'
  • A: 正常运行!
  • B: SyntaxError. 你不能通过这种方式给函数增加属性。
  • C: undefined
  • D: ReferenceError

答案及解析

答案 : A 解析 : 在JS中是可以的,因为函数是一个特殊的对象(除了基本类型之外其他都是对象) 函数是一个拥有属性的对象,并且属性也可被调用。 bark.animal = function(){ console.log(1)} bark.animal () // 1

写出执行结果,并解释原因

class Chameleon {
  static colorChange(newColor) {
    this.newColor = newColor
    return this.newColor
  }

  constructor({ newColor = 'green' } = {}) {
    this.newColor = newColor
  }
}

const freddie = new Chameleon({ newColor: 'purple' })
freddie.colorChange('orange')
  • A: orange
  • B: purple
  • C: green
  • D: TypeError

答案及解析

答案 : D 解析 : colorChange 是一个静态方法。静态方法只能被创建它们的构造器使用(也就是 Chameleon), 并且不能传递给实例。因为 freddie 是一个实例,静态方法不能被实例使用,因此抛出了 TypeError 错误。

写出执行结果,并解释原因

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

const member = new Person("Lydia", "Hallie");
Person.getFullName = function () {
  return `${this.firstName} ${this.lastName}`;
}

console.log(member.getFullName());
  • A: TypeError
  • B: SyntaxError
  • C: Lydia Hallie
  • D: undefined undefined

答案及解析

答案 : A 解析 : 不能像常规对象那样,给构造函数添加属性。应该使用原型。 Person.prototype.getFullName = function () { return ${this.firstName} ${this.lastName}; } 这样 member.getFullName() 才起作用。将公共属性和方法添加到原型中,它只存在于内存中的一个位置,所有实例都可以访问它,节省内存空间

写出执行结果,并解释原因

function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

const lydia = new Person('Lydia', 'Hallie')
const sarah = Person('Sarah', 'Smith')

console.log(lydia)
console.log(sarah)
  • A: Person {firstName: "Lydia", lastName: "Hallie"} and undefined
  • B: Person {firstName: "Lydia", lastName: "Hallie"} and Person {firstName: "Sarah", lastName: "Smith"}
  • C: Person {firstName: "Lydia", lastName: "Hallie"} and {}
  • D:Person {firstName: "Lydia", lastName: "Hallie"} and ReferenceError

答案及解析

答案 : A 解析 : sarah没有使用 new 关键字。当使用 new 时,this 指向我们创建的空对象。未使用 new 时,this 指向的是全局对象。上述操作相当于 window.firstName = 'Sarah' 和 window.lastName = 'Smith'。而 sarah 本身是 undefined。

写出执行结果,并解释原因

const obj = { a: 'one', b: 'two', a: 'three' }
console.log(obj)
  • A: { a: "one", b: "two" }
  • B: { b: "two", a: "three" }
  • C: { a: "three", b: "two" }
  • D: SyntaxError

答案及解析

答案 : C 解析 : 如果一个对象有两个同名的键,则键会被替换掉。但仍位于该键第一次出现的位置,但是值是最后出现那个值。

写出执行结果,并解释原因

const a = {}
const b = { key: 'b' }
const c = { key: 'c' }

a[b] = 123
a[c] = 456

console.log(a[b])
  • A: 123
  • B: 456
  • C: undefined
  • D: ReferenceError

答案及解析

答案 : B 解析 : 对象的键被自动转换为字符串。

  1. 将对象 b 设置为对象 a 的键,会变成 "[object Object]",相当于a["[object Object]"] = 123。
  2. 再次将对象 c 设置为对象 a 的键,相当于 a["[object Object]"] = 456。
  3. 此时打印 a[b],也就是 a["[object Object]"]。刚设置为 456,因此返回 456。

写出执行结果,并解释原因

function sayHi() {
  return (() => 0)()
}

typeof sayHi()
  • A: "object"
  • B: "number"
  • C: "function"
  • D: "undefined"

答案及解析

答案 : B 解析 : sayHi 方法返回的是立即执行函数(IIFE)的返回值.此立即执行函数的返回值是 0, 类型是 number

写出执行结果,并解释原因

[1, 2, 3].map(num => {
  if (typeof num === "number") return;
  return num * 2;
});
  • A: []
  • B: [null, null, null]
  • C: [undefined, undefined, undefined]
  • D: [ 3 x empty ]

答案及解析

答案 : C 解析 : num表示当前元素. 都是number类型,因此typeof num === "number"结果都是true.map函数创建了新数组,并且将函数的返回值插入数组。 但并没有任何值返回。当函数没有返回任何值时,即默认返回undefined.对数组中的每一个元素来说,函数块都得到了这个返回值,所以结果中每一个元素都是undefined. 扩展:

  1. [1, 2, 3].map(num => typeof num === "number" ); // [true, true, true]
  2. [1, 2, 3].map(num => typeof (num === "number")); // ["boolean", "boolean", "boolean"]

输出什么?

function getFine(speed, amount) {
  const formattedSpeed = new Intl.NumberFormat({
    'en-US',
    { style: 'unit', unit: 'mile-per-hour' }
  }).format(speed)

  const formattedAmount = new Intl.NumberFormat({
    'en-US',
    { style: 'currency', currency: 'USD' }
  }).format(amount)

  return `The driver drove ${formattedSpeed} and has to pay ${formattedAmount}`
}

console.log(getFine(130, 300))
  • A: The driver drove 130 and has to pay 300
  • B: The driver drove 130 mph and has to pay $300.00
  • C: The driver drove undefined and has to pay undefined
  • D: The driver drove 130.00 and has to pay 300.00

答案及解析

答案 : B 解析 : Intl.NumberFormat 方法,可以格式化任意区域的数字值。 mile-per-hour 通过格式化结果为 mph; USD通过格式化结果为 $.

写出执行结果,并解释原因

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", TypeError
  • B: "Woof I am Mara","Woof I am Mara"
  • C: "Woof I am Mara", undefined
  • D: TypeError, TypeError

答案及解析

答案 : A 解析 : delete关键字删除对象的属性,对原型也适用。删除原型的属性后,该属性在原型链上就不可用。 执行 delete Dog.prototype.bark 后不可用,尝试调用一个不存在的函数时会抛出异常。 TypeError: pet.bark is not a function,因为pet.bark是undefined.

写出执行结果,并解释原因

const set = new Set([1, 1, 2, 3, 4]);

console.log(set);

答案及解析

答案 : D 解析 : Set对象是唯一值的集合:也就是说同一个值在其中仅出现一次。。所以结果是 {1, 2, 3, 4}. 易错 : B, 常见的set用法可用于数组去重,因此大家可能会误以为返回的是唯一值的数组,其实不然, var set1 = [...new Set([1, 1, 2, 3, 4])]; console.log(set1); // 此时返回的才是数组 [1, 2, 3, 4]

写出执行结果,并解释原因

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个空格。 如果传递给 padStart 方法的参数小于字符串的长度,则不会添加填充。

写出执行结果,并解释原因

const { name: myName } = { name: "Lydia" };

console.log(name);
  • A: "Lydia"
  • B: "myName"
  • C: undefined
  • D: ReferenceError

答案及解析

答案 : D 解析 : 对象解构:{name:myName}该语法为获取右侧对象中name属性值,并重命名为myName。 而name是一个未定义的变量,直接打印会引发ReferenceError: name is not defined。

写出执行结果,并解释原因

function checkAge(age) {
  if (age < 18) {
    const message = "Sorry, you're too young."
  } else {
    const message = "Yay! You're old enough!"
  }

  return message
}

console.log(checkAge(21))
  • A: "Sorry, you're too young."
  • B: "Yay! You're old enough!"
  • C: ReferenceError
  • D: undefined

答案及解析

答案 : C 解析 : 本题考查const和let声明的变量具有块级作用域,无法在声明的块之外引用变量,抛出 ReferenceError。

写出执行结果,并解释原因

let name = 'Lydia'
function getName() {
  console.log(name)
  let name = 'Sarah'
}
getName()
  • A: Lydia
  • B: Sarah
  • C: undefined
  • D: ReferenceError

答案及解析

答案 : D 解析 : let和const声明的变量,与var不同,它不会被初始化。在初始化之前无法访问。称为“暂时性死区”。 JavaScript会抛出ReferenceError: Cannot access 'name' before initialization。

写出执行结果,并解释原因

console.log(`${(x => x)('I love')} to program`)
  • A: I love to program
  • B: undefined to program
  • C: ${(x => x)('I love') to program
  • D: TypeError

答案及解析

答案 : A 解析 : 带有模板字面量的表达式首先被执行。相当于字符串包含表达式,(x => x)('I love')是一个立即执行函数 向箭头函数 x => x 传递 'I love' 作为参数。x 等价于返回的 'I love'。结果就是 I love to program。

写出执行结果,并解释原因

const spookyItems = ["👻", "🎃", "🕸"];
({ item: spookyItems[3] } = { item: "💀" });
console.log(spookyItems);
  • A: ["👻", "🎃", "🕸"]
  • B: ["👻", "🎃", "🕸", "💀"]
  • C: ["👻", "🎃", "🕸", { item: "💀" }]
  • D: ["👻", "🎃", "🕸", "[object Object]"]

答案及解析

答案 : B 解析 : 解构对象,可以从右边对象中拆出值,并将拆出的值分配给左边对象同名的属性。此时将值 "💀" 分配给 spookyItems[3]。 相当于正在篡改数组 spookyItems,给它添加了值 "💀"。当输出 spookyItems 时,结果为 ["👻", "🎃", "🕸", "💀"]。

以下哪个先打印?

setTimeout(() => {
  	console.log('setTimeout')
}, 0)
queueMicrotask(() => {
  	console.log('queueMicrotask')
})

答案及解析

答案是第二种情况(打印出queueMicroTask更好),因为来自queueMicroTask的任务在调用栈为空之后且在调用事件循环之前被调用,对于setTimeout而言,任务是eventQeue的一部分。

控制台输出是什么?

let x = 10

const byValue = y => {
    y = 20
}

byValue(x)
console.log(x)

答案及解析

答案是输出为10,因为将对象传递给函数时的对象相似,仅传递其值,而不传递对内存位置的实际引用。这就是为什么更改仅影响函数范围内的参数的原因。

控制台输出是什么?

let x = 10
let x = 20

答案及解析

在这种情况下,由于我们两次定义了相同的变量,因此,会在控制台上引发错误。 但是,如果我们使用var定义相同的变量,则控制台将返回50 。同样,在使用const定义变量时,我们将得到相同的错误。

Line1和Line2的控制台输出是什么?

console.log(new String('mkimq') === new String('mkimq'))
console.log('mkimq' === 'mkimq')

答案及解析

在Line1中,我们有两个相互比较的对象,并且它们都是唯一的,因此它将在控制台上记录为False。 在Line2中,我们使用===运算符来检查两个字符串基元而不是字符串对象,因此我们得到True。

控制台输出是什么,为什么?

const x = new String('mkimq')
const y = x
console.log(x === y)

答案及解析

与之前的问题类似,我们比较了两个唯一的对象。在这种情况下,只有一个唯一的对象,它具有两个常量x和y,它们指向内存中的唯一对象,并在控制台上返回True。

数组对象是JavaScript中的原始对象吗?

在JavaScript中,我们处理的大多数事物都是对象,类似地,数组只是JavaScript中的特殊对象,它们具有其他对象所没有的属性。

以下函数的返回类型是什么?

async function username() {
    return 'mkimq'
}
  • A: String
  • B: Promise
  • C: Async

答案及解析

答案,是B,因为异步函数在JavaScript中返回Promises 。

等待关键字会阻止应用程序中的所有JavaScript代码执行,直到返回等待的Promises?

答案是False,await关键字仅阻止执行包含await关键字的特定函数内的代码。

以下打印什么?

function name() {}

console.log(typeof name)

答案及解析

JavaScript中的函数是对象,typeof name将输出function。

以下是用于打印“用户名”的有效语法?

const username = async () => 'mkimq'

username().then(console.log)

答案及解析

以下语法是有效的,因为我们正在将异步函数的返回值传递给callback。

控制台输出是什么,为什么?

console.log(11 & 3)
  • A: 11
  • B: 1
  • C: 2
  • D: 3

答案及解析

在这种情况下,我们有&运算符,它与&&运算符完全不同。&是按位运算符,当我们比较11和3时,它将与1011和0011的二进制相同。结果,只有都为1的位保持为1,返回的输出为0011,它是3的二进制表示形式, 因此3记录在控制台上。

Object.[[Prototype]]的值是什么?

  • Object
  • null
  • {}

答案及解析

答案是null,因为默认值的对象。[[原型]为空,它会返回undefined在控制台上。该对象位于原型链的顶部,当浏览器查找访问属性的值时,它将遍历原型链,直到找到该值或直到不再遍历所有原型为止。

在JavaScript中使用事件委托时

例如,当我们必须侦听页面加载期间可能不存在的事件时,可以使用事件委托,并在父元素上提供事件处理程序并查看event.target。但是,如今,现代的前端框架和库使此操作变得不必要了。

以下哪一项不是内置的JS错误类型?

  • A: Error
  • B: EvalError
  • C: SyntaxError
  • D: TypeError
  • E: UndefinedError

答案及解析

答案是E。

创建字符串后,我们可以修改它吗?

不可以,因为字符串在JavaScript中是不可变的,指向字符串的变量可以分配给另一个字符串。

诺链中的嵌套捕获可以捕获在承诺链中向上抛出的错误吗?

不可以,嵌套是一种用于限制catch语句范围的控制结构。用简单的话来说,嵌套的catch仅捕获其作用域及其以下范围内的故障,而不捕获嵌套范围之外的链中较高的错误。

控制台输出是什么,为什么?

const mymap = new Map()
mymap.set({}, 1)

console.log(mymap.get({}))

答案及解析

即使mymap.get({})是有效的语法,它也会在控制台上返回undefined。因为set和get中的Object是内存中两个不同的空对象,因此getter不会返回值。

控制台输出是什么,为什么?

const map1 = new Map([
    ['A', 1],
    ['B', 1],
    ['C', 1],
])

const map2 = new Map([
    ['A', 2],
    ['B', 2],
])

const map = new Map([...map1, ...map2])

console.log(map)

答案及解析

控制台输出将为Map {'a'=> 2,'b'=> 2,'c'=> 1},这意味着第二个映射中的所有相同键将覆盖第一个映射中的键。

括号符号可以像点符号一样链接吗?

是的,可以,obj.prop1.prop2和obj ['prop1'] ['prop2']是等效的。

for…in循环中会显示什么类型的属性?

  • A: Executable Properties
  • B: Enumerable Properties
  • C: Iterable Properties

答案及解析

答案是B,可枚举属性。

以下内容是什么?

function getUserName() {
    var name = 'mkimq'

    function printUserName() {
        console.log(name)
    }

    printUserName()
}

getUserName()

答案及解析

控制台输出将为'mkimq',因为内部函数有权访问在外部作用域中声明的变量。

函数引用自身进行递归的三种方式是什么?

该函数的名称,一个指向该函数的范围内变量,并使用arguments.callee。

JavaScript是否支持重载?

不,JavaScript本身不支持重载,但TypeScript可以。但是,可以在JavaScript中通过在未将所有可能的参数都传递给函数时返回不同的输出来执行重载。

return语句在数组的forEach循环中做什么?

它不会返回任何内容,并且如果你需要从循环中返回值,则永远不要使用forEach循环。

RegExp没有任何属性。那是对的吗?

不,RegExp具有许多属性,例如.flags和.global。

控制台输出是什么?

function resolveFast(x) {
    return new Promise(resolve => {
        console.log(x)
    })
}

async function asyncTest() {
    var x = resolveFast(10)
    console.log(5)
}

asyncTest()

答案及解析

控制台输出将为10和5,因为该函数在Promise中没有异步的内容,并且Promise同步解析。

在浏览器下一次重画显示内容之前,哪个函数会执行指定的代码块?

  • A: requestAnimationFrame()
  • B: setTimeout()
  • C: requestRepaintDelay()

答案及解析

requestAnimationFrame()。

为什么在导入模块时使用别名?

大多数时候,我们处理具有默认命名约定的简单导入,除此之外,有时我们不得不处理名称,因为有的名称较长。在这种情况下,使用别名是有帮助的。

JavaScript中的子程序是什么?

子例程是主例程中遇到的函数,然后将其保存到对象并存储以供以后使用。例如,执行范围(变量,参数等)与子例程一起存储。

我们可以使用eventHandlers剪切和复制来防止用户将内容从浏览器复制到剪贴板吗?

是的,这些事件处理程序是Web API的一部分。

创建新对象的三种可能方法是什么?

new Object()&Object.create()和文字符号,其中我们定义了像this-(const obj = {a:2})这样的对象。

控制台输出是什么,为什么?

const a = {x: 1}
const b = {...a}
const c = {}

Object.assign(c, a)
a.x = 2

console.log(a.x)
console.log(b.x)
console.log(c.x)

答案及解析

一个被分配到一个对象,b被分配给一个使用该扩展运算符,它意味着一个和b在技术上是相同的。 c只是一个空对象。 使用Object.assign()中,c现在被指定到一个,并且后来在这之后,我们改变的值X在一个作为2。 控制台输出将为2,1,1。

Object.freeze()的作用是什么?

它防止添加新属性。 它可以防止更改对象的原型。 它防止更改属性的值。 它防止更改属性的可写性。

event.target与event.currentTarget有何不同?

event.currentTarget随着事件起泡而变化,event.target保持不变。

Array sort()方法的默认排序是什么?

按字符值从最小到最大。

什么是比赛条件?

当两个线程或异步进程必须完成自身操作以更新某些共享状态时,否则将出现错误或不良结果。

class关键字在JavaScript中有什么作用?

使JavaScript更加面向对象只是语法上,即使使用class关键字,JavaScript仍会使用原型继承。

queueMicrotask队列中的任务是在后进先出的基础上执行的。真的吗?

否,任务按照先进先出的顺序执行。

什么是Shadow DOM API?

阴影DOM API提供了一种隐藏的单独的DOM,附加到不是通过正常的访问元件JS DOM操作API。它提供Web组件的封装。

使用哪种方法将影子DOM树附加到指定的元素,并返回对其ShadowRoot的引用?

Element.attachShadow()。

贡献者: mankueng