学习 React 需要具备的 JavaScript 知识

为什么要学习 React?

  • React 可以与任何其他库或框架无缝集成,因为 React 是一个仅视图库(它是 Model View C ontroler MVC 架构 UI 模式的视图部分),使用任何其他框架和库的自由使实验和创新成为可能
  • React 有一个相对简单的 API,因此没有陡峭的学习曲线
  • JSX 代表 Javascript Syntax Extension,它允许您在 JavaScript 中使用 HTML 和 XML
  • React 实现了单向数据流,这使得对您的应用程序的推理变得容易
  • React 是一个非常受欢迎且不断发展的库,这意味着 React 社区很大,而且还在不断增长

要学习 React 需要 JavaScript,当然建议直接 ECMAScript,关系参考 ECMAScript-know

入门知识

变量、运算符、表达式

在 2015 年之前,唯一可用于声明变量的关键字是 var 关键字,随着 JavaScript ES6 的引入,出现的两个新关键字是 constlet

  • const 声明一个只读的常量,一旦声明,常量的值就不能改变
  • let 声明一个块级作用域的本地变量,可选地可以初始化为一个值
  • var 声明一个函数作用域或全局作用域的变量,可选地可以初始化为一个值,实际上已经被 letconst 取代

怎样用它们

  • 不要使用 var,因为 let 和 const 更具体
  • 默认值使用 const,因为它不能被重新分配或重新声明
  • let 将来要重新分配变量时使用
  • 使用频率 const > let > var

JavaScript 运算符可以大致分为以下几类:

  • 算术运算符:+-*/%++--
  • 赋值运算符:=+=-=*=/=%=<<=>>=>>>=&=^=|=
  • 逻辑运算符:&&||!
  • 比较运算符:==!====!==>>=<<=
  • 位运算符:&|^~<<>>>>>
  • 条件运算符:? :
  • 字符串运算符:+
  • 逗号运算符:,
  • typeof 运算符:typeof
  • instanceof 运算符:instanceof
  • delete 运算符:delete
  • void 运算符:void
  • in 运算符:in
// 部分示例
console.log("2 + 3 = " + (2 + 3)) // 2 加上 3 的和
console.log("2 - 3 = " + (2 - 3)) // 2 减去 3 的差
console.log("2 * 3 = " + (2 * 3)) // 2 乘以 3 的积
console.log("6 / 3 = " + (6 / 3)) // 6 除以 3 的商
console.log("7 / 3 = " + (7 / 3)) // 7 除以 3 的商
console.log("7 % 3 = " + (7 % 3)) // 7 除以 3 的余数
console.log("2 ** 3 = " + (2 ** 3)) // 2 的 3 次方
console.log("1 OR 1 = " + (1 || 1)) // 1 OR 1
console.log("1 OR 0 = " + (1 || 0)) // 1 OR 0
console.log("0 OR 0 = " + (0 || 0)) // 0 OR 0
console.log("1 AND 1 = " + (1 && 1)) // 1 AND 1
console.log("1 AND 0 = " + (1 && 0)) // 1 AND 0
console.log("0 AND 0 = " + (0 && 0)) // 0 AND 0
console.log(!true) // NOT TRUE
console.log(!1) // NOT TRUE
console.log(!false) // NOT FALSE
console.log(!0) // NOT FALSE
console.log(1 > 2) //false
console.log(1 < 2) //true
console.log(1 == 1) //true
console.log(1 != 1) //false

表达式是一种计算值的 JavaScript 语法结构,表达式可以是字面量、变量、关键字、运算符、函数调用等,下面提到了 JavaScript 中使用的一些基本表达式和关键字:

  • this: 指向当前对象
  • super: 调用对象父对象的方法,例如调用父对象的构造函数
  • function: 用于定义函数
  • function*: 用于定义生成器函数
  • async function: 用于定义异步函数

JavaScript 中引入的另一个语言特性称为对象解构,它允许您将对象的属性分配给变量,这样就可以使用变量而不是对象属性来访问属性值

