TypeScript学习之 -- 高级类型_如果一个值是联合类型,那么这个值可以访问此联合类型的所有类型的所有成员(2)

这里分享一份由字节前端面试官整理的「2021大厂前端面试手册」,内容囊括Html、CSS、Javascript、Vue、HTTP、浏览器面试题、数据结构与算法。全部整理在下方文档中,共计111道

HTML

  • HTML5有哪些新特性?

  • Doctype作⽤? 严格模式与混杂模式如何区分?它们有何意义?

  • 如何实现浏览器内多个标签页之间的通信?

  • ⾏内元素有哪些?块级元素有哪些? 空(void)元素有那些?⾏内元 素和块级元素有什么区别?

  • 简述⼀下src与href的区别?

  • cookies,sessionStorage,localStorage 的区别?

  • HTML5 的离线储存的使用和原理?

  • 怎样处理 移动端 1px 被 渲染成 2px 问题?

  • iframe 的优缺点?

  • Canvas 和 SVG 图形的区别是什么?

JavaScript

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  • 问:0.1 + 0.2 === 0.3 嘛?为什么?

  • JS 数据类型

  • 写代码:实现函数能够深度克隆基本类型

  • 事件流

  • 事件是如何实现的?

  • new 一个函数发生了什么

  • 什么是作用域?

  • JS 隐式转换,显示转换

  • 了解 this 嘛,bind,call,apply 具体指什么

  • 手写 bind、apply、call

  • setTimeout(fn, 0)多久才执行,Event Loop

  • 手写题:Promise 原理

  • 说一下原型链和原型链的继承吧

  • 数组能够调用的函数有那些?

  • PWA使用过吗?serviceWorker的使用原理是啥?

  • ES6 之前使用 prototype 实现继承

  • 箭头函数和普通函数有啥区别?箭头函数能当构造函数吗?

  • 事件循环机制 (Event Loop)

class Person {
constructor (public name: string) {
}
}

interface Loggable {
log (): void
}

// 定义ConsoleLogger 类, 具有log方法
class ConsoleLogger implements Loggable {
log () {
// …
}
}

// 通过交叉类型,可以获得 Person的name属性和 ConsoleLogger的log()方法
const jim = extend(new Person(‘Jim’), new ConsoleLogger())
let n = jim.name
jim.log()


### 联合类型


联合类型与交叉类型很有关联,但是使用上却完全不同。 偶尔你会遇到这种情况,一个代码库希望传入 `number` 或 `string` 类型的参数。 例如下面的函数:



// 这里 padding为any就很容易报错,如何约束呢?
function padLeft(value: string, padding: any) {
if (typeof padding === ‘number’) {
return Array(padding + 1).join(’ ') + value
}
if (typeof padding === ‘string’) {
return padding + value
}
throw new Error(Expected string or number, got '${padding}'.)
}

padLeft(‘Hello world’, 4) // returns " Hello world"


`padLeft` 存在一个问题,`padding` 参数的类型指定成了 `any`。 这就是说我们可以传入一个既不是 `number` 也不是 `string` 类型的参数,但是 TypeScript 却不报错。



let indentedString = padLeft(‘Hello world’, true) // 编译阶段通过,运行时报错


为了解决这个问题,我们可以使用**联合类型**做为 `padding` 的参数:



function padLeft(value: string, padding: string | number) {
// …
}

let indentedString = padLeft(‘Hello world’, true) // 编译阶段报错


联合类型表示一个值可以是几种类型之一。我们用竖线(`|`)分隔每个类型,所以 `number | string` 表示一个值可以是 `number` 或 `string`。


**如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的成员**。



interface Bird {
fly()
layEggs()
}

interface Fish {
swim()
layEggs()
}

function getSmallPet(): Fish | Bird {
// …
}

let pet = getSmallPet()
pet.layEggs() // okay
pet.swim() // error


这里的联合类型可能有点复杂:如果一个值的类型是 `A | B`,我们能够确定的是它包含了 `A` 和 `B` 中共有的成员。这个例子里,`Fish` 具有一个 `swim` 方法,我们不能确定一个 `Bird | Fish` 类型的变量是否有 `swim`方法。 如果变量在运行时是 `Bird` 类型,那么调用 `pet.swim()` 就出错了。


### 类型保护


联合类型适合于那些值可以为不同类型的情况。 但当我们想确切地了解是否为 `Fish` 或者是 `Bird` 时怎么办? JavaScript 里常用来区分这 2 个可能值的方法是检查成员是否存在。如之前提及的,我们只能访问联合类型中共同拥有的成员。



let pet = getSmallPet()

// 每一个成员访问都会报错
if (pet.swim) {
pet.swim()
} else if (pet.fly) {
pet.fly()
}


为了让这段代码工作,我们要使用**类型断言**:



let pet = getSmallPet()

if ((pet as Fish).swim) {
(pet as Fish).swim()
} else {
(pet as Bird).fly()
}


#### 用户自定义的类型保护


这里可以注意到我们不得不多次使用类型断言。如果我们一旦检查过类型,就能在之后的每个分支里清楚地知道 `pet` 的类型的话就好了。


TypeScript 里的**类型保护**机制让它成为了现实。 类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个**类型谓词**:



function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}


