美文网首页互联网科技Java架构技术进阶Java
7 个常见的 JavaScript 测验及解答

7 个常见的 JavaScript 测验及解答

作者: can_4999 | 来源:发表于2019-11-01 19:52 被阅读0次

1.声明

查看以下代码,并回答输出的内容(以及原因)。

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. // situation 1

  2. console.log(person);

  3. var person = 'John';

  4. // situation 2

  5. console.log(person);

  6. let person = 'Phill';

  7. // situation 3

  8. console.log(person);

  9. const person = 'Frank';

  10. // situation 4

  11. const person = 'Vanessa';

  12. console.log(person);

  13. person = 'Mike';

  14. console.log(person);

  15. // situation 5

  16. var person = 'John';

  17. let person = 'Mike';

  18. console.log(person);

  19. // situation 6

  20. var person = 'John';

  21. if (person) {

  22. let person = 'Mike';

  23. console.log(person);

  24. }

  25. console.log(person);

</pre>

说明

Situation 1: 预期结果是在控制台中看到文本 John,但是令人惊讶的是,我们看到记录了undefined。想知道为什么吗?

好吧,这是经典的 JavaScript 在起作用。这种行为被称为提升。在后台,该语言将变量声明和值分配分为两部分。不管变量最初由开发人员在哪里声明,变量都将移动到顶部,声明时将其值设置为 undefined。看起来像这样:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. var person;
  2. console.log(person);
  3. person = 'John';

</pre>

Situation 2: 在这里,结果将是引用错误。

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. Uncaught ReferenceError: Cannot access 'person' before initialization

</pre>

错误文本说明了一切。因为我们使用了关键字 let,所以我们的变量被提升,但没有初始化,并且抛出该错误,通知我们正在尝试访问未初始化的变量。在 ES6 中引入了关键字 let,使我们能够使用块作用域中的变量,从而帮助我们防止意外行为。

在这里,我们会得到与 Situation 2 中相同的错误。

不同之处在于我们使用了关键字 const,从而防止在初始化后重新分配变量。 ES6 中也引入了此关键字。

Situation 4: 在这种情况下,我们可以看到关键字 const 是如何工作的,以及它如何避免无意中重新分配变量。在我们的示例中,首先会在控制台中看到 Vanessa,然后是一个类型错误。

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. Uncaught TypeError: Assignment to constant variable

</pre>

const 变量的使用随着我们的代码库呈指数增长。

Situation 5: 如果已经在某个作用域内使用关键字 var 定义了变量,则在同一作用域中用关键字 let 再次声明该变量将会引发错误。

因此,在我们的示例中,将不会输出任何内容,并且会看到语法错误提示。

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. Uncaught SyntaxError: Identifier 'person' has already been declared

</pre>

Situation 6: 我们分别有一个函数作用域的变量,和块作用域的变量。在这种情况下,它们是否有相同的名字或标识符并不重要。

在控制台中,我们应该看到 Mike 和 John 被依次输出。为什么?

因为关键字 let 为我们提供了块作用域内的变量,这意味着它们仅存在于自己创建的作用域内,在这种情况下,位于if...else 语句中。内部变量优先于外部变量,这就是为什么我们可以使用相同标识符的原因。

2.继承

考虑以下类,并尝试回答输出了什么以及为什么。

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. class Person {

  2. constructor() {

  3. this.sayHello = () => {

  4. return 'Hello';

  5. }

  6. }

  7. sayBye() {

  8. return 'Bye';

  9. }

  10. }

  11. class Student extends Person {

  12. sayHello() {

  13. return 'Hello from Student';

  14. }

  15. }

  16. const student = new Student();

  17. console.log(student.sayHello());

</pre>

说明

如果你的答案是 Hello,那是对的!

为什么:每次我们创建一个新的 Student 实例时,都会将 sayHello 属性设置为是一个函数,并返回字符串 Hello。这是在父类(Person)类的构造函数中发生的。

在 JavaScript 中,类是语法糖,在我们的例子中,在原型链上定义了 Student 类中的 sayHello 方法。考虑到每次我们创建 Student 类的实例时,都会将 sayHello 属性设置为该实例,使其成为返回字符串 Hello 的 function,因此我们永远不会使用原型链上定义的函数,也就永远不会看到消息 Hello from Student 。

3.对象可变性

思考以下情况中每个部分的输出:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. // situation 1

  2. const user = {

  3. name: 'John',

  4. surname: 'Doe'

  5. }

  6. user = {

  7. name: 'Mike'

  8. }

  9. console.log(user);

  10. // situation 2

  11. const user = {

  12. name: 'John',

  13. surname: 'Doe'

  14. }

  15. user.name = 'Mike';

  16. console.log(user.name);

  17. // situation 3

  18. const user = {

  19. name: 'John',

  20. surname: 'Doe'

  21. }

  22. const anotherUser = user;

  23. anotherUser.name = 'Mike';

  24. console.log(user.name);

  25. // situation 4

  26. const user = {

  27. name: 'John',

  28. surname: 'Doe',

  29. address: {

  30. street: 'My Street'

  31. }

  32. }

  33. Object.freeze(user);

  34. user.name = 'Mike';

  35. user.address.street = 'My Different Street';

  36. console.log(user.name);

  37. console.log(user.address.street);

</pre>

说明

Situation 1: 正如我们在上一节中所了解的,我们试图重新分配不允许使用的 const 变量,所以将会得到类型错误。

