7个常见的 JavaScript 测验及解答

来源:http://www.chinese-glasses.com 作者:Web前端 人气:176 发布时间:2020-03-31
摘要:时间: 2019-11-01阅读: 110标签: js知识介绍 简介初心 我相信学习新事物并评估我们所知的东西对自己的进步非常有用,可以避免了我们觉得自己的知识过时的情况。在本文中,我将介绍一

时间: 2019-11-01阅读: 110标签: js知识介绍

简介初心

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

本文档是一份 JavaScript 速查表,你在现代项目中会经常遇到,以及最新的代码示例。

1.声明

本指南不是为了教你从头开始学习 JavaScript ,而是为了帮助那些可能不熟悉当前代码库所用到 JavaScript 概念的开发人员。

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

此外,我有时还会提供一些个人的建议,这些建议可能是有争议的,但我也会注意到,当我这么做的时候,这是我个人的建议。

// situation 1console.log(person);var person = 'John';// situation 2console.log(person);let person = 'Phill';// situation 3console.log(person);const person = 'Frank';// situation 4const person = 'Vanessa';console.log(person);person = 'Mike';console.log(person);// situation 5var person = 'John';let person = 'Mike';console.log(person);// situation 6var person = 'John';if (person) { let person = 'Mike'; console.log(person);}console.log(person);

注意: 这里介绍的大多数概念来自于最新的 JavaScript 语言。你可以在 这里 找到新增的特性,网站做得很棒。

说明

补充资源

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

当您努力了解一个新概念时,我建议你在以下资源网站上寻找相关的答案:

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

MDN (Mozilla Developer Network) 你所不知道的JS ES6 新特性和例子 WesBos 的博客 Reddit 用 Google 来查找特定的博客和资源 StackOverflow目录 现代 JavaScript 速查 简介 初心 参考资料 目录 概念 变量声明: var, const, let 简单说明 简单的示例 详细说明 扩展阅读 箭头函数 简单的示例 详细说明 简洁性 this 引用 有用的资源 函数参数默认值 扩展阅读 解构对象和数组 用示例代码说明 有用的资源 数组方法 – map / filter / reduce 简单的示例 说明 Array.prototype.map() Array.prototype.filter() Array.prototype.reduce() 扩展阅读 展开操作符 “…” 简单的代码示例 说明 应用于迭代 函数剩余参数 对象属性展开 扩展阅读 对象属性简写 说明 扩展阅读 Promises 简单的代码示例 说明 创建 promise Promise 处理器的用法 扩展阅读 模板字符串 简单的代码示例 扩展阅读 带标签的模板字符串 扩展阅读 ES6 模块的导入 / 导出 用示例代码说明 命名导出 默认导入 / 导出 扩展阅读 JavaScript 中的 this 扩展阅读 类 简单的示例 扩展阅读 Extendssuper 关键字 简单的代码示例 扩展阅读 异步和等待 简单的代码示例 用示例代码说明 错误处理 扩展阅读 真值/假值 扩展阅读 静态方法 简单说明 简单的代码示例 详细说明 在静态方法调用另一个静态方法 在非静态方法调用静态方法 扩展阅读 词汇表 作用域 变量的可变性 概念变量声明: var, const, let

var person;console.log(person);person = 'John';

在 JavaScript 中,有 3 个关键字可用于声明一个变量,他们之间有些差异。那些是 varletconst

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

简单说明

UncaughtReferenceError: Cannot access'person'before initialization

使用 const 关键字声明的变量无法重新分配,而 letvar 可以。

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

我建议总是默认使用 const 来声明你的变量,如果你需要改变它,或者稍后需要重新分配,那么实用 let

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

作用域

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

可否重新分配

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

可变性

UncaughtTypeError: Assignment to constant variable

暂时性死区

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

const

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

Block No Yes Yes

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

let

UncaughtSyntaxError: Identifier'person'has already been declared

Block Yes Yes Yes

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

var

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

Function Yes Yes No 简单的示例

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

const person = "Nick";person = "John" // 将会引起错误,person 不能重新分配

let person = "Nick";person = "John";console.log // "John", 使用 let 允许重新分配

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

var

说明

var 声明的变量是 函数作用域 ,这意味着当在函数中创建变量时,该函数中的所有内容都可以访问该变量。此外,函数中创建的 函数作用域 变量无法在此函数外访问。

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

