7个常见的 JavaScript 测验及解答

时间: 2019-11-01阅读: 943标签: js知识

介绍

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


1.声明

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

// situation 1
console.log(person);
var person = 'John';

// situation 2
console.log(person);
let person = 'Phill';

// situation 3
console.log(person);
const person = 'Frank';

// situation 4
const person = 'Vanessa';
console.log(person);
person = 'Mike';
console.log(person);

// situation 5
var person = 'John';
let person = 'Mike';
console.log(person);

// situation 6
var person = 'John';
if (person) {
  let person = 'Mike';
  console.log(person);
}
console.log(person);

说明

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

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

var person;
console.log(person);
person = 'John';
Situation 2: 在这里,结果将是引用错误。
Uncaught ReferenceError: Cannot access 'person' before initialization

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

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

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

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

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

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

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

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

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

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


2.继承

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

class Person {
  constructor() {
    this.sayHello = () => {
      return 'Hello';
    }
  }

  sayBye() {
    return 'Bye';
  }
}

class Student extends Person {
  sayHello() {
    return 'Hello from Student';
  }
}

const student = new Student();
console.log(student.sayHello());

说明

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

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

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


3.对象可变性

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

// situation 1
const user = {
  name: 'John',
  surname: 'Doe'
}

user = {
  name: 'Mike'
}

console.log(user);

// situation 2
const user = {
  name: 'John',
  surname: 'Doe'
}

user.name = 'Mike';
console.log(user.name);

// situation 3
const user = {
  name: 'John',
  surname: 'Doe'
}

const anotherUser = user;
anotherUser.name = 'Mike';
console.log(user.name);

// situation 4
const user = {
  name: 'John',
  surname: 'Doe',
  address: {
    street: 'My Street'
  }
}

Object.freeze(user);

user.name = 'Mike';
user.address.street = 'My Different Street';
console.log(user.name);
console.log(user.address.street);

说明

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

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

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

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

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

控制台中的结果应为 Mike。

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

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


4.箭头函数

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

const student = {
  school: 'My School',
  fullName: 'John Doe',
  printName: () => {
    console.log(this.fullName);
  },
  printSchool: function () {
    console.log(this.school);
  }
};

student.printName();
student.printSchool();

说明

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

你可能会熟悉以下语法:

var me = this;
// or
var self = this;

// ...
// ...
// somewhere deep...
// me.doSomething();

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

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


5.解构

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

const rawUser = {
   name: 'John',
   surname: 'Doe',
   email: 'john@doe.com',
   displayName: 'SuperCoolJohn',
   joined: '2016-05-05',
   image: 'path-to-the-image',
   followers: 45
}

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

console.log(user);
console.log(userDetails); 

说明

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

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

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


6.异步/等待

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

(async () => {
  let result = 'Some Data';

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Some data retrieved from the server'), 2000);
  });

  result = await promise;
  console.log(result);
})();

说明

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

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


7. Return 语句

const multiplyByTwo = (x) => {
    return
    {
        result: x * 2
    };
}
console.log(multiplyByTwo(2));  

说明

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

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

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

const multiplyByTwo = (x) => {
    return {
        result: x * 2
    };
}

要么

const multiplyByTwo = (x) => {
  return (
    {
      result: x * 2
    }
  );
}
原文:https://devinduct.com/blogpost/49/7-quick-javascript-pop-quizzes-with-explanations,作者:Milos Protic

翻译:疯狂的技术


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/6239

JS的变量作用域问题,理解js全局变量和局部变量问题

js的变量分为2种类型:局部变量和全局变量。主要区别在于:局部变量是指只能在变量被声明的函数内部调用,全局变量在整个代码运行过程中都可以调用。值得注意的js中还可以隐式声明变量,而隐式声明的变量千万不能当做全局变量来使用。

js原型链,Javascript重温OOP之原型与原型链

js的原型链,得出了一个看似很简单的结论。对于一个对象上属性的查找是递归的。查找属性会从自身属性(OwnProperty)找起,如果不存在,就查看prototype中的存在不存在。

深入理解JS中引用类型和基本类型

javascript中基本类型指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存中的一个位置。 引用类型指那些保存在堆内存中的对象,意思是变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。

Js中的命名空间(namespace)

全局变量应该由有系统范围相关性的对象们保留,并且它们的命名应该避免含糊并尽量减少命名冲突的风险。在实践中,这意味着你应该避免创建全局对象,除非它们是绝对必须的。 所以你对此是怎么做的?传统方法告诉我们,最好的消除全局策略是创建少数作为潜在模块和子系统的实际命名空间的全局对象。

javascript对dom的操作总汇,js创建,更新,添加,删除DOM的方法

HTML文档在浏览器解析后,会成为一种树形结构,我们需要改变它的结构,就需要通过js来对dom节点进行操作。dom节点(Node)通常对应的是一个标题,文本,或者html属性。

JavaScript中的特殊运算,一些有趣的js等式

JavaScript中的特殊运算,字符,true,false参与运算结果会怎么样?打开控制台。这会允许你再你的浏览器里输入下面所有的代码,所以你可以实时的看到发生什么了。

JavaScript中公有、私有、静态、受保护的属性和方法

在开发中,我们需要限制某些属性和方法的暴露程度,使得它们不能通过对象实例本身被访问、修改或调用。要了解js面向对象,就必需先了解js中什么是公有、私有、静态、受保护。

JS中for循环的常见题型

for循环示例;让用户输入行数,使用for循环嵌套打出倒着的星星出来,行数等于用户输入的数字 ;有1,2,3,4这么4个数,能组成多少个互不相同且不含有重复数字的三位数?都是多少?

打造自己的JavaScript武器库

作为战斗在业务一线的前端,要想少加班,就要想办法提高工作效率。这里提一个小点,我们在业务开发过程中,经常会重复用到日期格式化、url参数转对象、浏览器类型判断、节流函数等一类函数,这些工具类函数

JavaScript中的魔幻代理Proxy

什么是 JavaScript 代理?通过 Proxy 我们可以拦截并改变一个对象的几乎所有的根本操作,包括但不限于属性查找、赋值、枚举、函数调用等等。利用 Proxy,我们可以拦截并不存在的属性的读取

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!