const student = {
ID: '21',
NAME: 'Jhon',
GPA: '3.0',
}; let id = student.ID;
let name = student.NAME;
let gpa = student.GPA; console.log(id);
console.log(name);
console.log(gpa); // 使用对象解构
const { id, name, gpa } = student;
console.log(id);
console.log(name);
console.log(gpa); // 使用对象解构并重命名
const { id: studentId, name: studentName, gpa: studentGpa } = student;
console.log(studentId);
console.log(studentName);
console.log(studentGpa);

解构的另一个例子可能是:

// 正常写法
function Greeting(props) {
return <h1>{props.greeting}</h1>;
} // 使用解构
function Greeting({ greeting }) {
return <h1>{greeting}</h1>;
}

解构也适用于 JavaScript 数组:

// 其余解构到 rest 数组
const { users, ...rest } = this.state;

在 React 中经常使用的另一个 JavaScript 特性是 Spread Operator,它允许您将数组或对象的内容展开,假设我们想要连接两个数组,我们要么通过使用 concat 函数来实现,或者我们可以使用 Spread Operator 做同样的事情

// 使用 concat 函数
a = [1,2,3];
b = [4,5,6];
c = a.concat(b);
console.log("c: " + c); // 使用 Spread Operator
a = [1,2,3];
b = [4,5,6];
c = [...a, ...b];
console.log("c: " + c); // 在 React 中,您可以使用 Spread Operator 组合两个对象,并向该对象添加额外的属性
const person = { name: "Jhon"};
const student = { ID: "21", GPA: "3.0"}; const new_object = { ...person, ...student, semester: '3'};
console.log(new_object);

函数

函数是 JavaScript 中的一等公民,这意味着函数可以像其他任何 JavaScript 对象一样被传递、存储和使用。函数是一种特殊的对象,它可以被调用,它可以有属性和方法,它可以被传递给其他函数,它可以从其他函数返回,它可以具有自己的属性和方法。

典型的 JavaScript 函数具有以下特征:

  • 关键字 function
  • 函数名
  • 参数列表
  • 函数体
  • 返回值

命名函数和匿名函数有什么区别?

  • 命名函数可以在函数体内部递归调用自身,而匿名函数则不行,因为匿名函数没有名称,因此无法在函数体内部递归调用自身
  • 命名函数可以在函数体外部调用自身,而匿名函数则不行,因为匿名函数没有名称,因此无法在函数体外部调用自身

声明 JavaScript 函数的方法

  • 函数声明:这是在 JavaScript 中声明函数的最典型方法

    使用此方法声明的所有函数都允许提升;意味着它们可以在声明之前使用

    function function_name(Arg1, Arg2..){}                      // 函数声明
  • 函数表达式:这是最常用的类型,它可以是命名函数表达式或匿名函数表达式,当您想将函数作为对象分配给变量时,它最适合使用

    var var_name = function function_name(Arg1,Arg2..){};       // 命名函数表达式
    var var_name = function(Arg1, Arg2..){}; // 匿名函数表达式
  • 生成器函数:它用于声明一个生成器函数,该函数使用 yield 关键字返回一个 Generator-Iterator 对象,next 稍后可以调用该对象的方法

    function* function_name(Arg1, Arg2..){}                     // 生成器函数声明
  • 生成器函数表达式:这与我们上面刚刚讨论的类型非常相似,唯一的区别是它允许从函数中省略名称

    var var_name = function* function_name(Arg1, Arg2..){};     // 生成器函数表达式
  • 箭头函数:在 ES6 中引入此类函数

    为函数表达式编写更短的语法并摆脱 this 值,如果函数只接受一个参数,则可以排除函数括号;如果函数体内只有一个语句,您也可以删除大括号

    var var_name = (Arg1, Arg2..) => {};                        // 箭头函数表达式
  • 函数构造器:这是最不推荐的函数声明方式

    在这里,Function 关键字实际上是一个创建新函数的构造函数。传递给构造函数的参数成为新创建函数的参数,最后一个参数是一个字符串,它被转换成一个函数体。这可能会导致安全和引擎优化问题,这就是为什么始终不建议使用它的原因。

    var var_name = new Function("Arg1", "Arg2..", "function_body");  // 函数构造器