控制台中的结果将显示以下文本:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. Uncaught TypeError: Assignment to constant variable

</pre>

Situation 2: 在这种情况下,即使我们改用关键字 const 声明的变量,也会有不同的行为。不同之处在于我们正在修改对象属性而不是其引用,这在 const 对象变量中是允许的。

控制台中的结果应为单词 Mike。

Situation 3: 通过将 user 分配给 anotherUser 变量,可以在它们之间共享引用或存储位置(如果你愿意)。换句话说,它们两个都会指向内存中的同一个对象,因所以更改一个对象的属性将反映另一个对象的更改。

控制台中的结果应为 Mike。

Situation 4: 在这里,我们使用 Object.freeze 方法来提供先前场景(Situation 3)所缺乏的功能。通过这个方法,我们可以“冻结”对象,从而不允许修改它的属性值。但是有一个问题!它只会进行浅冻结,这意味着它不会保护深层属性的更新。这就是为什么我们能够对 street 属性进行更改,而 name 属性保持不变的原因。

控制台中的输出依次为 John 和 My Different Street 。

4.箭头函数

运行以下代码段后,将会输出什么以及原因:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. const student = {

  2. school: 'My School',

  3. fullName: 'John Doe',

  4. printName: () => {

  5. console.log(this.fullName);

  6. },

  7. printSchool: function () {

  8. console.log(this.school);

  9. }

  10. };

  11. student.printName();

  12. student.printSchool();

</pre>

说明

控制台中的输出将依次为 undefined 和 My School。

你可能会熟悉以下语法:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. var me = this;

  2. // or

  3. var self = this;

  4. // ...

  5. // ...

  6. // somewhere deep...

  7. // me.doSomething();

</pre>

你可以把 me 或 self 变量视为父作用域,该作用域可用于在其中创建的每个嵌套函数。

当使用箭头函数时,这会自动完成,我们不再需要存储 this 引用来访问代码中更深的地方。箭头函数不绑定自己,而是从父作用域继承一个箭头函数,这就是为什么在调用 printName 函数后输出了 undefined 的原因。

5.解构

请查看下面的销毁信息,并回答将要输出的内容。给定的语法是否允许,否则会引发错误?

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. const rawUser = {

  2. name: 'John',

  3. surname: 'Doe',

  4. email: 'john@doe.com',

  5. displayName: 'SuperCoolJohn',

  6. joined: '2016-05-05',

  7. image: 'path-to-the-image',

  8. followers: 45

  9. }

  10. let user = {}, userDetails = {};

  11. ({ name: user.name, surname: user.surname, ...userDetails } = rawUser);

  12. console.log(user);

  13. console.log(userDetails);

</pre>

说明

尽管有点开箱即用,但是上面的语法是允许的,并且不会引发错误! 很整洁吧?

上面的语法功能强大,使我们能够轻松地将任何对象分成两个更具体的对象,上面的示例在控制台的输出为:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. // {name: "John", surname: "Doe"}
  2. // {email: "john@doe.com", displayName: "SuperCoolJohn", joined: "2016-05-05", image: "path-to-the-image", followers: 45}

</pre>

6.异步/等待

调用以下函数后将输出什么?

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. (async () => {

  2. let result = 'Some Data';

  3. let promise = new Promise((resolve, reject) => {

  4. setTimeout(() => resolve('Some data retrieved from the server'), 2000);

  5. });

  6. result = await promise;

  7. console.log(result);

  8. })();

</pre>

说明

如果你认为是两秒钟后输出 Some data retrieved from the server ,那么你是对的!

代码将会暂停,直到 promise 得到解决。两秒钟后,它将继续执行并输出给定的文本。这意味着 JavaScript 引擎实际上会等到异步操作完成。可以说 async/await 是用来获得 promise 结果的语法糖。也有人认为它是比 promise.then 更具可读性的方式。

7. Return 语句

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. const multiplyByTwo = (x) => {
  2. return
  3. {
  4. result: x * 2
  5. };
  6. }
  7. console.log(multiplyByTwo(2));

</pre>

说明

如果你的答案是 {result: 4},那你就错了。输出是 undefined。但是不要对自己太苛刻,考虑到我也写 C# 代码,这也曾经困扰着我,这在 C# 那儿不是个问题。

由于自动分号插入的原因,上面的代码将返回 undefined。 return 关键字和表达式之间不允许使用行结束符

解决方案是用以下列方式之一去修复这个函数:

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. const multiplyByTwo = (x) => {
  2. return {
  3. result: x * 2
  4. };
  5. }

</pre>

要么

<pre style="padding: 0px; margin: 0px 0px 1em; font-family: "Courier New", monospace; font-size: 12px; width: 643.49px; overflow: auto; background: rgb(230, 230, 230); color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

  1. const multiplyByTwo = (x) => {
  2. return (
  3. {
  4. result: x * 2
  5. }
  6. );
  7. }

</pre>

【编辑推荐】

  1. Java开发数据库设计的14个技巧
  2. JavaScript冒泡排序与选择排序
  3. 面试还没法说透Synchronized底层原理?推荐看看这篇文章!
  4. IT 人眼里最吃香的技术:软件开发 JavaScript;数据专业 R等
  5. 2019年,React开发人员应该掌握的22种神奇工具

相关文章

网友评论

    本文标题:7 个常见的 JavaScript 测验及解答

    本文链接:https://www.haomeiwen.com/subject/ovtqbctx.html