又是一个年底来了,好大一批人可能又准备跑路了,翻了翻掘金和 CSDN 发现好多大佬都有大厂 Offer ,看着看着我心动了!
话不多说,赶紧开干,给自己整了一个前端面试小助手——微信小程序内搜索 “WEB学习学习加油站” ,整理了前端经典高频面试题,笔试题库,是前端跳槽人必不可少的利器。
1.1、使用 typeof 进行类型判断(这些缩小类型范围的技术都有助于TS基于控制流程下的类型分析)
function unknownToString(value: unknown): string {
if (typeof value === "string") {
return value;
}
return String(value);
}
1.2、对 unknown 类型使用类型断言
要强制编译器信任类型为 unknown 的值为给定类型,则可以使用类型断言:
const value: unknown = "Hello World";
const foo: string = value; // Error
const bar: string = value as string; // OK
断言错了时语法能通过检测,但是运行的时候就会报错了!
const value: unknown = "Hello World";
const bar: number = value as number; // runtime Error
2.1、模块
TypeScript 与 ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块。
相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的
例如我们在在一个 TypeScript 工程下建立一个文件 1.ts,声明一个变量a,如下:
const a = 1
然后在另一个文件同样声明一个变量a,这时候会出现错误信息
提示重复声明a变量,但是所处的空间是全局的
如果需要解决这个问题,则通过import或者export引入模块系统即可,如下:
const a = 10;
export default a
在typescript中,export关键字可以导出变量或者类型,用法与es6模块一致,如下:
export const a = 1
export type Person = {
name: String
}
通过import 引入模块,如下:
import { a, Person } from './export';
2.2、命名空间
命名空间一个最明确的目的就是解决重名问题
命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的
这样,在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中
TypeScript 中命名空间使用 namespace 来定义,语法格式如下:
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
以上定义了一个命名空间 SomeNameSpaceName,如果我们需要在外部可以调用 SomeNameSpaceName 中的类和接口,则需要在类和接口添加 export 关键字
使用方式如下:
SomeNameSpaceName.SomeClassName
命名空间本质上是一个对象,作用是将一系列相关的全局变量组织到一个对象的属性,如下:
namespace Letter {
export let a = 1;
export let b = 2;
export let c = 3;
// ...
export let z = 26;
}
编译成js如下:
var Letter;
(function (Letter) {
Letter.a = 1;
Letter.b = 2;
Letter.c = 3;
// ...
Letter.z = 26;
})(Letter || (Letter = {}));
2.3、区别
tsconfig.json文件是JSON格式的文件。
在tsconfig.json文件中,可以指定不同的选项来告诉编译器如何编译当前项目。
目录中包含tsconfig.json文件,表明该目录是TypeScript项目的根目录。
// 常用配置
{
/*
tsconfig.json是ts编译器的配置文件,ts可以根据它的信息来对待吗进行编译 可以再tsconfig中写注释
include : 用来指定哪些文件需要被编译
exclude : 用来指定哪些文件不需要被编译 :默认node_module
extends : 用来指定继承的配置文件
files : 用来指定被编译的文件列表,只有编译少量文件才使用
compilerOptions : 编译器的选项是配置文件中非常重要也是非常复杂的配置选项
*/
"include":[
// ** : 任意目录 , * : 任意文件
"./src/**/*"
],
"exclude": [
"./src/hello/**/*"
],
// "extends": "./configs/base",
"files": [
"1.ts",
// "2.ts"
],
"compilerOptions": {
// 用来指定 ES 版本 ESNext : 最新版。 'ES3', 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ESNext'
"target": "ES2020",
// 指定要使用模块化的规范 : 'None', 'CommonJS', 'AMD', 'System', 'UMD', 'ES6'/'ES2015', 'ES2020' or 'ESNext'
"module": "ESNext",
// 用来指定项目中要使用的库 'ES5', 'ES6', 'ES2015', 'ES7', 'ES2016', 'ES2017', 'ES2018', 'ESNext', 'DOM', 'DOM.Iterable',
// 'WebWorker', 'ScriptHost', 'ES2015.Core', 'ES2015.Collection', 'ES2015.Generator', 'ES2015.Iterable',
// 'ES2015.Promise', 'ES2015.Proxy', 'ES2015.Reflect', 'ES2015.Symbol', 'ES2015.Symbol.WellKnown',
// 'ES2016.Array.Include', 'ES2017.object', 'ES2017.Intl', 'ES2017.SharedMemory', 'ES2017.String',
// 'ES2017.TypedArrays', 'ES2018.Intl', 'ES2018.Promise', 'ES2018.RegExp', 'ESNext.AsyncIterable',
// 'ESNext.Array', 'ESNext.Intl', 'ESNext.Symbol'
// 运行在浏览器中不用设置,运行在node或其他中才需要设置
// "lib":[],
// 用来指定编译后文件的存放位置
"outDir":"./dist",
// 将代码合并为一个文件,设置之后所有的全局作用域中的代码会合并到同一个文件中 但是只能在 'amd' and 'system' 中才能使用
// "outFile": "./dist/app.js",
// 是否对js文件进行编译,默认false
"allowJs": false,
// 是否检查js代码是否符合语法规范,默认false
"checkJs": false,
// 是否移除注释,默认false
"removeComments":false,
// 是否不生成编译后文件,默认false
"noEmit": false,
// 当有错误时是否生成文件,默认false
"noEmitOnError": false,
// 是否生成sourceMap,默认false 这个文件里保存的,是转换后代码的位置,和对应的转换前的位置。有了它,出错的时候,通过断点工具可以直接显示原始代码,而不是转换后的代码。
"sourceMap":false,
// 所有的严格检查的总开关,默认false
"strict": false,
// 编译后的文件是否开启严格模式,默认false
"alwaysStrict": false,
// 不允许隐式的any,默认false(允许)
"noImplicitAny": false,
// 不允许隐式的this,默认false(允许)
"noImplicitThis": false,
// 是否严格的检查空值,默认false 检查有可能为null的地方
"strictNullChecks": true,
// 是否严格检查bind、call和apply的参数列表,默认false 检查是否有多余参数
"strictBindCallApply":false,
// 是否严格检查函数的类型,
"strictFunctionTypes":false,
// 是否严格检查属性是否初始化,默认false
"strictPropertyInitialization":false,
// 是否检查switch语句包含正确的break,默认false
"noFallthroughCasesInSwitch":false,
// 检查函数没有隐式的返回值,默认false
"noImplicitReturns":false,
// 是否检查检查未使用的局部变量,默认false
"noUnusedLocals":false,
// 是否检查未使用的参数,默认false
"noUnusedParameters":false,
// 是否检查不可达代码报错,默认false true,忽略不可达代码 false,不可达代码将引起错误
"allowUnreachableCode":false
}
}
JavaScript库或框架没有TypeScript声明文件。 但是,如果要在TypeScript文件中使用它们而没有任何编译错误,则必须使用declare关键字。 declare关键字用于环境声明和您要定义可能在其他位置存在的变量的方法。
如果要在我们的TypeScript代码中使用该库,则可以使用以下代码:
declare var myLibrary;
TypeScript运行时会将myLibrary变量分配为 any。
TypeScript支持访问修饰符 public,private 和 protected,它们决定了类成员的可访问性。
如果未指定访问修饰符,则它是隐式公共的,因为它符合 JavaScript 的便利性。
枚举是 TypeScipt 数据类型,它允许我们定义一组命名常量。 使用枚举使记录意图或创建一组不同的案例变得更加容易。 它是相关值的集合,可以是数字值或字符串值。
enum Gender {
Male,
Female
Other
}
console.log(Gender.Male); // Output: 0
//We can also access an enum value by it's number value.
console.log(Gender[1]); // Output: Female
如果子类(子类)具有与父类中声明的相同的方法,则称为方法覆盖。换句话说,在派生类或子类中重新定义基类方法。
方法重写的规则
class NewPrinter extends Printer {
doPrint(): any {
super.doPrint();
console.log("Called Child class.");
}
doInkJetPrint(): any {
console.log("Called doInkJetPrint().");
}
}
let printer: new () => NewPrinter;
printer.doPrint();
printer.doInkJetPrint();
继承是一种从另一个类获取一个类的属性和行为的机制。它是OOPs语言的一个重要方面,并且具有从现有类创建新类的能力,继承成员的类称为基类,继承这些成员的类称为派生类。
继承可以通过使用extend关键字来实现。我们可以通过下面的例子来理解它。
class Shape {
Area:number
constructor(area:number) {
this.Area = area
}
}
class Circle extends Shape {
display():void {
console.log("圆的面积: "+this.Area)
}
}
var obj = new Circle(320);
obj.display()
TypeScript 引入了类,以便它们可以利用诸如封装和抽象之类的面向对象技术的好处。
TypeScript 编译器将 TypeScript 中的类编译为普通的 JavaScript 函数,以跨平台和浏览器工作。
一个类包括以下内容:
class Employee {
empID: number;
empName: string;
constructor(ID: number, name: string) {
this.empName = name;
this.empID = ID;
}
getSalary(): number {
return 40000;
}
}
类的其他特性有:
Getter 和 setter 是特殊类型的方法,可帮助你根据程序的需要委派对私有变量的不同级别的访问。
Getters 允许你引用一个值但不能编辑它。Setter 允许你更改变量的值,但不能查看其当前值。这些对于实现封装是必不可少的。
例如,新雇主可能能够了解get公司的员工人数,但无权set了解员工人数。
const fullNameMaxLength = 10;
class Employee {
private _fullName: string = "";
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (newName && newName.length > fullNameMaxLength) {
throw new Error("fullName has a max length of " + fullNameMaxLength);
}
this._fullName = newName;
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
console.log(employee.fullName);
}
TypeScript是微软公司开发和维护的一种面向对象的编程语言。它是JavaScript的超集,包含其所有元素。
强类型和弱类型、静态类型和动态类型是两组不同的概念。
类型强弱是针对类型转换是否显示来区分,静态和动态类型是针对类型检查的时机来区分。
TS对JS的改进主要是静态类型检查,静态类型检查有何意义?标准答案是“静态类型更有利于构建大型应用”。
推荐使用TypeScript的原因有:
在 typescript 项目开发中,引用其他第三方的非 typescript 编写的 javascript 的库的时候,必须为这个类编写一个声明文件,如果没有的话,就会提示找不到。
以 jQuery 库为例:
声明文件的作用:主要用来描述 JS 模块内的类型信息,声明文件一般都是 *.d.ts 作为后缀,一般放到 types 文件夹内。
以 jQuery 库为例,写一个声明文件:jQuery.d.ts 文件,内容如下:
declare var jQuery:(selector:string)=>any
此时上边的 jQuery 就不会报红了!
通常,声明文件都是由类库的开发者编写的,包含在类库的源码中,不需要我们手动一个一个类库地写。大部分主流类库都可以在社区中找到,地址为:
https://www.typescriptlang.org/dt/search
查找对应的库,在后边复制命令,安装类库时会自动生成 *.d.ts 声明文件。如:
typescript 的优点有:
typescript 的缺点有:
可以的。
tsc --outFile common.js demo1.ts demo2.ts demo3.ts
可以将 demo1.ts、demo2.ts、demo3.ts 三个文件自动编译并合并到 common.js 文件内。
tsc --outFile test.ts test1.ts test2.ts
可以将 test1.ts、test2.ts 编译,编译后的 js 代码放入 test.ts 文件内,如果 test.ts 之前有内容,执行命令后 test.ts 原文件内容被清空。