【前端】20道JavaScript进阶问题(2)

来源:

javascript-questions/zh-CN/README-zh_CN.md at master · lydiahallie/javascript-questions · GitHub
记录一些有趣的题。

系列:
【前端】35道JavaScript进阶问题(1)
【前端】20道JavaScript进阶问题(2)

1

[1, 2, 3, 4].reduce((x, y) => console.log(x, y));

答:

1 2
undefined 3
undefined 4

解析:

reduce 方法接收一个回调函数和一个可选的初始值。 在你的例子中,回调函数是 (x, y) => console.log(x, y),没有提供初始值

reduce 方法会对数组中的每个元素执行回调函数。 在每次调用回调函数时,它都会接收两个参数:累积值(我们这里称之为 x)和当前元素(我们这里称之为 y)。然后,回调函数的返回值会成为下一次调用回调函数时的累积值。

在你的例子中,回调函数并没有返回任何值,所以在第二次及以后调用回调函数时,x 的值都是 undefined。

以下是详细的步骤:

  • 首先,reduce 方法会取数组的第一个元素(也就是 1)作为累积值 x,然后取数组的第二个元素(也就是 2)作为当前元素 y,然后调用回调函数。所以,第一次调用 console.log(x, y) 会输出 1 2。

  • 然后,因为回调函数没有返回任何值,所以下一次调用回调函数时,x 的值是 undefined,y 的值是数组的第三个元素(也就是 3)。所以,第二次调用 console.log(x, y) 会输出 undefined 3。

  • 同样,因为回调函数没有返回任何值,所以下一次调用回调函数时,x 的值还是 undefined,y 的值是数组的第四个元素(也就是 4)。所以,第三次调用 console.log(x, y) 会输出 undefined 4。

  • 所以,你的代码会依次输出 1 2、undefined 3 和 undefined 4。

2

使用哪个构造函数可以成功继承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;
  }

};

答:

2

解析:

在 JavaScript 中,如果你想要继承一个类,你需要在子类的构造函数中首先调用 super 函数。 super 函数会调用父类的构造函数,这是必须的,否则 JavaScript 会不能访问到this关键字。

所以,在你的例子中,只有第二个构造函数可以成功继承 Dog 类:

constructor(name, size) {
  super(name);
  this.size = size;
}

在这个构造函数中,首先调用了 super(name) 来调用 Dog 类的构造函数,然后设置了 size 属性。这样就成功地创建了一个 Labrador 对象,它既有 Dog 类的 name 属性,也有自己的 size 属性。

3

输出为?

// 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;

答:

running sum.js, running index.js, 3

解析:

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

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

4

console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol('foo') === Symbol('foo'))

答:

true, true, false

解析:

Number(2) 会返回一个数值 2,因此第一个为true。
若是new Number(2),则会返回一个对象。

console.log(new Number(2) === new Number(2)); // false

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

5

const name = "Lydia Hallie"
console.log(name.padStart(13))
console.log(name.padStart(2))

答:

 Lydia Hallie
Lydia Hallie

解析:

padStart传入的参数表示前面添加空格后总字符串的长度。小于原有长度的不处理。

6

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

答:

A。

7

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

function* startGame() {
  const ans = yield "Do you love JavaScript?";
  if (ans !== "Yes") {
    return "Oh wow... Guess we're gone here";
  }
  return "JavaScript loves you back ❤️";
}

const game = startGame();
console.log(/* 1 */); // Do you love JavaScript?
console.log(/* 2 */); // JavaScript loves you back ❤️

答:

console.log(game.next().value); // Do you love JavaScript?
console.log(game.next('Yes').value); // JavaScript loves you back ❤️

在第一次调用game.next()时,生成器函数会运行到第一个yield语句,并返回其右侧的值。然后,在第二次调用game.next('Yes')时,yield表达式的结果将被替换为传递给next()的参数(在这种情况下是"Yes"),然后函数继续执行,直到遇到下一个yield或者结束,返回其值。

8

console.log(String.raw`Hello\nworld`);

答:

Hello\nworld

String.raw是一个模板字符串的标签函数,它会将所有的反斜杠(\)视为普通字符。因此,\n不会被解析为换行符,而是会被视为两个独立的字符:反斜杠和n。

但是,要直接接一个字符串,而不是变量:

const path = `C:\Documents\Projects\table.html`
console.log(String.raw`${path}`) // C:DocumentsProjects     able.html
console.log(String.raw`C:\Documents\Projects\table.html`) // C:\Documents\Projects\table.html

9

async function getData() {
  return await Promise.resolve("I made it!");
}

const data = getData();
console.log(data);

答:

Promise { <pending> }

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

如果我们想要访问已解决的值"I made it!",可以在data上使用.then()方法:

data.then(res => console.log(res))

这样将打印 "I made it!"

10

const box = { x: 10, y: 20 };

Object.freeze(box);

const shape = box;
shape.x = 100;
console.log(shape)

答:

{ x: 10, y: 20 }

Object.freeze使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。

当我们创建变量shape并将其设置为等于冻结对象box时,shape指向的也是冻结对象。你可以使用Object.isFrozen检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)将返回true

由于shape被冻结,并且x的值不是对象,所以我们不能修改属性xx仍然等于10{x:10,y:20}被打印。

注意,上述例子我们对属性x进行修改,可能会导致抛出 TypeError 异常(最常见但不仅限于严格模式下时)。

11

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

console.log(name);

答:

ReferenceError

当我们从右侧的对象解构属性name时,我们将其值Lydia分配给名为myName的变量。