在 React 中经常使用它们来使事情变得更高效和更简单(事件处理、防止错误等)

// 不使用箭头函数
const students = [
{ ID: 1, present: true},
{ ID: 2, present: true},
{ ID: 3, present: false},
]; const presentStudents = students.filter(function(student){return student.present;});
console.log(presentStudents); // 使用箭头函数
const students = [
{ ID: 1, present: true},
{ ID: 2, present: true},
{ ID: 3, present: false},
];
const presentStudents = students.filter((student) => student.present);
console.log(presentStudents);

在编写箭头函数或将现有函数转换为箭头函数时,必须牢记以下几点:

  • 如果函数体只有一行,则可以省略 return 关键字和大括号
  • 如果函数只有一个参数,则可以省略括号
  • 如果函数没有参数,则必须使用空括号

React 中的高阶函数

import React from 'react';

export default class App extends React.Component {

  constructor(props){
super(props); this.state = {
query: '',
}; this.onChange=this.onChange.bind(this);
} onChange(event) {
this.setState({ query: event.target.value });
} render() {
const users = [
{ name: 'Robin' },
{ name: 'Markus' }, ];
return (
<div>
<ul>
{ users
.filter(user => this.state.query === user.name)
.map(myuser => <li>{myuser.name}</li>)
}
</ul>
<input
type="text"
onChange={this.onChange}
/>
</div>
);
}
}

并不总是希望提取函数,因为它会增加不必要的复杂性,但另一方面,它可以对 JavaScript 产生有益的效果

import React from 'react';

function doFilter(user) {
return query === user.name;
} export default class App extends React.Component { constructor(props){
super(props); this.state = {
query: '',
}; this.onChange=this.onChange.bind(this);
} onChange(event) {
this.setState({ query: event.target.value });
} render() {
const users = [
{ name: 'Robin' },
{ name: 'Markus' }, ];
return (
<div>
<ul>
{ users
.filter(doFilter)
.map(myuser => <li>{myuser.name}</li>)
}
</ul>
<input
type="text"
onChange={this.onChange}
/>
</div>
);
}
}

之前的实现不起作用,因为该 doFilter() 函数需要了解来自状态的查询属性,因此您可以通过将它与另一个导致高阶函数的函数包装起来,将其传递给该函数

import React from 'react';

function doFilter(query) {
return function (user) {
return query === user.name;
}
} export default class App extends React.Component { constructor(props){
super(props); this.state = {
query: '',
}; this.onChange=this.onChange.bind(this);
} onChange(event) {
this.setState({ query: event.target.value });
} render() {
const users = [
{ name: 'Robin' },
{ name: 'Markus' }, ];
return (
<div>
<ul>
{ users
.filter(doFilter(this.state.query))
.map(myuser => <li>{myuser.name}</li>)
}
</ul>
<input
type="text"
onChange={this.onChange}
/>
</div>
);
}
}

通过使用 JavaScript ES6 箭头函数,可以使高阶函数更加简洁

import React from 'react';

const doFilter = query => user =>
query === user.name; export default class App extends React.Component { constructor(props){
super(props); this.state = {
query: '',
}; this.onChange=this.onChange.bind(this);
} onChange(event) {
this.setState({ query: event.target.value });
} render() {
const users = [
{ name: 'Robin' },
{ name: 'Markus' }, ];
return (
<div>
<ul>
{ users
.filter(doFilter(this.state.query))
.map(myuser => <li>{myuser.name}</li>)
}
</ul>
<input
type="text"
onChange={this.onChange}
/>
</div>
);
}
}

将这些函数提取到 React 组件外部的(高阶)函数中也有利于单独测试 React 的本地状态管理

import React from 'react';

export const doIncrement = state =>
({ counter: state.counter + 1 }); export const doDecrement = state =>
({ counter: state.counter - 1 }); export default class Counter extends React.Component {
state = {
counter: 0,
}; onIncrement = () => {
this.setState(doIncrement);
} onDecrement = () => {
this.setState(doDecrement);
} render() {
return (
<div>
<p>{this.state.counter}</p> <button onClick={this.onIncrement} type="button">Increment</button>
<button onClick={this.onDecrement} type="button">Decrement</button>
</div>
);
}
}

