likes
comments
collection
share

⚡学习react前你需要知道的javascript基础! 我浅看一下

作者站长头像
站长
· 阅读数 18

1. 前言

如果你想学习React,或者任何JavaScript框架,你首先需要理解基本的JavaScript方法和概念。不然的话,这就像是一个孩子在学会走路之前就试图跑步一样~~~

许多开发者在学习React时选择“边学边用”的方法。但这通常不会提高生产力,反而会加剧他们在JavaScript知识方面的空白。这种方法使得理解每个新特性变得更加困难(你可能开始混淆JavaScript和React)。

React是一个基于UI组件的JavaScript框架,所有的代码都是用JavaScript编写的,包括用JSX编写组件(这使得开发者能够轻松地将HTML和JavaScript写在一起)。

在本文中,我们将采用实用的方法,讨论在学习React之前你需要掌握的所有JavaScript思想和技术。

⚡学习react前你需要知道的javascript基础! 我浅看一下

2. 回调函数

回调函数是在另一个函数执行完毕后执行的函数。它通常作为输入传递给另一个函数中。

理解回调函数至关重要,因为它们被广泛应用于数组方法(如 map()filter() 等)、setTimeout()、事件监听器(如点击、滚动等)以及许多其他场景。

以下是一个点击事件监听器的例子,其中包含一个回调函数,每当按钮被点击时,这个函数就会执行:

//HTML
<button class="btn">Click Me</button>

//JavaScript
const btn = document.querySelector('.btn');

btn.addEventListener('click', () => {
  let name = 'John doe';
  console.log(name.toUpperCase())
})

注意:回调函数可以是普通函数,也可以是箭头函数。

3. Promise

Promise是一种异步操作的解决方案,可以将异步代码以同步的方式进行编写。

如前所述,回调函数在原始函数执行后执行。

您现在可能开始考虑将如此多的回调函数堆叠在一起,因为您不希望在父函数完成运行或经过特定时间之前运行特定函数。 例如,让我们尝试显示每个 2 秒后控制台中出现 5 个名称 - 也就是说,第一个名称在 2 秒后出现,第二个名称在 4 秒后出现,依此类推...

setTimeout(() => {
    console.log("Joel");
    setTimeout(() => {
        console.log("Victoria");
        setTimeout(() => {
            console.log("John");
            setTimeout(() => {
                console.log("Doe");
                setTimeout(() => {
                    console.log("Sarah");
                }, 2000);
            }, 2000);
        }, 2000);
    }, 2000);
}, 2000);

上面的示例可以工作,但是很难理解、调试,甚至添加错误处理。这被称为回调地狱。  

回调地狱是由复杂的嵌套回调编码引起的一个大问题。 使用 Promise 的主要原因是为了防止回调地狱。借助 Promise,我们可以以同步方式编写异步代码。

JavaScript Promise 语法:

const myPromise = new Promise((resolve, reject) => {  
    // condition
});

Promise 有两个参数,一个表示成功(resolve),一个表示失败(reject)。

每个 Promise 都有一个必须满足的条件,否则 Promise 将被reject:

const promise = new Promise((resolve, reject) => {  
    let condition;
    
    if(condition is met) {    
        resolve('Promise is resolved successfully.');  
    } else {    
        reject('Promise is rejected');  
    }
});

Promise 对象有 3 种状态:

  • Pending:默认情况下,这是 Promise 成功或失败之前的初始状态。

  • Resolved:完成的 Promise

  • Rejected:失败的 Promise

最后,让我们尝试将回调地狱重新实现为 Promise

function addName (time, name){
  return new Promise ((resolve, reject) => {
    if(name){
      setTimeout(()=>{
        console.log(name)
        resolve();
      },time)
    }else{
      reject('No such name');
    }
  })
}

addName(2000, 'Joel')
  .then(()=>addName(2000, 'Victoria'))
  .then(()=>addName(2000, 'John'))
  .then(()=>addName(2000, 'Doe'))
  .then(()=>addName(2000, 'Sarah'))
  .catch((err)=>console.log(err))

4. Map()

最常用的方法之一是 Array.map(),它允许您迭代数组并使用回调函数修改其元素。

回调函数将在每个数组元素上运行。

假设我们有一个包含用户信息的用户数组。

let users = [
  { firstName: "Susan", lastName: "Steward", age: 14, hobby: "Singing" },
  { firstName: "Daniel", lastName: "Longbottom", age: 16, hobby: "Football" },
  { firstName: "Jacob", lastName: "Black", age: 15, hobby: "Singing" }
];

我们可以使用map循环并修改它的输出

