使用VScode调试运行TS的方法:
1.安装node.js,会一起安装好npm,然后使用命令npm install -g typescript
安装ts环境。
2.在ts项目文件夹下使用命令
tsc --init 生成tsconfig.json文件,文件中outDir的值为转换的js文件目录。sourceMap为JS何TS的映射表,使调试时能正确的显示TS行号。
3.按照如下步骤就能在改动TS后自动生成JS
4.最后把调试配置文件launch.json中的program设置为生成的js文件即可。
VScode设置:
1.自动补全函数参数和括号
typescript.suggest.completefunctioncalls:true
2.活动代码段是否阻止快速建议设为false,就能在使用代码片段后出现补全提示
editor.suggest.snippetspreventquicksuggestions:false
语法关键点记录:
1、字符串使用``可定义多行文本和内嵌表达式。
let words: string = `您好,今年是 ${ name } 发布 ${ years + 1} 周年`;//其中name和years为变量
2、null和undefined使用typeof得到的值分别为object和undefined。
3、"use strict";使用严格模式,对未定义的变量赋值将会报错。不允许删除变量或对象。不允许删除函数。不允许变量重名。不允许使用转义字符。等等。
好处:
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
4、new 的作用原理
5、this 的原理
6、变量名除了_还能使用$。
7、类型断言,可绕过编译阶段的类型检查。用法有两种:1.尖括号:<type>varName,2.as:varName as type。
let str: string = "1";
let str2: number = <any>str;
//或者
//let str2: number = str as any;
console.log(typeof(str) + " " + typeof(str2));//输出为:string string
8、let与var
let定义的变量才会有块级作用域,比如for循环内定义的变量,在循环体外部无法访问。let变量不允许重名,不存在变量提升(使用前必须定义)。
9、数字字符串和数字相等?
- "==="运算符也称为严格相等运算符,它用来检测两个操作数是否严格相等。该运算符首先计算其操作数的值,然后比较这两个值,比较过程中并不会首先对操作符进行任何类型转换。
- "=="运算符称为相等运算符,用来检测两个操作数是否相等,这里“相等”的定义非常宽松,可以允许进行类型转换。相等运算符"=="和"==="运算符类似,但相等运算符的比较并不严格。如果两个操作数不是同一类型,那么相等运算符会尝试对操作数进行一些类型转换,然后进行比较。例如:
- 如果一个值是null,另一个是undefined,则他们相等。
- 如果一个值是数字,另一个是字符串,比较时现将字符串转换为数字,然后使用转换后的值比较。
- 如果其中一个值是true,则将其转换为1再进行比较。
- 因为在使用过程中"=="会出现类型转换,所以为避免在使用"=="过程中出现意想不到的类型转换而影响比较结果,建议除特殊情况外全部用"==="。
- 另一个例外是
NaN
这个特殊的Number与所有其他值都不相等,包括它自己:
NaN === NaN; // false
唯一能判断NaN
的方法是通过isNaN()
函数:
isNaN(NaN); // true
10、几种遍历方式
let list = [1, "2", true];
for (const k in list) {
console.log(k);
}//输出:0, 1, 2
for (const v of list) {
console.log(v);
}//输出:1, 2, true
list.every((v, k) => {
console.log(k, v);
return true;//没有返回或者返回false跳出循环
});//输出:0 1, 1 2, 2 true
12、函数定义时形参后面加问号为可选参数,可选参数必须放后面。不传可选参数时值为undefined。与普通可选参数不同的是,带默认值的参数不需要放在必选参数的后面。
//可选参数必须放在必选参数后面
function greeter(content: string, extra?: string): string{
return "name" + " say: " + content;
}
console.log(greeter("hello"));
//带默认值的参数可以放在必选参数前面
function greeter2(content: string = "defualt", extra: string): string{
return "name" + " say: " + content;
}
console.log(greeter2(undefined, "hello"));
形参前面加...为剩余参数,可接受不定数量的参数,剩余参数必须为数组。
function greeter(content: string, ...extra: string[]): string{
let str: string = "";
for (let i = 0; i < extra.length; ++i) {
str += extra[i];
}
return " say: " + content + " extra: " + str;
}
13、条件判断中 0、""、false、null、undefined、NaN 都为假。
14、特别的函数定义 new Function(),可用于将字符串转换为函数。
let myFunction = new Function("a", "b", "return a * b");//Function接受多个字符串参数,最后一个作为函数体,前面的作为形参。
console.log(myFunction(3, 4));//输出:12
15、匿名函数语法糖 箭头函数(lambda函数),有些需要定义函数类型的地方只能使用箭头函数。箭头函数还会自动捕获this。
//正常写法
let addFunc1 = function (x: number, y: number) {
return x + y;
}
//箭头函数写法
let addFunc2 = (x: number, y: number) => {
return x + y;
}
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
//此处如果不使用箭头函数编译会报错。在外边调用此函数时this会是window,在严格模式下会是undefined
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
//下面为编译成JS后的代码。看完我们就知道为什么this能正常使用了。
// var _this = this;//帮我把this捕获了,并且在后面使用this的地方都替换外使用_this
// return function () {
// var pickedCard = Math.floor(Math.random() * 52);
// var pickedSuit = Math.floor(pickedCard / 13);
// return { suit: _this.suits[pickedSuit], card: pickedCard % 13 };
// };
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
console.log("card: " + pickedCard.card + " of " + pickedCard.suit);
16、基本包装类型
一、什么是基本包装类型?
为了便于操作基本类型值,ECMAScript还提供了3个特殊的引用类型: Boolean、Number、String。这些类型与其他内置对象类型相似,但同时具有各自的基本类型相应的特殊行为。实际上,每当读取一个基本类型值得时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。
包装类型,是一个专门封装原始类型的值,并提供对原始类型的值执行操作的API对象二、其他内置对象与基本包装类型对象的区别?
普通的内置对象与基本包装类型的主要区别就是对象的生命期,使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中,而自动创建的基本包装类型的对象,则只是存在于一行代码的执行瞬间,然后立即被立即销毁。这意味着我们不能再运行时为基本包装类型值添加属性和方法。
————————————————
版权声明:本文为CSDN博主「冯小东」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baidu_25343343/article/details/54849475
17、布尔包装类型Boolean需要注意的点。
console.log(false ? "true" : "false"); //false
console.log(Boolean(false) ? "true" : "false"); //false
console.log(new Boolean(false) ? "true" : "false"); //true
18、数组相关。
let list: number[] = [1, 2, 3, 4];
console.log(list.length); //4
console.log(list[5]); //undefined
list[100] = 5;
console.log(list.length); //101
console.log(list[5]); //undefined
//数字索引会被转换为字符串索引
let list: any = {}
list[1] = 1;
list["1"] = 2;
console.log(list[1], list["1"]);//2 2
19、联合类型使用"|"使变量可以赋值为多种类型。let val: number|string;
20、接口interface 只是定义一种属于TS的规范,用于编译过程的检查,最终转换成JS是不存在接口的。
21、数组接口、函数接口
//数组接口
interface namelist {
[index:number]:string
}
let list2:namelist = ["John",1,"Bran"] / 错误元素 1 不是 string 类型
interface ages {
[index:string]:number
}
let agelist:ages = {};
agelist["John"] = 15 // 正确
agelist[2] = "nine" // 错误
//函数接口
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
//混合类型
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;
22、prototype 原型,用来继承父类方法。类似lua的元表
23、hasOwnProperty 检查自身的属性和方法,不向父类原型中查找。
24、枚举相关,枚举编译成JS后实际上是生成了一个枚举名与枚举值正反映射的对象。而const声明的枚举是常量枚举,不会生成额外的对象,而是用枚举常量值替换掉代码中的枚举,不存在额外的属性访问,由于并没有真的构造一个枚举类,所以也无法反向映射枚举值。
enum Month { Jan, Feb, Mar, Apr }
//编译后生成的枚举对象
// var Month;
// (function (Month) {
// Month[Month["Jan"] = 0] = "Jan";
// Month[Month["Feb"] = 1] = "Feb";
// Month[Month["Mar"] = 2] = "Mar";
// Month[Month["Apr"] = 3] = "Apr";
// })(Month || (Month = {}));
const enum Month { Jan, Feb, Mar, Apr }
let month = [Month.Jan, Month.Feb, Month.Mar];
// 编译的结果Month 是没有产生额外对象的,只是替换掉了枚举改为数字
//var month = [0 /* Jan */, 1 /* Feb */, 2 /* Mar */];
25、鸭子类型(Duck Typing)
鸭子类型(英语:duck typing)是动态类型的一种风格,是多态(polymorphism)的一种形式。
在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
可以这样表述:
"当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。"
在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
//关于鸭子类型的测试
interface IPerson {
name: string;
age: number;
greeter(content:string):void;
}
enum Sex {male, female};
class PersonClass {
name: string;
age: number;
sex:Sex;
constructor(name: string = "defaultName", age: number = 18) {
this.name = name;
this.age = age;
this.sex = Sex.female;
}
greeter(content: string, ...extra: string[]): string{
return this.name + " say: " + content + " extra: " + extra;
}
}
let person = new PersonClass("mike", 20);
let personObj = {
name: "mike",
age: 20,
sex: Sex.female,
greeter: function (content:string, ...extra:string[]) { return this.name + " say: " + content + " extra: " + extra; },
getName: function () {return this.name;}
}
//以下三种情况均能通过编译且输出一致
function testObj(person: {name: string, age: number, greeter: (content:string, ...extra:string[])=>string}) {
return person.greeter("hello");
}
console.log(testObj(personObj));
console.log(testObj(person));
function testObj2(person: PersonClass) {
return person.greeter("hello");
}
console.log(testObj2(personObj));
console.log(testObj2(person));
function testObj3(person: IPerson) {
return person.greeter("hello");
}
console.log(testObj3(personObj));
console.log(testObj3(person));
但是,当存在private或protected属性的时情况就不同了
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
class Rhino extends Animal {
constructor() { super("Rhino"); }
}
class Employee {
private name: string;
constructor(theName: string) { this.name = theName; }
}
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");
function testFunc(animel: Animal) {
return animal;
}
testFunc(rhino);//正确
testFunc(employee);// 错误: Animal 与 Employee 不兼容.
let animelObj = {name: "xxx"};
testFunc(animelObj);//错误
27、解构用法(语法糖)
//数组解构
let list = [1, 2, 3 ,4]
let [x,,y] = list;
console.log(x, y); //1 3
//配合剩余变量使用
let [first, ...rest] = [1, 2, 3, 4];
//编译成JS后:
//var _a = [1, 2, 3, 4], first = _a[0], rest = _a.slice(1);
console.log(first); //1
console.log(rest); //[ 2, 3, 4 ]
//交换两个变量的值
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); //2 1
//解构对象
let personObj = {
name: "mike",
age: 20,
sex: Sex.female,
telephone: undefined,
greeter: function (content:string, ...extra:string[]) { return this.name + " say: " + content + " extra: " + extra; },
getName: function () {return this.name;}
}
let {sex: sseexx, age, telephone = 10068,...rest} = personObj;//这里冒号后面不是指类型,是将属性重命名。可以使用=设置默认值,当取值为undefined时使用默认值。
//编译成JS后:
//var sseexx = personObj.sex, age = personObj.age, _a = personObj.telephone, telephone = _a === void 0 ? 10068 : _a, rest = __rest(personObj, ["sex", "age", "telephone"]);
console.log(Sex[sseexx], age, rest.getName());//female 20 10086 mike
28、展开用法
//展开数组
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];//[1,2,3,4,5]
//展开对象
let personObj = {
name: "mike",
age: 20,
sex: Sex.female,
greeter: function (content:string, ...extra:string[]) { return this.name + " say: " + content + " extra: " + extra; },
getName: function () {return this.name;}
}
let newPersonObj = {name: "lisa", ...personObj}//展开后name属性会覆盖前面的。
console.log(newPersonObj.name)//mike
console.log(newPersonObj.getName())//mike 这里要注意如果是展开的一个类(Class),是不能获得方法的!。
29、额外的属性检查
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string, area: number} {
let square = { color: "white", area: 100}
if (config.color)
square.color = config.color;
if (config.width)
square.area = config.width * config.width;
return square
}
console.log(createSquare({color: "red", width: 5, isBig: true}));//这种写发会触发额外属性检查报错,isBig不属于SquareConfig
//三种避免额外属性检查的方法
let obj = {color: "red", width: 5, isBig: true};
console.log(createSquare(obj));//1、使用变量
console.log(createSquare(<SquareConfig>{color: "red", width: 5, isBig: true}));//2、使用类型断言
// interface SquareConfig {
// color?: string;
// width?: number;
// [propName: string]: any;//3、增加字符串索引签名,表示可以存着任意数量的属性
// }
30、参数属性
在构造函数里使用private name: string
参数来创建和初始化name
成员。 我们把声明和赋值合并至一处。
参数属性通过给构造函数参数添加一个访问限定符来声明。 使用private
限定一个参数属性会声明并初始化一个私有成员;对于public
和protected
来说也是一样。
class Animal {
//private name: string;
//constructor(name: string) { this.name = name }
constructor(private name: string) { }
move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
31、存取器
TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。只带有get
不带有set
的存取器自动被推断为readonly。
下面来看如何在一个简单的类使用get
和set。
let passcode = "secret passcode";
class Employee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
console.log(employee.fullName);
}
32、泛型约束
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // 报错,T类型不一定存在length属性
return arg;
}
//使用约束后
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 正确,现在T类型必定存在length属性
return arg;
}
在泛型里使用类类型
在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。比如,
class Person {
name: string;
constructor(name: string = "default") {
this.name = name;
}
}
function create<T>(c: {new(): T; }): T {
return new c();
}
let person = create(Person);
33、高级类型