我建议你把它看作一个 X 作用域 变量,意味着这个变量是 X 的属性。

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

function myFunction() { var myVar = "Nick"; console.log; // "Nick" - 在这个函数中 myVar 可被访问到}console.log; // 抛出错误 ReferenceError, 在函数之外 myVar 则无法访问

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

继续关注变量的作用域,这里是一个更微妙的例子:

3.对象可变性

function myFunction() { var myVar = "Nick"; if  { var myVar = "John"; console.log; // "John" // 实际上,myVar是函数作用域,我们只是将之前 myVar 的值 "Nick" 抹去,重新声明为 "John" } console.log; // "John" - 看看 if 语句块中的指令是如何影响这个值的 }console.log; // 抛出错误 ReferenceError, 在函数之外 myVar 则无法访问

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

此外,在执行过程中,var声明的变量被移动到范围的顶部。这就是我们所说的变量声明提升。

// situation 1const user = { name: 'John', surname: 'Doe'}user = { name: 'Mike'}console.log(user);// situation 2const user = { name: 'John', surname: 'Doe'}user.name = 'Mike';console.log(user.name);// situation 3const user = { name: 'John', surname: 'Doe'}const anotherUser = user;anotherUser.name = 'Mike';console.log(user.name);// situation 4const 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);
console.log // undefined -- 不会报错var myVar = 2;

var myVar;console.log // undefined -- 不会报错myVar = 2;

说明

愚人码头注:变量提升和函数声明提升可以查看:JavaScript 中的 Hoisting

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

let

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

varlet 大致相同,但是用 let 声明的变量时有以下几个特性:

UncaughtTypeError: Assignment to constant variable

块级作用域 在被分配之前, 无法 访问使用 在同一个作用域之下,不能重新声明

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

我们来看看我们前面的例子,采用块级作用域后的效果:

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

function myFunction() { let myVar = "Nick"; if  { let myVar = "John"; console.log; // "John" // 实际上 myVar 在块级作用域中,我们只是创建了一个新变量 myVar。 // 此变量在 if 语句块之外不可访问, // 完全独立于创建的第一个 myVar 变量! } console.log; // "Nick", 可以看到 if 语句块中的指令不会影响这个值}console.log; // 抛出错误 ReferenceError,myVar 无法在函数外部被访问。

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

现在,我们来看看 let变量在被赋值之前不可访问是什么意思:

控制台中的结果应为Mike。

console.log // 抛出一个引用错误 ReferenceError !let myVar = 2;

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

var 变量不同的是,如果你在 let 或者 const 变量被赋值之前读写,那么将会出现错误。这种现象通常被称为暂存死区(Temporal dead zone)或者 TDZ

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

注意: 从技术上讲,letconst 变量声明时也存在提升,但并不代表它们的赋值也会被提升。但由于它被设计成了赋值之前无法使用,所以我们直观感觉上它没有被提升,但其实是存在提升的。如果想了解更多细节,请看这篇文章。

4.箭头函数

此外,您不能重新声明一个 let 变量:

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

let myVar = 2;let myVar = 3; // 抛出语法错误 SyntaxError
const student = { school: 'My School', fullName: 'John Doe', printName: () = { console.log(this.fullName); }, printSchool: function () { console.log(this.school); }};student.printName();student.printSchool();

const

说明

const 声明的变量很像 let ,但它不能被重新赋值。

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

总结一下 const 变量:

你可能会熟悉以下语法:

块级作用域 分配之前无法访问 在同一个作用域内部,不能重新声明 不能被重新分配

var me = this;// orvar self = this;// ...// ...// somewhere deep...// me.doSomething();
const myVar = "Nick";myVar = "John" // 抛出一个错误, 不允许重新分配

const myVar = "Nick";const myVar = "John" // 抛出一个错误, 不允许重新声明

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

但这里有一个小细节:const 变量并不是不可变,具体来说,如果 const 声明的变量是 objectarray 类型的值,那它是 可变的

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

const person = { name: 'Nick'};person.name = 'John' // 这是有效的!person 变量并非完全重新分配,只是值被改变console.log // "John"person = "Sandra" // 抛出一个错误, 因为用 const 声明的变量不能被重新分配

const person = [];person.push; // 这是有效的!person 变量并非完全重新分配,只是值被改变console.log // "John"person = ["Nick"] // 抛出一个错误, 因为用 const 声明的变量不能被重新分配

5.解构

扩展阅读 How let and const are scoped in JavaScript – WesBos Temporal Dead Zone Demystified箭头函数

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

ES6 JavaScript 更新引入了 箭头函数 ,这是另一种声明和使用函数的方法。以下是他们带来的好处:

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

更简洁 this 的值继承自外围的作用域 隐式返回简单的示例 简洁性和隐式返回

说明

function double { return x * 2; } // 传统的方法console.log // 4

const double = x => x * 2; // 相同的函数写成带有隐式返回的箭头函数console.log // 4

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

this 的引用

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

在箭头函数中, this 意味着封闭执行上下文的 this 值。基本上,使用箭头函数,在函数中调用函数之前,您不需要执行 “that = this” 这样的的技巧。

// {name: "John", surname: "Doe"}// {email: "john@doe.com", displayName: "SuperCoolJohn", joined: "2016-05-05", image: "path-to-the-image", followers: 45}
function myFunc() { this.myVar = 0; setTimeout => { this.myVar++; console.log // 1 }, 0);}

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);})();

隐式 VS 显式返回

说明

显式返回 是指在函数体中明确的使用 return 这个关键字。

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

 function double { return x * 2; // 这个函数显示返回 x * 2, 并且使用了 *return* 关键字 }

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

在函数传统的写法中,返回总是显式的。但是如果是使用箭头函数,你可以执行 隐式返回,这表示你不需要使用关键字 return 来返回一个值。

  1. Return 语句

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

要做隐式回传,代码必须用一行语句写完。

说明

 const double =  => { return x * 2; // 这里是显式返回 }

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

由于这里只有一个返回值,我们可以做一个隐式的返回。

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

 const double =  => x * 2;

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

这样做,我们只需要 移除括号 以及 return 关键字。这就是为什么它会被称为 隐式 返回,return 关键字不在了,但是这个函数确实会返回 x * 2

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

注意: 如果你的函数没有回传一个值 ,那么它将不会做显式或隐式返回。

要么

另外,如果你想隐式地返回一个 对象,你必须用括号包裹,否则它将与块大括号冲突:

{ return ( { result: x * 2 } );}" title="" data-original-title="复制">

const getPerson = () => ({ name: "Nick", age: 24 })console.log // { name: "Nick", age: 24 } -- 箭头函数隐式地返回一个对象
const multiplyByTwo = (x) = { return ( { result: x * 2 } );}

只有一个参数

原文:-quick-javascript-pop-quizzes-with-explanations,作者:Milos Protic

如果你的函数只接受一个参数,你可以省略包裹它的括号。如果我们拿上述的 double 代码做为举例:

翻译:疯狂的技术宅

 const double =  => x * 2; // 这个箭头函数只接受一个参数

包裹参数的括号是可以被省略:

 const double = x => x * 2; // 这个箭头函数只接受一个参数

没有参数

当没有为箭头函数提供任何参数时,你就必须加上括号,否则将会抛出语法错误。

 () => { // 提供括号,一切都能正常运行 const x = 2; return x; }

 => { // 没有括号,这不能正常运行! const x = 2; return x; }

this 引用

要理解箭头函数的精妙之处,你就必须知道 this 在 JavaScript 中是如何运作的。

在一个箭头函数中,this 等同于封闭执行上下文的 this 值。这意味着,一个箭头函数并不会创造一个新的 this,而是从它的外围作用域中抓取的。

如果没有箭头函数,你想在一个函数内部的函数中通过 this 访问变量,你就只能使用 that = this 或者是 self = this 这样的技巧。

举例来说,你在 myFunc 中使用 setTimeout 函数:

function myFunc() { this.myVar = 0; var that = this; // that = this 技巧 setTimeout { // 在这个函数作用域中,一个新的 *this* 被创建 that.myVar++; console.log // 1 console.log // undefined -- 见上诉函数声明 }, 0 );}

但是如果你使用箭头函数,this 是从它的外围作用域中抓取的:

function myFunc() { this.myVar = 0; setTimeout => { // this 值来自它的外围作用域, 在这个示例中,也就是 myFunc 函数 this.myVar++; console.log // 1 }, 0 );}

有用的资源 Arrow functions introduction – WesBos JavaScript arrow function – MDN Arrow function and lexical this函数参数默认值

从 ES2015 JavaScript 更新之后开始,你可以通过下列的语法为函数的参数设定默认值:

function myFunc { return x;}console.log // 10 -- 没有提供任何值,所以在 myFunc 中 10 做为默认值分配给 xconsole.log // 5 -- 有提供一个参数值,所以在 myFunc 中 x 等于 5 console.log // 10 -- 提供 undefined 值,所以默认值被分配给 x console.log // null -- 提供一个值 ,详细资料请见下文 

默认参数应用于两种且仅两种情况:

没有提供参数 提供 undefined 未定义参数

换句话说,如果您传入 null ,则不会应用默认参数。

注意: 默认值分配也可以与解构参数一起使用。

扩展阅读 Default parameter value – ES6 Features Default parameters – MDN解构对象和数组

解构 是通过从存储在对象或数组中的数据中提取一些值来创建新变量的简便方法。

举个简单的实例,destructuring 可以被用来解构函数中的参数,或者像是 React 项目中 this.props 这样的用法。

用示例代码说明 Object

我们考虑一下以下对象的所有属性:

const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M"}

const first = person.firstName;const age = person.age;const city = person.city || "Paris";

使用解构,只需要 1 行代码:

const { firstName: first, age, city = "Paris" } = person; // 就是这么简单!console.log // 35 -- 一个新变量 age 被创建,并且其值等同于 person.ageconsole.log // "Nick" -- 一个新变量 first 被创建,并且其值等同于 person.firstName A new variable first is created and is equal to person.firstNameconsole.log // Undefined -- person.firstName 虽然存在,但是新变量名为 firstconsole.log // "Paris" -- 一个新变量 city 被创建,并且因为 person.city 为 undefined ,所以 city 将等同于默认值也就是 "Paris"。

注意:const { age } = person; 中, const 关键字后的括号不是用于声明对象或代码块,而是 解构 语法。

函数参数

解构 经常被用来解构函数中的对象参数。

function joinFirstLastName { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName;}joinFirstLastName; // "Nick-Anderson"

在解构对象参数 person 这个参数时,我们可以得到一个更简洁的函数:

function joinFirstLastName({ firstName, lastName }) { // 通过解构 person 参数,我们分别创建了 firstName 和 lastName 这两个变数 return firstName + '-' + lastName;}joinFirstLastName; // "Nick-Anderson"

箭头函数中使用解构,使得开发过程更加愉快:

const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName;joinFirstLastName; // "Nick-Anderson"

Array

我们考虑一下以下数组:

const myArray = ["a", "b", "c"];

const x = myArray[0];const y = myArray[1];

const [x, y] = myArray; // 就是这么简单!console.log // "a"console.log // "b"

有用的资源 ES6 Features – Destructuring Assignment Destructuring Objects – WesBos ExploringJS – Destructuring数组方法 – map / filter / reduce

mapfilterreduce 都是数组提供的方法,它们源自于 函数式编程

Array.prototype.map() 接受一组数组,在其元素上执行某些操作,并返回具有转换后的元素数组。 Array.prototype.filter() 接受一组数组,依照元素本身决定是否保留,并返回一个仅包含保留元素的数组。 Array.prototype.reduce() 接受一组数组,将这些元素合并成单个值。

我建议尽可能地使用它们来遵循函数式编程 (functional programming) 的原则,因为它们是可组合的,简洁的且优雅的。

通过这三种方法,您可以避免在大多数情况下使用 forforEach 。当你试图做一个 for 循环时,尝试用 mapfilterreduce 来组合试试。起初你可能很难做到这一点,因为它需要你学习一种新的思维方式,但一旦你得到它,事情会变得更容易。

愚人码头注:JavaScript 函数式编程建议看看以下几篇文章

JavaScript 中的 Currying 和 Partial Application 一步一步教你 JavaScript 函数式编程 一步一步教你 JavaScript 函数式编程 一步一步教你 JavaScript 函数式编程 JavaScript 函数式编程术语大全简单的示例

const numbers = [0, 1, 2, 3, 4, 5, 6];const doubledNumbers = numbers.map; // [0, 2, 4, 6, 8, 10, 12]const evenNumbers = numbers.filter; // [0, 2, 4, 6]const sum = numbers.reduce => prev + next, 0); // 21

通过组合 map,filter 和 reduce 来计算 10 分以上的学生成绩总和 sum :

const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 },];const aboveTenSum = students .map(student => student.grade) // 我们将学生数组映射到他们成绩的数组中 .filter // 我们过滤成绩数组以保持10分以上的元素 .reduce => prev + next, 0); // 我们将合计所有10分以上的成绩console.log // 44 -- 10  + 19 , 低于10的 Nathalie 被忽略 

说明

让我们考虑一下下列数组:

const numbers = [0, 1, 2, 3, 4, 5, 6];

Array.prototype.map()

const doubledNumbers = numbers.map { return n * 2;});console.log; // [0, 2, 4, 6, 8, 10, 12]

这里发生了什么?我们在 numbers 这个数组中使用 .map 方法,map 将会迭代数组的每个元素,并传递给我们的函数。该函数的目标是生成并返回一个新的值,以便 map 可以替换掉原本的数组。

我们来解释一下这个函数,使之更清楚一点:

const doubleN = function { return n * 2; };const doubledNumbers = numbers.map;console.log; // [0, 2, 4, 6, 8, 10, 12]

numbers.map 将会产生 [doubleN, doubleN, doubleN, doubleN] 而它们分别等同于 [0, 2, 4, 6, 8, 10, 12]

注意: 如果你不需要返回一个新的数组, 且只想执行一个带有副作用的循环,使用 for / forEach 循环会更为符合你的需求。

Array.prototype.filter()

const evenNumbers = numbers.filter { return n % 2 === 0; // 如果 "n" 符合条件返回 true , 如果 "n" 不符合条件则 false 。});console.log; // [0, 2, 4, 6]

我们在 numbers 数组中使用 .filter 方法,过滤器遍历数组中的每个元素,并将其传递给我们的函数。函数的目标是返回一个布尔值,它将确定当前值是否被保留。过滤之后返回的数组将只包含保留值。

Array.prototype.reduce()

reduce 方法的目标是将迭代数组中的所有元素,减少 到只留下单一值。如何聚合这些元素取决于你。

const sum = numbers.reduce { return acc + n; }, 0 // 累加器迭代变量的初始值);console.log //21

就像 .map 和 .filter 方法一样, .reduce 方法被应用在数组上并接收一个函数做为第一个参数。

.reduce 接受两个参数

第一个参数是一个函数,将在每个迭代步骤中被调用。

第二个参数是在第一个迭代步骤的累加器变量的值。

函数参数

作为 .reduce 的第一个参数传递的函数需要两个参数。第一个是累加器变量,而第二个参数则是当前元素。

累加器变量的值等于 上一次 迭代步骤中函数的返回值。在迭代过程的第一步,acc 等于你做为 .reduce 时第二个参数所传递的值。

进行第一次迭代

acc = 0 因为我们把 0 做为 reduce 的第二个参数

n = 0 number 数组的第一个元素

函数返回 acc + n –> 0 + 0 –> 0

进行第二次迭代

acc = 0 因为它是上次迭代所返回的值

n = 1 number 数组的第二个元素

函数返回 acc + n –> 0 + 1 –> 1

进行第三次迭代

acc = 1 因为它是上次迭代所返回的值

n = 2 number 数组的第三个元素

函数返回 acc + n –> 1 + 2 –> 3

进行第四次迭代

acc = 3 因为它是上次迭代所返回的值

n = 3 number 数组的第四个元素

函数返回 acc + n –> 3 + 3 –> 6

[…] 进行最后一次迭代

acc = 15 因为它是上次迭代所返回的值

n = 6 number 数组的最后一个元素

函数返回 acc + n –> 15 + 6 –> 21

因为它是最后一个迭代步骤了, .reduce 将返回 21 。

扩展阅读 Understanding map / filter / reduce in JS展开操作符 “…”

ES2015 已经引入了展开操作符 ... ,可以将可迭代多个元素展开到适合的位置。

简单的代码示例

const arr1 = ["a", "b", "c"];const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"]

function myFunc { console.log; console.log}myFunc("a", "b", "c", "d", "e", "f")// "a"// "b"// ["c", "d", "e", "f"]

const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };console.log; // 1console.log; // 2console.log; // { a: 3, b: 4 }const n = { x, y, ...z };console.log; // { x: 1, y: 2, a: 3, b: 4 }

说明应用于迭代

如果我们有以下两个数组:

const arr1 = ["a", "b", "c"];const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"]

本文由10bet发布于Web前端,转载请注明出处:7个常见的 JavaScript 测验及解答

关键词:

最火资讯