使用{name:myName},我们是在告诉 JavaScript 我们要创建一个名为myName的新变量,并且其值是右侧对象的name属性的值。

当我们尝试打印name,一个未定义的变量时,就会引发ReferenceError

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

console.log(name); // ReferenceError: name is not defined
console.log(myName); // Lydia

12

const myLifeSummedUp = ["☕", "💻", "🍷", "🍫"]

for (let item in myLifeSummedUp) {
  console.log(item)
}

for (let item of myLifeSummedUp) {
  console.log(item)
}

答:

0
1
2
3
☕
💻
🍷
🍫

通过for-in循环,我们可以遍历一个对象自有的继承的可枚举的非 Symbol 的属性。在数组中,可枚举属性是数组元素的“键”,即它们的索引。类似于下面这个对象:

{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}

其中键则是可枚举属性,因此 0123被记录。

通过for-of循环,我们可以迭代可迭代对象(包括 ArrayMapSetStringarguments等)。当我们迭代数组时,在每次迭代中,不同属性的值将被分配给变量item,因此“☕”“💻”“🍷”“🍫”被打印。

13

var status = "😎"

setTimeout(() => {
  const status = "😍"

  const data = {
    status: "🥑",
    getStatus() {
      return this.status
    }
  }

  console.log(data.getStatus())
  console.log(data.getStatus.call(this))
}, 0)

答:

🥑
undefined

这段代码中,data.getStatus()data.getStatus.call(this)的返回值取决于函数调用时的上下文(也就是this的值)。

  • data.getStatus():在这种情况下,this指向的是data对象,因此this.status返回的是data对象的status属性,即"🥑"。所以,console.log(data.getStatus())将打印出"🥑"。

  • data.getStatus.call(this)Function.prototype.call方法允许你改变函数调用时this的值。在这个例子中,由于call方法被调用时没有提供参数,所以this的值将是全局对象(在非严格模式下)。然而,由于这段代码是在一个箭头函数中执行的,this的值实际上是从包围它的普通(非箭头)函数(在这种情况下是全局作用域)继承来的。在全局作用域中,this通常指向全局对象(在浏览器中是window),但是由于status不是全局对象的属性,this.status将返回undefined。所以,console.log(data.getStatus.call(this))将打印出undefined。

需要注意的是,这个行为可能会因JavaScript运行环境的不同而有所差异。例如,在Node.js中,全局this的值是一个空对象,而不是global对象。

14

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))

答:

ReferenceError: message is not defined

constlet声明的变量是具有块级作用域的,块是大括号({})之间的任何东西,即上述情况if / else语句的花括号。

在return的地方已经没有message这个变量了。

15

打印什么?

fetch('https://www.website.com/api/user/1')
  .then(res => res.json())
  .then(res => console.log(res))
  • A: fetch方法的结果
  • B: 第二次调用fetch方法的结果
  • C: 前一个.then()中回调方法返回的结果
  • D: 总是undefined

答:

C。

解析:

第二个.thenres的值等于前一个.then中的回调函数返回的值。你可以像这样继续链接.then,将值传递给下一个处理程序。

16

// module.js 
export default () => "Hello world"
export const name = "Lydia"

// index.js 
import * as data from "./module"

console.log(data)

答:

{ default: function default(), name: "Lydia" }

使用import * as name语法,我们将module.js文件中所有export导入到index.js文件中,并且创建了一个名为data的新对象。在module.js文件中,有两个导出:默认导出和命名导出。默认导出是一个返回字符串“Hello World”的函数,命名导出是一个名为name的变量,其值为字符串“Lydia”

data对象具有默认导出的default属性,其他属性具有指定 exports 的名称及其对应的值。

17

class Person {
  constructor(name) {
    this.name = name
  }
}

const member = new Person("John")
console.log(typeof member)

答:

object

解析:

类是构造函数的语法糖,如果用构造函数的方式来重写Person类则将是:

function Person() {
  this.name = name
}

通过new来调用构造函数,将会生成构造函数Person的实例,对实例执行typeof关键字将返回"object",上述情况打印出"object"

18

function giveLydiaPizza() {
  return "Here is pizza!"
}

const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."

console.log(giveLydiaPizza.prototype)
console.log(giveLydiaChocolate.prototype)

答:

{ constructor: ...}  undefined

解析:

在JavaScript中,只有通过function关键字定义的函数才有prototype属性。箭头函数并没有prototype属性。

所以,console.log(giveLydiaPizza.prototype)将打印出giveLydiaPizza函数的原型对象,通常是一个空对象,但包含一个constructor属性指向该函数本身。

console.log(giveLydiaChocolate.prototype)将打印出undefined,因为giveLydiaChocolate是一个箭头函数,它没有prototype属性。

19

function getItems(fruitList, ...args, favoriteFruit) {
  return [...fruitList, ...args, favoriteFruit]
}

getItems(["banana", "apple"], "pear", "orange")

答:

SyntaxError: Rest parameter must be last formal parameter

解析:

... args是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,并且只能作为最后一个参数

20

function nums(a, b) {
	if (a > b) console.log("a is bigger");
	else console.log("b is bigger");
	return
	a + b;
}

console.log(nums(4, 2));
console.log(nums(1, 2));

答:

a is bigger
undefined
b is bigger
undefined

解析:

相当于:

function nums(a, b) {
	if (a > b) console.log("a is bigger");
	else console.log("b is bigger");
	return;
	a + b;
}

a+b永远走不到,只return一个undefined。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

karshey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值