在这个例子里,`pet is Fish` 就是类型谓词。谓词为 `parameterName is Type` 这种形式, `parameterName` 必须是来自于当前函数签名里的一个参数名。


每当使用一些变量调用 `isFish` 时,`TypeScript` 会将变量缩减为那个具体的类型。



if (isFish(pet)) {
pet.swim()
}
else {
pet.fly()
}


注意 `TypeScript` 不仅知道在 `if` 分支里 `pet` 是 `Fish` 类型;它还清楚在 `else` 分支里,一定不是 Fish类型而是 `Bird` 类型。


#### typeof 类型保护


现在我们回过头来看看怎么使用联合类型书写 `padLeft` 代码。我们可以像下面这样利用类型断言来写:



function isNumber (x: any):x is string {
return typeof x === ‘number’
}

function isString (x: any): x is string {
return typeof x === ‘string’
}

function padLeft (value: string, padding: string | number) {
if (isNumber(padding)) {
return Array(padding + 1).join(’ ') + value
}
if (isString(padding)) {
return padding + value
}
throw new Error(Expected string or number, got '${padding}'.)
}


然而,你必须要定义一个函数来判断类型是否是原始类型,但这并不必要。其实我们不必将 `typeof x === 'number'`抽象成一个函数,因为 TypeScript 可以将它识别为一个类型保护。 也就是说我们可以直接在代码里检查类型了。



function padLeft (value: string, padding: string | number) {
if (typeof padding === ‘number’) {
return Array(padding + 1).join(’ ') + value
}
if (typeof padding === ‘string’) {
return padding + value
}
throw new Error(Expected string or number, got '${padding}'.)
}


这些 `typeof` 类型保护只有两种形式能被识别:`typeof v === "typename"` 和 `typeof v !== "typename"`, `"typename"`必须是 `"number"`, `"string"`,`"boolean"` 或 `"symbol"`的基本类型。 但是 TypeScript 并不会阻止你与其它字符串比较,只是 TypeScript 不会把那些表达式识别为类型保护。


#### instanceof 类型保护


如果你已经阅读了 `typeof` 类型保护并且对 JavaScript 里的 `instanceof` 操作符熟悉的话,你可能已经猜到了这节要讲的内容。


`instanceof` 类型保护是通过构造函数来细化类型的一种方式。我们把之前的例子做一个小小的改造:



class Bird {
fly () {
console.log(‘bird fly’)
}

layEggs () {
console.log(‘bird lay eggs’)
}
}

class Fish {
swim () {
console.log(‘fish swim’)
}

layEggs () {
console.log(‘fish lay eggs’)
}
}

function getRandomPet () {
return Math.random() > 0.5 ? new Bird() : new Fish()
}

let pet = getRandomPet()

// 如果是类,可以直接通过instanceof来获取类的构造函数名
if (pet instanceof Bird) {
pet.fly()
}
if (pet instanceof Fish) {
pet.swim()
}


### 可以为 null 的类型


TypeScript 具有两种特殊的类型,`null` 和 `undefined`,它们分别具有值 `null` 和 `undefined`。我们在[基础类型](/chapter2/type)一节里已经做过简要说明。 默认情况下,类型检查器认为 `null` 与 `undefined` 可以赋值给任何类型。 `null` 与 `undefined` 是所有其它类型的一个有效值。 这也意味着,你阻止不了将它们赋值给其它类型,就算是你想要阻止这种情况也不行。`null`的发明者,Tony Hoare,称它为[价值亿万美金的错误](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)。


`--strictNullChecks` 标记可以解决此错误:当你声明一个变量时,它不会自动地包含 `null` 或 `undefined`。 你可以使用联合类型明确的包含它们:



let s = ‘foo’
s = null // 错误, ‘null’不能赋值给’string’

算法

  1. 冒泡排序

  2. 选择排序

  3. 快速排序

  4. 二叉树查找: 最大值、最小值、固定值

  5. 二叉树遍历

  6. 二叉树的最大深度

  7. 给予链表中的任一节点,把它删除掉

  8. 链表倒叙

  9. 如何判断一个单链表有环

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

. 冒泡排序

  1. 选择排序

  2. 快速排序

  3. 二叉树查找: 最大值、最小值、固定值

  4. 二叉树遍历

  5. 二叉树的最大深度

  6. 给予链表中的任一节点,把它删除掉

  7. 链表倒叙

  8. 如何判断一个单链表有环

    [外链图片转存中…(img-k8kwJyTj-1715796129491)]

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

如果你觉得对你有帮助,可以戳这里获取:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  • 13
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值