let singleUser = users.map((user)=>{
  //let's add the firstname and lastname together
  let fullName = user.firstName + ' ' + user.lastName;
  return `
    <h3 class='name'>${fullName}</h3>
    <p class="age">${user.age}</p>
  `
});
  • map() 始终返回一个新数组,即使它是一个空数组。

  • 它不会改变原始数组。

  • 在创建新数组时,它始终使用原始数组中的值。

map 方法的工作方式几乎与其他所有 JavaScript 迭代器(例如 forEach())一样,但每当您要返回值时,最好始终使用 map 方法。

5. Filter() and Find()

Filter() 根据某些条件提供一个新数组。与 map() 不同,它可以改变新数组的大小

find() 仅返回单个实例(这可能是一个对象或项)。如果存在多个匹配项,则返回第一个匹配项,否则返回未定义。

Filter()

假设您有一个包含不同年龄的注册用户的数组集合:

let users = [
  { firstName: "Susan", age: 14 },
  { firstName: "Daniel", age: 16 },
  { firstName: "Bruno", age: 56 },
  { firstName: "Jacob", age: 15 },
  { firstName: "Sam", age: 64 },
  { firstName: "Dave", age: 56 },
  { firstName: "Neils", age: 65 }
];

你可以选择按年龄段对这些数据进行排序,比如年轻人(1-15岁)、老年人(50-70岁)等等...

这种情况下,过滤功能就派上用场了因为它根据条件生成一个新数组。

// for young people
const youngPeople = users.filter((person) => {
  return person.age <= 15;
});

//for senior people
const seniorPeople = users.filter((person) => person.age >= 50);

console.log(seniorPeople);
console.log(youngPeople);

这会生成一个新数组。如果不满足条件(不匹配),它会生成一个空数组。

Find()

find() 方法与 filter() 方法类似,会在数组中迭代查找满足指定条件的实例/项目。一旦找到它,它就会返回该特定的数组项并立即终止循环。

如果未发现匹配,该函数将返回undefined

const Bruno = users.find((person) => person.firstName === "Bruno");

console.log(Bruno);

6. 数组解构

解构是 ES6 中引入的 JavaScript 功能,它允许更快、更简单地访问和解包数组和对象中的变量。

在解构引入之前,如果我们有一个水果数组,并且想要获取第一个、第二个和分开第三个水果,我们最终会得到这样的结果:

let fruits= ["Mango", "Pineapple" , "Orange", "Lemon", "Apple"];

let fruit1 = fruits[0];
let fruit2 = fruits[1];
let fruit3 = fruits[2];

console.log(fruit1, fruit2, fruit3); //"Mango" "Pineapple" "Orange"

这就像一遍又一遍地重复同样的事情,这可能会变得很麻烦。

让我们看看如何对其进行解构以获得前 3 个水果

let [fruit1, fruit2, fruit3] = fruits;

console.log(fruit1, fruit2, fruit3); //"Mango" "Pineapple" "Orange"

小伙伴可能想知道如果您只想打印第一个最后一个水果,或者第二个和第四个水果,如何跳过数据。

可以按如下方式使用逗号:

const [fruit1 ,,,, fruit5] = fruits;
const [,fruit2 ,, fruit4,] = fruits;

7. 对象解构

假设我们有一个用户对象,其中包含他们的名字、姓氏等等

const Susan = {
  firstName: "Susan",
  lastName: "Steward",
  age: 14,
  hobbies: {
    hobby1: "singing",
    hobby2: "dancing"
  }
};

按照旧的方式,获取这些数据会充满重复的工作量~~~:

const firstName = Susan.firstName;
const age = Susan.age;
const hobby1 = Susan.hobbies.hobby1;

console.log(firstName, age, hobby1); //"Susan" 14 "singing"

但通过解构它就容易多了:

const {firstName, age, hobbies:{hobby1}} = Susan;

console.log(firstName, age, hobby1); //"Susan" 14 "singing"

我们也可以在函数中执行此操作:

function individualData({firstName, age, hobbies:{hobby1}}){
  console.log(firstName, age, hobby1); //"Susan" 14 "singing"
}
individualData(Susan);

休息一下~~~

⚡学习react前你需要知道的javascript基础! 我浅看一下

8. 剩余运算符和扩展运算符

# 剩余运算符扩展运算符使用三个点...来表示

剩余运算符(rest)

rest收集项目, 它将某些用户提供的值的“剩余”放入 数组/对象中。

假设您有一个水果数组:

let fruits= ["Mango", "Pineapple" , "Orange", "Lemon", "Apple"];

我们可以解构以获得第一个第二个水果,然后通过使用剩余运算符将其余水果放入数组中。

const [firstFruit, secondFruit, ...rest] = fruits

console.log(firstFruit, secondFruit, rest); //"Mango" "Pineapple" ["Orange","Lemon","Apple"]

rest必须始终放在最后(位置非常重要)。

我们刚刚处理过数组, 现在让我们处理对象吧~~~

假设我们有一个有名字、姓氏等信息的用户对象。我们可以对其进行解构,然后提取剩余的数据。

const Susan = {
  firstName: "Susan",
  lastName: "Steward",
  age: 14,
  hobbies: {
    hobby1: "singing",
    hobby2: "dancing"
  }
};

const {age, ...rest} = Susan;
console.log(age, rest);

这将记录以下结果:

14
{
firstName: "Susan" ,
lastName: "Steward" ,
hobbies: {...}
}

扩展运算符

用于扩展数组项。它使我们能够从数组中获取参数列表。

扩展运算符的语法与剩余运算符类似,只是它的操作方向相反

注意:扩展运算符仅在数组、函数调用或初始化属性对象中使用时才有效。

例如,假设有不同类型动物的数组:

let pets= ["cat", "dog" , "rabbits"];

let carnivorous = ["lion", "wolf", "leopard", "tiger"];

想将这两个数组合并为一个动物数组。让我们尝试一下:

let animals = [pets, carnivorous];

console.log(animals); //[["cat", "dog" , "rabbits"], ["lion", "wolf", "leopard", "tiger"]]

这不是我们想要的——我们希望所有项目都位于一个数组中。我们可以使用展开运算符来实现这一点:

let animals = [...pets, ...carnivorous];

console.log(animals); //["cat", "dog" , "rabbits", "lion", "wolf", "leopard", "tiger"]

这也适用于对象。需要注意的是,扩展运算符无法扩展不能迭代的对象。

let name = {firstName:"John", lastName:"Doe"};
let hobbies = { hobby1: "singing", hobby2: "dancing" }
let myInfo = {...name, ...hobbies};

console.log(myInfo); //{firstName:"John", lastName:"Doe", hobby1: "singing", hobby2: "dancing"}

9. Set()

简单说,就是用来去除重复的值。

let animals = [
  {
    name:'Lion',
    category: 'carnivore'
  },
  {
    name:'dog',
    category:'pet'
  },
  {
    name:'cat',
    category:'pet'
  },
  {
    name:'wolf',
    category:'carnivore'
  }
]

第一件事是循环遍历数组,但我得到了重复的值:

let category = animals.map((animal)=>animal.category);
console.log(category); //["carnivore" , "pet" , "pet" , "carnivore"]

这时,我们可以使用Set():

//wrap your iteration in the set method like this
let category = [...new Set(animals.map((animal)=>animal.category))];

console.log(category); ////["carnivore" , "pet"]

10. 对象的动态键

我们知道对象通常由属性/键和值组成,并且我们可以使用点符号来添加、编辑或访问某些值。

举个例子:

let lion = {
  category: "carnivore"
};

console.log(lion); // { category: "carnivore" }
lion.baby = 'cub';
console.log(lion.category); // carnivore
console.log(lion); // { category: "carnivore" , baby: "cub" }

标准命名约定只允许camelCasesnake_case,如果有些键没有使用标准命名怎么办呢?

可以使用方括号[]表示法我们可以解决这个问题。

let lion = {
  'lion-baby' : "cub"
};

// dot notation
console.log(lion.lion-baby); // error: ReferenceError: baby is not defined
// bracket notation
console.log(lion['lion-baby']); // "cub"

您可以看到点符号括号符号之间的区别。再来点其他例子:

let category = 'carnivore';
let lion = {
  'lion-baby' : "cub",
  [category] : true,
};

console.log(lion); // { lion-baby: "cub" , carnivore: true }

甚至还可以加点运算~~~ 让我们玩出点花

const number = 5;
const gavebirth = true;

let animal = {
  name: 'lion',
  age: 6,
  [gavebirth && 'babies']: number
};

console.log(animal); // { name: "lion" , age: 6 , babies: 5 }

11. reduce()

reduce()方法用于对数组元素进行累加或合并操作,返回一个单一的值。

这可以说是最强大的数组函数。它有时可以取代filter()find()方法,并且在对大量数据执行map()filter()方法时也非常方便。

第一个参数是所有计算的总和/总计,并且第二个是当前迭代值。

例如,假设我们有一个员工的工资列表:

let staffs = [
  { name: "Susan", age: 14, salary: 100 },
  { name: "Daniel", age: 16, salary: 120 },
  { name: "Bruno", age: 56, salary: 400 },
  { name: "Jacob", age: 15, salary: 110 },
  { name: "Sam", age: 64, salary: 500 },
  { name: "Dave", age: 56, salary: 380 },
  { name: "Neils", age: 65, salary: 540 }
];

我们想把所有员工的薪水加一起,用reduce()非常容易实现

const totalSalary = staffs.reduce((total, staff) => {
  total += staff.salary;
  return total;
},0)
console.log(totalSalary); // 2150

我们传递了第二个参数0,即总数,初始值是0。它可以是任何东西,例如数字或对象。

现在让我们计算所有员工的 10%的税加一下并得出总数。

const salaryInfo = staffs.reduce(
  (total, staff) => {
    let staffTithe = staff.salary * 0.1;
    total.totalTithe += staffTithe;
    total['totalSalary'] += staff.salary;
    return total;
  },
  { totalSalary: 0, totalTithe: 0 }
);

console.log(salaryInfo); // { totalSalary: 2150 , totalTithe: 215 }

12. 可选链

可选链是一种在 JavaScript 中访问嵌套对象属性的安全方法,而不必在访问长链对象属性时执行多个 null 检查。 这是ES2020中引入的新功能。

let users = [
{
    name: "Sam",
    age: 64,
    hobby: "cooking",
    hobbies: {
      hobb1: "cooking",
      hobby2: "sleeping"
    }
  },
  { name: "Bruno", age: 56 },
  { name: "Dave", age: 56, hobby: "Football" },
  {
    name: "Jacob",
    age: 65,
    hobbies: {
      hobb1: "driving",
      hobby2: "sleeping"
    }
  }
];

假设您试图从上面的数组中获取hobbies。让我们尝试一下:

users.forEach((user) => {
  console.log(user.hobbies.hobby2);
});

当您查看控制台时,您会注意到第一次迭代已完成,但第二次迭代没有任何hobbies

因此它必须抛出一个错误并退出迭代——这意味着它无法从数组中的其他对象获取数据

"sleeping"
error: Uncaught TypeError: user.hobbies is undefined

尽管有多种方法可以修复此错误(例如,使用条件),但可以通过可选链接来修复此错误。

让我们看看如何使用条件和可选链来做到这一点:

条件:

users.forEach((user) => {
  console.log(user.hobbies && user.hobbies.hobby2);
});

可选链:

users.forEach((user) => {
  console.log(user?.hobbies?.hobby2);
});

输出

"sleeping"
undefined
undefined
"sleeping"

13. Fetch API

Fetch API用于在JavaScript中进行基本的AJAX请求,获取API数据。

它是由浏览器提供的,所以您可以使用它而无需安装或导入任何包或依赖项(例如轴)。

它的配置相当简单易懂。

fetch API 默认提供一个 Promise(我在本文前面介绍过 Promise)。

    fetch('https://type.fit/api/quotes')
      .then(response => response.json())
      .then(data => console.log(data))

接着,让我们看下如何处理接口请求时的错误

fetch("https://type.fit/api/quotes")
  .then((response) => {
    if (!response.ok) {
      throw Error(response.statusText);
    }
    return response.json();
  })
  .then((data) => console.log(data))
  .catch((err) => console.log(err));

14. Async/Await

Async/Await 允许我们以同步方式编写异步代码。这意味着我们不需要继续嵌套回调。

异步函数总是返回一个promise

小伙伴们可能想知道同步异步之间的区别是什么?

简单地说:

  • 同步意味着作业一个接一个地完成。

  • 异步意味着任务是独立完成的。

请注意,我们总是在函数前面加上 async,并且只有在有 async 的情况下才可以使用await。

现在让我们使用 async/await 实现之前处理的 Fetch API 代码:

const fetchData = async () =>{
  const quotes = await fetch("https://type.fit/api/quotes");
  const response = await quotes.json();
  console.log(response);
}

fetchData();

嗯,看起来这更容易阅读了~~~

小伙伴可能想知道我们如何使用 async/await 处理错误

const fetchData = async () => {
  try {
    const quotes = await fetch("https://type.fit/api/quotes");
    const response = await quotes.json();
    console.log(response);
  } catch (error) {
    console.log(error);
  }
};

fetchData();

参考资料:Top JavaScript Concepts to Know Before Learning React

15. 总结

到这,学习react前的一些javascript基础就结束啦~~~

这些是学习React之前必须掌握的JavaScript核心概念

通过理解和熟练掌握这些概念,你将为学习和使用React打下坚实的基础。

不知道坚持看下来的小伙伴有多少? 希望坚持看到这的小伙伴给博主点个赞支持一下吧~~~

欢迎转载,但请注明来源。 最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

⚡学习react前你需要知道的javascript基础! 我浅看一下

转载自:https://juejin.cn/post/7390188606256103424
评论
请登录