在 React 中 Map, Reduce, Filter

  • Map - 用于遍历数组,返回一个新数组
  • Reduce - 用于遍历数组,返回一个值
  • Filter - 用于过滤数组,返回一个新数组

JavaScript 类和对象

类对于 JavaScript 来说相对较新,因为以前也只有 JavaScript 的原型链可以用于继承,JavaScript 中的类是原型链上的语法糖

类是一种独立的语法结构,它可以用于创建对象【它们可以包含构造函数、属性、方法】具有自己的上下文——方法(函数)和属性(变量)的集合

// 创建一个类,使用关键字 class
class Developer { // 构造函数,使用关键字 constructor
constructor(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
} getName() {
return `${this.firstname} ${this.lastname}`;
}
} // 可以使用关键字创建一个新对象 new
var me = new Developer('Robin', 'Wieruch'); console.log(me.getName());

类——如前所述——对于 Javascript 来说是相对较新的,对象很像类

let computer = { brand : 'HP', RAM : '8 GB', clockspeed : "2 GHz"};

// 对象定义有空格和换行
let computer2 = {
brand : 'HP',
RAM : '8 GB',
clockspeed : "2 GHz"
}; // 对象也可以使用方法
let computer3 = {
brand : 'HP',
RAM : '8 GB',
clockspeed : "2 GHz", printRam() {
console.log(this.RAM)
}
}

我们将研究臭名昭著的 this 关键字在显式、隐式、new 和全局绑定的上下文中如何在 JavaScript 中发挥作用

  • call() - 用于调用一个对象的一个方法,以另一个对象替换当前对象
  • apply() - 与 call() 方法类似,区别是接受的是参数数组
  • bind() - 会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind() 方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数
// call() 方法示例
let obj = {num: 2};
let addToThis = function(a, b, c) {
return this.num + a + b + c;
};
addToThis.call(obj, 1, 2, 3); // 8 // apply() 方法示例
let arr = [1, 2, 3];
let sum = function(a, b, c) {
return a + b + c;
};
sum.apply(null, arr); // 6 // bind() 方法示例
let module = {
x: 42,
getX: function() {
return this.x;
}
};
let getX = module.getX.bind(module); // 42

类继承

  • 类用于面向对象编程中的继承:

    • 继承使新类能够继承现有类的属性和方法
    • 另一个类继承的类称为 超类或基类
    • 从超类继承的类称为 子类或派生类
  • 在 JavaScript 中,extends 关键字可用于从一个类继承另一个类

随着您在 React 之旅中的进步,您将意识到与类组合相比,继承在某种程度上是有限的,如果想了解为什么可以参考 Gorilla/Banana Problem

  • 继承遵循 IS-A 原则,这意味着子类是父类
  • 组合使用 HAS-A 原则,因此类可以包含其他类的实例

组合相对于继承的优势

  • 类别分类法不必预先定义,这使代码动态并适应变化
  • 由于必须对代码进行较少的更改,因此引入的错误也会减少
  • 代码更可重用

模块化

模块化是一种将代码分解为可重用单元的方法,这些单元可以独立开发和维护

  • 默认情况下,模块中定义的类是私有的,不能被项目中存在的其他文件访问,但是可以通过导出类来使其公开
  • 始终建议为每个文件只定义一个类,以使其具有很强的内聚性

export 和 import 语句作用

  • export 语句用于从模块中导出函数、对象或原始值
  • import 语句用于从其他模块导入函数、对象或原始值

模块命名和默认导出

  • 模块名称是模块的文件名,但是可以在模块中使用 export default 语句来指定默认导出的名称

    export default class_name {....}
  • 从模块导入默认导出类时,可以使用任何名称,但是建议使用与模块名称相同的名称

    import class_name from module_name;

React 中的库

  • React Router - 用于管理 React 应用程序中的路由
  • Redux - 用于管理 React 应用程序中的状态
  • React Bootstrap - 用于创建 React 应用程序的 Bootstrap 组件
  • React Native - 用于创建原生移动应用程序的 React 库
  • React Native Web - 用于在 Web 上创建 React Native 应用程序的库
  • React Native Elements - 用于创建 React Native 应用程序的 UI 组件
  • ...

React

React 是一个用于构建用户界面的 JavaScript 库

  • 组件是 React 应用程序的基本构建块
  • 组件是一个独立的、可重用的代码块,它可以用于构建复杂的 UI
  • 组件可以包含其他组件,这使得构建复杂的 UI 变得更容易

学习修改我们的组件并使用 props 使它们更加动态

  • 组件可以接受输入,这些输入称为 props
  • props 是从父组件传递给子组件的数据
  • props 是只读的,这意味着子组件不能修改它们

React 中的状态

  • 组件可以拥有自己的状态
  • 组件的状态是一个对象,它包含组件的数据
  • 组件的状态是私有的,组件可以通过 setState() 方法来更新它

React 中的生命周期

  • React 组件有三种状态:挂载、更新、卸载
  • 挂载是指将组件插入 DOM 的过程,通过 componentWillMount() 实现挂载
  • 更新是指重新渲染组件以更新 UI 的过程,通过 componentDidUpdate() 实现更新
  • 卸载是指将组件从 DOM 中删除的过程,通过 componentWillUnmount() 实现卸载
  • 每个组件都有一个生命周期,它包含了组件从创建到销毁的过程

React 组件 Syntax

  • React 组件可以使用 ES6 类语法或 ES5 React.createClass() 方法来创建
  • 在早期阶段,React.createClass() 方法是创建 React 类组件的默认方式
  • 如今,它不再被使用了,因为随着 JavaScript ES6 的兴起,之前使用的 React 类组件语法成为了默认语法

Functions 在 React 中最为组件

  • 函数组件是一种简单的组件,它只接受 props 作为输入并返回 React 元素作为输出
  • 函数组件是无状态的,这意味着它们不会存储状态
  • 函数组件是纯函数,这意味着它们不会修改输入并且具有相同的输入总是返回相同的输出

附录

当然此处对 React 的学习还有很多,但是我觉得这些是最基础的,如果你想要深入学习 React,可以参考官方文档,网址:<React>

学习内容在 Educative 课程 Entering React after learning JavaScript

学习 React 需要具备的 JavaScript 知识的更多相关文章

  1. 2021 年学习 React 的所需要的 JavaScript 基础

    在理想的情况中,您可以先了解所有有关 JavaScript 和 web 开发的知识,然后再深入了解React. 但是,我们没有办法这样,如果等你把所有 JavaScript 的知识都掌握了再去学习 R ...

  2. 学习React之前你需要知道的的JavaScript基础知识

    在我的研讨会期间,更多的材料是关于JavaScript而不是React.其中大部分归结为JavaScript ES6以及功能和语法,但也包括三元运算符,语言中的简写版本,此对象,JavaScript内 ...

  3. 深入浅出 React Native:使用 JavaScript 构建原生应用

    深入浅出 React Native:使用 JavaScript 构建原生应用 链接:https://zhuanlan.zhihu.com/p/19996445 原文:Introducing React ...

  4. 为什么学习React Native三点原因

    React Native不到两岁,兼容Android平台刚刚1年.我学习React Native其实也就不到1年,不算长,也不算短. Paul Graham在文章中写过:大多数人真正注意到你的时候,不 ...

  5. 如何在2023年学习React

    在2023年学习React并不是一件容易的事情.自2019年React Hooks发布以来,我们已经拥有了很多稳定性,但现在形势正在再次变化.而这次变化可能比使用React Hooks时更加不稳定.在 ...

  6. React 基础入门,基础知识介绍

    React不管在demo渲染还是UI上,都是十分方便,本人菜鸟试试学习一下,结合阮一峰老师的文章,写下一点关于自己的学习react的学习笔记,有地方不对的地方,希望各位大牛评论指出: PS:代码包下载 ...

  7. 《jQuery风暴》第2章 必须知道的JavaScript知识

    第2章 必须知道的JavaScript知识 JavaScript是jQuery应用的基础,掌握JavaScript这门语言是使用jQuery的基础条件.本章不会全面细致的讲解JavaScript的全部 ...

  8. 正式学习React(一) 开始学习之前必读

    为什么要加这个必读!因为webpack本身是基于node环境的, 里面会涉及很多路径问题,我们可能对paths怎么写!webpack又是怎么找到这些paths的很迷惑. 本文是我已经写完正式学习Rea ...

  9. 正式学习 react(三)

    有了基础的webpack基础,我们要对react的基本语法进行学习. 我这个教程全部用es6 实现.可能会忽略一些最基本的语法讲解,这些你在官网上或者其他别的地方都比我讲的全. 今天我要讲一下reac ...

  10. Javascript知识——事件

    O(∩_∩)O~~又是新的一周开始了,今天还是在继续学习Javascript知识,今天主要讲了事件的知识.现在就总结下吧. 事件 事件一般是用于浏览器和用户操作进行交互.最早是 IE 和 Netsca ...

