29

7个常见的 JavaScript 测验及解答[每日前端夜话0xDE]

 4 years ago
source link: https://www.tuicool.com/articles/qyyqQn2
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

每日前端夜话 0xDE

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:2244 字

预计阅读时间:10 分钟

作者:Milos Protic

翻译:疯狂的技术宅

来源: devinduct

ZbqiEre.jpg!web

介绍

我相信学习新事物并评估我们所知的东西对自己的进步非常有用,可以避免了我们觉得自己的知识过时的情况。在本文中,我将介绍一些常见的 JavaScript 知识。请享用!

1.声明

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

 1// situation 1
 2console.log(person);
 3var person = 'John';
 4
 5// situation 2
 6console.log(person);
 7let person = 'Phill';
 8
 9// situation 3
10console.log(person);
11const person = 'Frank';
12
13// situation 4
14const person = 'Vanessa';
15console.log(person);
16person = 'Mike';
17console.log(person);
18
19// situation 5
20var person = 'John';
21let person = 'Mike';
22console.log(person);
23
24// situation 6
25var person = 'John';
26if (person) {
27  let person = 'Mike';
28  console.log(person);
29}
30console.log(person);

说明

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

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

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

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

1Uncaught ReferenceError: Cannot access 'person' before initialization

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

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

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

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

1Uncaught TypeError: Assignment to constant variable

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

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

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

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

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

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

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

2.继承

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

 1class Person {
 2  constructor() {
 3    this.sayHello = () => {
 4      return 'Hello';
 5    }
 6  }
 7
 8  sayBye() {
 9    return 'Bye';
10  }
11}
12
13class Student extends Person {
14  sayHello() {
15    return 'Hello from Student';
16  }
17}
18
19const student = new Student();
20console.log(student.sayHello());

说明

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

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

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

3.对象可变性

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

 1// situation 1
 2const user = {
 3  name: 'John',
 4  surname: 'Doe'
 5}
 6
 7user = {
 8  name: 'Mike'
 9}
10
11console.log(user);
12
13// situation 2
14const user = {
15  name: 'John',
16  surname: 'Doe'
17}
18
19user.name = 'Mike';
20console.log(user.name);
21
22// situation 3
23const user = {
24  name: 'John',
25  surname: 'Doe'
26}
27
28const anotherUser = user;
29anotherUser.name = 'Mike';
30console.log(user.name);
31
32// situation 4
33const user = {
34  name: 'John',
35  surname: 'Doe',
36  address: {
37    street: 'My Street'
38  }
39}
40
41Object.freeze(user);
42
43user.name = 'Mike';
44user.address.street = 'My Different Street';
45console.log(user.name);
46console.log(user.address.street);

说明

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

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

1Uncaught TypeError: Assignment to constant variable

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

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

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

控制台中的结果应为 Mike

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

控制台中的输出依次为 JohnMy Different Street

4.箭头函数

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

 1const 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
12student.printName();
13student.printSchool();

说明

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

你可能会熟悉以下语法:

1var me = this;
2// or
3var self = this;
4
5// ...
6// ...
7// somewhere deep...
8// me.doSomething();

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

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

5.解构

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

 1const rawUser = {
 2   name: 'John',
 3   surname: 'Doe',
 4   email: '[email protected]',
 5   displayName: 'SuperCoolJohn',
 6   joined: '2016-05-05',
 7   image: 'path-to-the-image',
 8   followers: 45
 9}
10
11let user = {}, userDetails = {};
12({ name: user.name, surname: user.surname, ...userDetails } = rawUser);
13
14console.log(user);
15console.log(userDetails); 

说明

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

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

1// {name: "John", surname: "Doe"}
2// {email: "[email protected]", displayName: "SuperCoolJohn", joined: "2016-05-05", image: "path-to-the-image", followers: 45}

6.异步/等待

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

 1(async () => {
 2  let result = 'Some Data';
 3
 4  let promise = new Promise((resolve, reject) => {
 5    setTimeout(() => resolve('Some data retrieved from the server'), 2000);
 6  });
 7
 8  result = await promise;
 9  console.log(result);
10})();

说明

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

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

7. Return 语句

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

说明

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

由于自动分号插入【 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return#Automatic_Semicolon_Insertion 】的原因,上面的代码将返回 undefinedreturn 关键字和表达式之间不允许使用行结束符

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

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

要么

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

原文: https://devinduct.com/blogpost/49/7-quick-javascript-pop-quizzes-with-explanations

下面夹杂一些私货:也许你和高薪之间只差这一张图

2019年京程一灯课程体系上新,这是我们第一次将全部课程列表对外开放。

愿你有个好前程,愿你月薪30K。我们是认真的 ! BbquyaF.png!web

zMFVruu.jpg!web

在公众号内回复“体系”查看高清大图

长按二维码,加大鹏老师微信好友

拉你加入前端技术交流群

唠一唠怎样才能拿高薪

JFNJFbv.jpg!web

小手一抖,资料全有。长按二维码关注 前端先锋 ,阅读更多技术文章和业界动态。

MFryQjN.gif


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK