Browse Source

docs:更新TS、Vue及React

master
曹鹏 3 years ago
parent
commit
d162854ef5
  1. 224
      06.TypeScript.md
  2. 77
      07.Vue.md
  3. 162
      08.React.md

224
06.TypeScript.md

@ -0,0 +1,224 @@
1、什么是TypeScript?
TypeScript是JavaScript的加强版,它给JavaScript添加了可选的静态类型和基于类的面向对象编程,它拓展了JavaScript的语法。
而且TypeScript不存在跟浏览器不兼容的问题,因为在编译时,它产生的都是JavaScript代码。
2、TypeScript 和 JavaScript 的区别是什么?
Typescript 是 JavaScript 的超集,可以被编译成 JavaScript 代码。 用 JavaScript 编写的合法代码,在 TypeScript 中依然有效。Typescript 是纯面向对象的编程语言,包含类和接口的概念。 程序员可以用它来编写面向对象的服务端或客户端程序,并将它们编译成 JavaScript 代码。
TypeScript和 JavaScript的关系
TypeScript 引入了很多面向对象程序设计的特征,包括:
interfaces 接口
classes 类
enumerated types 枚举类型
generics 泛型
modules 模块
主要不同点如下:
TS 是一种面向对象编程语言,而 JS 是一种脚本语言(尽管 JS 是基于对象的)。
TS 支持可选参数, JS 则不支持该特性。
TS 支持静态类型,JS 不支持。
TS 支持接口,JS 不支持接口。
3为什么要用 TypeScript ?
TS 在开发时就能给出编译错误, 而 JS 错误则需要在运行时才能暴露。
作为强类型语言,你可以明确知道数据的类型。代码可读性极强,几乎每个人都能理解。
TS 非常流行,被很多业界大佬使用。像 Asana、Circle CI 和 Slack 这些公司都在用 TS。
4、TypeScript 和 JavaScript 哪个更好?
由于 TS 的先天优势,TS 越来越受欢迎。但是TS 最终不可能取代 JS,因为 JS 是 TS 的核心。
选择 TypeScript 还是 JavaScript 要由开发者自己去做决定。如果你喜欢类型安全的语言,那么推荐你选择 TS。 如果你已经用 JS 好久了,你可以选择走出舒适区学习 TS,也可以选择坚持自己的强项,继续使用 JS。
5、什么是泛型?
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,使用时再去指定类型的一种特性。
可以把泛型理解为代表类型的参数
// 我们希望传入的值是什么类型,返回的值就是什么类型
// 传入的值可以是任意的类型,这时候就可以用到 泛型
// 如果使用 any 的话,就失去了类型检查的意义
function createArray1(length: any, value: any): Array<any> {
let result: any = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray1(3, 'x');
console.log(result);
// 最傻的写法:每种类型都得定义一种函数
function createArray2(length: number, value: string): Array<string> {
let result: Array<string> = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
function createArray3(length: number, value: number): Array<number> {
let result: Array<number> = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
// 或者使用函数重载,写法有点麻烦
function createArray4(length: number, value: number): Array<number>
function createArray4(length: number, value: string): Array<string>
function createArray4(length: number, value: any): Array<any> {
let result: Array<number> = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray4(6, '666');
//使用泛型
// 有关联的地方都改成 <T>
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
// 使用的时候再指定类型
let result = createArray<string>(3, 'x');
// 也可以不指定类型,TS 会自动类型推导
let result2 = createArray(3, 'x');
console.log(result);
6、TS中的类
TypeScript 是面向对象的 JavaScript。而其中的类描述了所创建的对象共同的属性和方法。
传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但这对于熟悉使用面向对象方式的程序员来说有些棘手,因为他们用的是基于类的继承并且对象是从类构建出来的。
从ECMAScript 2015,也就是ECMAScript 6,JavaScript程序将可以使用这种基于类的面向对象方法。在TypeScript里允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,
7、什么是构造函数,构造函数作用是什么?
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。而TypeScript的构造函数用关键字constructor来实现。可以通过this(和java/C#一样代表对象实例的成员访问)关键字来访问当前类体中的属性和方法。
8、实例化是什么?
一般情况下,创建一个类后并不能直接的对属性和方法进行引用,必须对类进行实例化,即创建一个对象。TypeScript中用new 关键字创建对象。实例化后通过“.”来访问属性和方法
9、方法重写是什么?
子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写
重写的作用在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。
10、什么是可索引类型接口?
一般用来约束数组和对象
/ 数字索引——约束数组
// index 是随便取的名字,可以任意取名
// 只要 index 的类型是 number,那么值的类型必须是 string
interface StringArray {
// key 的类型为 number ,一般都代表是数组
// 限制 value 的类型为 string
[index:number]:string
}
let arr:StringArray = ['aaa','bbb'];
console.log(arr);
// 字符串索引——约束对象
// 只要 index 的类型是 string,那么值的类型必须是 string
interface StringObject {
// key 的类型为 string ,一般都代表是对象
// 限制 value 的类型为 string
[index:string]:string
}
let obj:StringObject = {name:'ccc'};
11、什么是函数类型接口?
对方法传入的参数和返回值进行约束
// 注意区别
// 普通的接口
interface discount1{
getNum : (price:number) => number
}
// 函数类型接口
interface discount2{
// 注意:
// “:” 前面的是函数的签名,用来约束函数的参数
// ":" 后面的用来约束函数的返回值
(price:number):number
}
let cost:discount2 = function(price:number):number{
return price * .8;
}
// 也可以使用类型别名
type Add = (x: number, y: number) => number
let add: Add = (a: number, b: number) => a + b
12、什么是类类型接口?
如果接口用于一个类的话,那么接口会表示“行为的抽象”
对类的约束,让类去实现接口,类可以实现多个接口
接口只能约束类的公有成员(实例属性/方法),无法约束私有成员、构造函数、静态属性/方法
// 接口可以在面向对象编程中表示为行为的抽象
interface Speakable {
name: string;
// ":" 前面的是函数签名,用来约束函数的参数
// ":" 后面的用来约束函数的返回值
speak(words: string): void
}
interface Speakable2 {
age: number;
}
class Dog implements Speakable, Speakable2 {
name!: string;
age = 18;
speak(words: string) {
console.log(words);
}
}
let dog = new Dog();
dog.speak('汪汪汪');
13、什么是混合类型接口?
一个对象可以同时做为函数和对象使用
interface FnType {
(getName:string):string;
}
interface MixedType extends FnType{
name:string;
age:number;
}
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
14、never 和 void 的区别?
void 表示没有任何类型(可以被赋值为 null 和 undefined)。
never 表示一个不包含值的类型,即表示永远不存在的值。
拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回,无法终止,或会抛出异常。
15、TS的学前基础?
因为 TypeScript 是对 JavaScript 的扩展,更准确的说是 ECMAScript。所以,我们学习我们这套 TypeScript 的课程,需要具备 ECMAScript 语言的基础:
熟悉语法基础(变量、语句、函数等基础概念)
掌握内置对象(Array、Date 等)的使用
面向对象基本概念(构造函数、原型、继承)

77
07.Vue.md

@ -29,8 +29,6 @@ Vue是一个典型的MVVM框架,模型(Model)只是普通的javascript对
**Compile(指令解析器)** : Compile主要做的事情是解析模板指令,将模板中变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加鉴定数据的订阅者,一旦数据有变动,收到通知,更新试图 **Compile(指令解析器)** : Compile主要做的事情是解析模板指令,将模板中变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加鉴定数据的订阅者,一旦数据有变动,收到通知,更新试图
传送门:☞ [20分钟吃透Diff算法核心原理](https://juejin.cn/post/6994959998283907102#heading-2) 传送门:☞ [20分钟吃透Diff算法核心原理](https://juejin.cn/post/6994959998283907102#heading-2)
@ -84,12 +82,10 @@ Vue是一个典型的MVVM框架,模型(Model)只是普通的javascript对
1.当 v-for 和 v-if 处于同一个节点时,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。如果要遍历的数组很大,而真正要展示的数据很少时,这将造成很大的性能浪费 1.当 v-for 和 v-if 处于同一个节点时,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。如果要遍历的数组很大,而真正要展示的数据很少时,这将造成很大的性能浪费
2.这种场景建议使用 computed,先对数据进行过滤 2.这种场景建议使用 computed,先对数据进行过滤
注意:3.x 版本中 `v-if` 总是优先于 `v-for` 生效。由于语法上存在歧义,建议避免在同一元素上同时使用两者。比起在模板层面管理相关逻辑,更好的办法是通过创建计算属性筛选出列表,并以此创建可见元素。 注意:3.x 版本中 `v-if` 总是优先于 `v-for` 生效。由于语法上存在歧义,建议避免在同一元素上同时使用两者。比起在模板层面管理相关逻辑,更好的办法是通过创建计算属性筛选出列表,并以此创建可见元素。
解惑传送门 ☞ [# v-if 与 v-for 的优先级对比非兼容](https://v3.cn.vuejs.org/guide/migration/v-if-v-for.html#%E6%A6%82%E8%A7%88) 解惑传送门 ☞ [# v-if 与 v-for 的优先级对比非兼容](https://v3.cn.vuejs.org/guide/migration/v-if-v-for.html#%E6%A6%82%E8%A7%88)
### React/Vue 项目中 key 的作用 ### React/Vue 项目中 key 的作用
- key的作用是为了在diff算法执行时更快的找到对应的节点,`提高diff速度,更高效的更新虚拟DOM`; - key的作用是为了在diff算法执行时更快的找到对应的节点,`提高diff速度,更高效的更新虚拟DOM`;
@ -173,6 +169,67 @@ console.log(o);
Vuex、`$attrs、$listeners` `Provide、inject` Vuex、`$attrs、$listeners` `Provide、inject`
### $emit 后面的两个参数是什么
1、父组件可以使用 props 把数据传给子组件。
2、子组件可以使用 $emit,让父组件监听到自定义事件 。
`vm.$emit( event, arg );`//触发当前实例上的事件,要传递的参数
`vm.$on( event, fn );`//监听event事件后运行 fn;
子组件
```vue
<template>
<div class="train-city">
<h3>父组件传给子组件的toCity:{{sendData}}</h3>
<br/><button @click='select(`大连`)'>点击此处将‘大连’发射给父组件</button>
</div>
</template>
<script>
export default {
name:'trainCity',
props:['sendData'], // 用来接收父组件传给子组件的数据
methods:{
select(val) {
let data = {
cityName: val
};
this.$emit('showCityName',data);//select事件触发后,自动触发showCityName事件
}
}
}
</script>
```
父组件
```vue
<template>
<div>
<div>父组件的toCity{{toCity}}</div>
<train-city @showCityName="updateCity" :sendData="toCity"></train-city>
</div>
<template>
<script>
export default {
name:'index',
components: {},
data () {
return {
toCity:"北京"
}
},
methods:{
updateCity(data){//触发子组件城市选择-选择城市的事件
this.toCity = data.cityName;//改变了父组件的值
console.log('toCity:'+this.toCity)
}
}
}
</script>
```
### nextTick的实现 ### nextTick的实现
1. `nextTick`是`Vue`提供的一个全局`API`,是在下次`DOM`更新循环结束之后执行延迟回调,在修改数据之后使用`$nextTick`,则可以在回调中获取更新后的`DOM`; 1. `nextTick`是`Vue`提供的一个全局`API`,是在下次`DOM`更新循环结束之后执行延迟回调,在修改数据之后使用`$nextTick`,则可以在回调中获取更新后的`DOM`;
@ -263,6 +320,18 @@ vue3提出的Composition API旨在解决这些问题【追求完美是要消耗
具体参考:[vue自定义指令模拟v-model指令](https://blog.csdn.net/qq_39157944/article/details/106262546) 具体参考:[vue自定义指令模拟v-model指令](https://blog.csdn.net/qq_39157944/article/details/106262546)
### 如何实现 v-model,说下思路
### Vue Router 相关
### Vuex的理解及使用场景 ### Vuex的理解及使用场景
Vuex 是一个专为 Vue 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。 Vuex 是一个专为 Vue 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。

162
08.React.md

@ -365,3 +365,165 @@ React并不是将click事件绑在该div的真实DOM上,而是`在document处
另外冒泡到 document 上的事件也不是原生浏览器事件,而是 React 自己实现的合成事件(SyntheticEvent)。因此我们如果不想要事件冒泡的话,调用 event.stopPropagation 是无效的,而应该调用 `event.preventDefault` 另外冒泡到 document 上的事件也不是原生浏览器事件,而是 React 自己实现的合成事件(SyntheticEvent)。因此我们如果不想要事件冒泡的话,调用 event.stopPropagation 是无效的,而应该调用 `event.preventDefault`
![react事件绑定原理](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2089718f74b342869de15f01588f033f~tplv-k3u1fbpfcp-zoom-1.image) ![react事件绑定原理](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2089718f74b342869de15f01588f033f~tplv-k3u1fbpfcp-zoom-1.image)
### React.lazy() 实现的原理
React的懒加载示例:
```js
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
```
**React.lazy 原理**
以下 React 源码基于 16.8.0 版本
React.lazy 的源码实现如下:
export function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> {
let lazyType = {
$$typeof: REACT_LAZY_TYPE,
_ctor: ctor,
// React uses these fields to store the result.
_status: -1,
_result: null,
};
return lazyType;
}
可以看到其返回了一个 LazyComponent 对象。
而对于 LazyComponent 对象的解析:
```js
case LazyComponent: {
const elementType = workInProgress.elementType;
return mountLazyComponent(
current,
workInProgress,
elementType,
updateExpirationTime,
renderExpirationTime,
);
}
```
```js
function mountLazyComponent(
_current,
workInProgress,
elementType,
updateExpirationTime,
renderExpirationTime,
) {
...
let Component = readLazyComponentType(elementType);
...
}
```
```js
// Pending = 0, Resolved = 1, Rejected = 2
export function readLazyComponentType<T>(lazyComponent: LazyComponent<T>): T {
const status = lazyComponent._status;
const result = lazyComponent._result;
switch (status) {
case Resolved: {
const Component: T = result;
return Component;
}
case Rejected: {
const error: mixed = result;
throw error;
}
case Pending: {
const thenable: Thenable<T, mixed> = result;
throw thenable;
}
default: { // lazyComponent 首次被渲染
lazyComponent._status = Pending;
const ctor = lazyComponent._ctor;
const thenable = ctor();
thenable.then(
moduleObject => {
if (lazyComponent._status === Pending) {
const defaultExport = moduleObject.default;
lazyComponent._status = Resolved;
lazyComponent._result = defaultExport;
}
},
error => {
if (lazyComponent._status === Pending) {
lazyComponent._status = Rejected;
lazyComponent._result = error;
}
},
);
// Handle synchronous thenables.
switch (lazyComponent._status) {
case Resolved:
return lazyComponent._result;
case Rejected:
throw lazyComponent._result;
}
lazyComponent._result = thenable;
throw thenable;
}
}
}
```
注:如果 readLazyComponentType 函数多次处理同一个 lazyComponent,则可能进入Pending、Rejected等 case 中。
从上述代码中可以看出,对于最初 React.lazy() 所返回的 LazyComponent 对象,其 _status 默认是 -1,所以首次渲染时,会进入 readLazyComponentType 函数中的 default 的逻辑,这里才会真正异步执行 import(url)操作,由于并未等待,随后会检查模块是否 Resolved,如果已经Resolved了(已经加载完毕)则直接返回moduleObject.default(动态加载的模块的默认导出),否则将通过 throw 将 thenable 抛出到上层。
为什么要 throw 它?这就要涉及到 Suspense 的工作原理,我们接着往下分析。
**Suspense 原理**
由于 React 捕获异常并处理的代码逻辑比较多,这里就不贴源码,感兴趣可以去看 throwException 中的逻辑,其中就包含了如何处理捕获的异常。简单描述一下处理过程,React 捕获到异常之后,会判断异常是不是一个 thenable,如果是则会找到 SuspenseComponent ,如果 thenable 处于 pending 状态,则会将其 children 都渲染成 fallback 的值,一旦 thenable 被 resolve 则 SuspenseComponent 的子组件会重新渲染一次。
为了便于理解,我们也可以用 componentDidCatch 实现一个自己的 Suspense 组件,如下:
```js
class Suspense extends React.Component {
state = {
promise: null
}
componentDidCatch(err) {
// 判断 err 是否是 thenable
if (err !== null && typeof err === 'object' && typeof err.then === 'function') {
this.setState({ promise: err }, () => {
err.then(() => {
this.setState({
promise: null
})
})
})
}
}
render() {
const { fallback, children } = this.props
const { promise } = this.state
return <>{ promise ? fallback : children }</>
}
}
```
至此,我们分析完了 React 的懒加载原理。简单来说,React利用 React.lazy与import()实现了渲染时的动态加载 ,并利用Suspense来处理异步加载资源时页面应该如何显示的问题。
参考传送门☞ [React Lazy 的实现原理](https://thoamsy.github.io/blogs/react-lazy/)
Loading…
Cancel
Save