随机推荐

  1. 最小生成树Kruskal算法的实现原理

    到底什么是最小生成树 最小生成树算法应用范围比较广,例如在网络的铺设当中难免会出现环路,需要要生成树算法来取出网络中的环,防止网络风暴的发生.那到底什么是最小生成树呢?我这里就不给严谨的定义了,这种定 ...

  2. 【已解决】docker overlay2占用大量磁盘空间处理方法

    在使用docker容器的时候遇到了容量上的问题,做一个记录 处理方式1:在使用docker时,往往会出现磁盘空间不足,导致该问题的通常原因是因为docker中部署的系统输出了大量的日志内容. 此时,可 ...

  3. 《iOS面试之道》-“串行队列的代码实战” 勘误

    一.原书第一版154页开始讲解串行队列.并发队列.以及在Dispatch_Async.Dispatch_Sync下面的作用 最后一段代码: if(_q == NULL) { _q = dispatch ...

  4. Java中的变量分类(按照位置分类)

    变量按位置分 通过上面类的建立我们又得到了新的概念:成员变量和局部变量 成员变量: 可以使用基本数据类型,也可以使用引用数据类型. java中的变量在使用时必须初始化,成员变量可以不对其初始化,系统会 ...

  5. kettle从入门到精通 第十二课 kettle java代码过滤记录、利用Janino计算Java表达式

    1.下图通过简单的示例讲解了根据java代码过滤记录和利用Janino计算Java表达式两个组件. 2.根据java代码过滤记录 1)步骤名称:自定义 2)接收匹配的行的步骤(可选):下面条件(jav ...

  6. flutter 尝试创建第一个页面(三)

    新建目录 assets  存放图片 在pubspec..yaml 中添加 flutter: # The following line ensures that the Material Icons f ...

  7. 微信支付or支付宝支付调用流程图

    微信支付or支付宝支付调用流程图 支付宝小程序支付调用流程https://opendocs.alipay.com/mini/03l735 微信H5支付调用流程https://pay.weixin.qq ...

  8. 基于SDF的光照效果

    基于SDF的光照效果 好久没写博客了,怠惰了,就当爬了一步 原神二次元风格面部渲染 效果 Show me the code Shader "Unlit/SDF" { Propert ...

  9. 使用Microsoft.SemanticKernel基于本地运行的Ollama大语言模型实现Agent调用函数

    大语言模型的发展日新月异,记得在去年这个时候,函数调用还是gpt-4的专属.到今年本地运行的大模型无论是推理能力还是文本的输出质量都已经非常接近gpt-4了.而在去年gpt-4尚未发布函数调用时,智能 ...

  10. java并发的发布和订阅测试

    现在编码的时候,为了处理消息,大家动不动就上个重器,例如MQ之类的.但很多时候,并不是那么有必要,因为数据量和并发其实远远不够. 可以替代的方案非常多,其中一个是java.util.concurren ...