React前置JavaScript知识

94 阅读8分钟

1 解构(Destructuring)

解构赋值是ES6引入的新特性。主要包括数组解构和对象解构,它允许我们按照一定模式,从数组和对象中提取值,对变量进行赋值。

1.1 数组解构

let [greeting,pronoun] = ["hello","I","am","Sarah"];
console.log(greeting,pronoun);  //"hello","I"

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。

下面是一些使用嵌套数组进行解构的例子:

let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo,bar,baz)  //1 2 3

let [x, , y] = [1, 2, 3];
console.log(x,y)  //1 3

let [head, ...tail] = [1, 2, 3, 4];  //这里用到了rest运算符
console.log(head,tail)  //1 [2,3,4]

解构赋值允许指定默认值:

let [foo = true] = []; //foo =    true
let [x, y = "b"] = ["a"]; //x='a',y='b'
let [x, y = "b"] = ["a", undefined]; //x='a',y='b'

注意:

  1. 如果解构失败,变量的值就等于undefined。
  2. 不完全解构(等号左边的模式,只匹配一部分的等号右边的数组)的情况下,解构依然可以成功
  3. 如果等号右边不是数据(或者严格来说,不是可遍历的结构),那么将会报错。事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

1.2 对象解构

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的
值。

let person = {name: "Sarah", country: "Nigeria", job: "Developer"};
let {name, job, country} = person;

console.log(name, job, country);//"Sarah","Developer","Nigeria"

如果要将对象的值分配给新变量,而不是使用属性名称,则可以执行以下操作。也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let person = {name: "Sarah", country: "Nigeria", job: "Developer"};
let {name: foo, job: bar} = person;

console.log(foo);//"Sarah"
console.log(bar);//"Developer"

对象的解构也可以指定默认值:

let person = {name: "Sarah", country: "Nigeria", job: "Developer"};
let {name:foo = "myName", friend: bar = "Annie"} = person;

console.log(foo,bar); //"Sarah","Annie"

2 Rest & Spread Operator

JavaScript 使用三个点(...)来表示 rest(剩余运算符)和 spread(扩展运算符),但是这两个运算符是不一样的。

rest 和 spread 的主要区别在于,rest 运算符将一些特定值的其余部分放入一个 JavaScript 数组中,而 spread 语法将可迭代对象展开成一系列用逗号隔开的值。

2.1 Rest Operator

let [head, ...tail] = [1, 2, 3, 4];  
console.log(head,tail)  //1 [2,3,4]

这段代码使用剩余运算符(...)将剩余的变量放入名为tail的数组中。

剩余运算符常被用于函数的最后一个参数的前缀,指示计算机将用户提供的任何参数加入一个数组中,然后将该数组分配给 otherInfo  参数。因此,我们称 ...otherInfo 为 rest 参数。

// 定义一个有两个常规参数和一个 rest 参数的函数
function myBio(firstName, lastName, ...otherInfo) { 
  return otherInfo;
}

注意:剩余运算符只能用于函数定义的最后一个参数之前!

2.2 Spread Operator

扩展运算符(...)可以帮助你将可迭代对象扩展为用逗号隔开的单个元素。

spread 语法在数组字面量、函数调用和初始化属性对象中起作用,将可迭代对象(如数组、对象、字符串)的值扩展到单独的项目中。因此,它做了与 rest 运算符相反的事情。

const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "name."];

console.log(aboutMe); //[ "Oluwatobi", "Sofela", "is", "my", "name." ]

const myName = "Oluwatobi Sofela";
console.log([...myName]);
// [ "O", "l", "u", "w", "a", "t", "o", "b", "i", " ", "S", "o", "f", "e", "l", "a" ]

扩展运算符常被用来往对象中添加新属性,也可以通过重写来修改旧属性

let book = {
  id: 1,
  title: "A Game of Thrones",
  publicationDate: "1996-08-01",
  author: "George R. R. Martin",
};

//向book对象中添加页数page属性
book = {...book,page:835}

//修改原有的id属性:重写该属性
book = {...book,id:10086}

2.3 区别

rest运算符和spread运算符的区别:

  • spread运算符:放在赋值一方,即放在实参或者等号右边
  • rest运算符:放在被赋值一方,即放在形参或者等号左边

3 模板字符串(Template Literals)

模板字符串是增强版的字符串,用反引号`代替单双引号。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量或表达式。

普通字符串:

let text = `my name is "sarah"`

多行字符串:

let text =
`The quick
brown fox
jumps over
the lazy dog`;

除此之外,模板字符串提供了一种将变量或表达式插入字符串的简单方法${...}。该方法称为字符串插值(string interpolation)。

let firstName = "Bill";
let lastName = "Gates";
let text = `Welcome ${firstName}, ${lastName}!`;   //Welcome Bill, Gates!

let price = 10;
let VAT = 0.25;
let total = `Total: ${(price * (1 + VAT)).toFixed(2)}`; //Total: 12.50

4 三元运算符(Ternaries)

在React中我们渲染JSX时往往使用大括号将js代码括起来,大括号中必须是表达式,这种情况下我们无法使用if-else语句(同样适用于模板字符串),因此需要学习三元运算符用来替代if-else语句。

三元运算符一个常见的用法是处理null值:

const greeting = (person) => {
  const name = person ? person.name : "stranger";
  return `Howdy, ${name}`;
}

console.log(greeting({ name: "Alice" }));  // "Howdy, Alice"
console.log(greeting(null));             // "Howdy, stranger"

另一个用法是条件链。三元运算符是右结合的,这意味着它可以按以下方式“链接”起来,类似于 if … else if … else if … else 链:

function example() {
  return condition1 ? value1
        : condition2 ? value2
        : condition3 ? value3
        : value4;
}

// 等价于以下if...else链
function example() {
  if (condition1) {
    return value1;
  } else if (condition2) {
    return value2;
  } else if (condition3) {
    return value3;
  } else {
    return value4;
  }
}

5 箭头函数(Arrow Function)

ES6 允许使用“箭头”(=> )定义函数。下面两种方法定义的函数作用是相同的。

function getBooks() { return data; }

const getBooks = () => data;

在定义代码块只有单条语句的函数时,箭头函数使得表达更加简洁。

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且需要手动return。

const sum = (n1, n2) => {
 return n1 + n2;
};

6 短路和逻辑运算符(Short-Circuiting & Logical Operator)

逻辑与(&&)和逻辑或(||)运算都是简便运算,即如果第一个运算数决定了结果,就不再计算第二个运算数,这就是短路求值。利用短路求值可以大幅减少逻辑判断的代码量,但同时也会降低代码可读性。

在JavaScript中共有5个falsy value:0,null,'',undefined,false。其他任何不是falsy value的值都为truthy value。

  • &&:从左到右选取表达式的第一个为false的表达式的值,如果一直未找到则返回最后一个表达式的值,类似于if判断。
  • ||:从左到右选取表达式的第一个为true的表达式的值,这个运算经常用来判断一个变量是否已定义,如果没有定义就给他一个初始值,在给函数的参数定义一个默认值的时比较有用。

 7 可选链(optional Chaining)

当我们访问一个对象不存在的属性时,会返回undefined。对于undefined我们进一步访问它的属性时会报错。

const book = {
  id: 1,
  title: "A Game of Thrones",
  publicationDate: "1996-08-01",
  author: "George R. R. Martin"
};

console.log(book.name)     // undefined
console.log(book.name.a)   // Cannot read properties of undefined (reading 'a') 

ES6引入了可选链操作符(?.),可以判断操作符之前属性是否有效,从而链式读取对象的属性或返回 undefined 。这里如果 ?. 判断的对象是 nullish(要么是 undefined , 要么是 null ) 值的话,表达式就会短路(不在往后执行),返回 undefined 。

const obj = { a: { b: [{ name: 'obj' }] } }

// 原本的写法
console.log(obj && obj.a && obj.a.b.length && obj.a.b[0].name)

// 可选链写法
console.log(obj?.a?.b?.[0]?.name); // obj
console.log(obj?.b?.c?.d) // undefined

8 高阶数组方法

map、filter 和 reduce 是三种最有用、最强大的高阶数组方法。这三个方法的共同点是它们不会改变原始数组,而是返回一个基于原始数组的新数组。

8.1 map()

map()方法对原数组每个元素进行处理,并回传新的数组。

const arr = [1,2,3,4,5];
const newArr = arr.map(el => el*2);
console.log(newArr)  // [2,4,6,8,10]

8.2 filter()

filter()方法筛选符合条件的所有元素,若为true则返回并组成新数组。下面的代码中,filter() 方法将从arr[0] 开始挑选该数组的每个值,并对每个值进行操作。然后,它将用计算出来的值形成一个新的数组。

const arr = [15, 39, 20, 32, 30, 45, 22];
const divByFive = arr.filter((el) => el % 5 == 0);
console.log(divByFive); // [ 15, 20, 30, 45 ]

8.3 reduce()

reduce()方法接受两个参数,第一个是函数,可以理解为累加器,遍历数组累加回传的返回值,第二个是初始数值。如果没有提供初始值,则将使用数组中的第一个元素。

const array1 = [1, 2, 3, 4];

const initialValue = 0;
const sumWithInitial = array1.reduce(
  (accumulator, currentValue) => accumulator + currentValue,
  initialValue
);

console.log(sumWithInitial); // Expected output: 10

8.4 sort()

 sort()方法用于对数组排序,但是是原地排序,不会复制或返回新数组。

const arr = [15, 39, 20, 32, 30, 45, 22];
arr.sort();
console.log(arr); // [ 15, 20, 22, 30, 32, 39, 45 ]