JS和TS的总结

本文详尽地介绍了JavaScript(JS)和TypeScript(TS)的基础概念及高级特性。首先,概述了JS的输出方式和语法,包括字面量、变量、数据类型、字符串和对象。接着,深入探讨了JS函数、作用域、HTML事件、特殊字符、循环、语句标识符、正则表达式、错误处理和函数细节。然后,讲解了JS对象、数组、链式语法和闭包的关键概念。最后,转入TS部分,讨论了TS的变量声明、解构、函数、泛型、类和模块。文章通过丰富的例子和注解,帮助读者深入理解这两种语言的用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JS总结

名字作用
HTML定义了网页的内容
CSS描述了网页的布局
JavaScript控制了网页的行为

一、JS输出

JavaScript 通过以下方式来输出数据:

作用举例
window.alert()弹出警告框window.alert(5 + 6);
document.write()方法将内容写到 HTML 文档中document.write(“<h1>这是一个标题</h1>”);
innerHTML写入到 HTML 元素document.getElementById(“demo”).innerHTML = “段落已修改。”;
console.log()写入到浏览器的控制台console.log(a+b);

JS直接写入HTML输出:

document.write("<h1>这是一个标题</h1>");
document.write("<p>这是一个段落。</p>");

注意:HTML 输出时使用 document.write,相当于添加在原有html代码中添加一串html代码。而如果在文档加载后使用(如使用函数),会覆盖整个文档。

二、JS语法

1、字面量
  1. 数字字面量 :可以是整数或者是小数,或者是科学计数(e)。
  2. 字符串字面量 :可以使用单引号或双引号。
  3. 表达式字面量 : 用于计算。
  4. 数组字面量 : 定义一个数组。
  5. 对象字面量 : 定义一个对象。
  6. 函数字面量 : 定义一个函数。
2、变量

使用关键字 var 来定义变量, 使用等号来为变量赋值。

var length = 16; // Number 通过数字字面量赋值                           
var points = x * 10; // Number 通过表达式字面量赋值                         
var lastName = "Johnson";  // String 通过字符串字面量赋值                       
var cars = ["Saab", "Volvo", "BMW"]; // Array  通过数组字面量赋值             
var person = {firstName:"John", lastName:"Doe"}; // Object 通过对象字面量赋值

变量是一个名称。字面量是一个值。

3、数据类型

JavaScript 有多种数据类型:数字,字符串,数组,对象等等。

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。

引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。

在这里插入图片描述
变量的数据类型可以使用 typeof 操作符来查看。

6种数据类型:string、number、boolean、object、function、symbol
3种对象类型:Object、Date、Array
2个不包含任何值的数据类型:null、undefined
(其中,Number() 转换为数字, String() 转换为字符串, Boolean() 转换为布尔值。)

类型转换:
1.数字转为字符串
全局方法 String() 可以将数字、布尔值、日期转换为字符串。
toString() 也是可以将数字、布尔值、日期转换为字符串。
toExponential() 把对象的值转换为指数计数法。
toFixed() 把数字转换为字符串,结果的小数点后有指定位数的数字。
toPrecision() 把数字格式化为指定的长度。
2.字符串转为数字
全局方法 Number() 可以将字符串、布尔值、日期转换为数字。
parseFloat() 解析一个字符串,并返回一个浮点数。
parseInt() 解析一个字符串,并返回一个整数。
getTime() 可以将日期转换为数字。

4、JS字符串
1.属性
属性描述
constructor返回创建字符串属性的函数
length返回字符串的长度
prototype允许您向对象添加属性和方法
2.方法
方法描述
charAt()返回指定索引位置的字符
charCodeAt()返回指定索引位置字符的 Unicode 值
concat()连接两个或多个字符串,返回连接后的字符串
fromCharCode()将 Unicode 转换为字符串
indexOf()返回字符串中检索指定字符第一次出现的位置
lastIndexOf()返回字符串中检索指定字符最后一次出现的位置
localeCompare()用本地特定的顺序来比较两个字符串
match()找到一个或多个正则表达式的匹配
replace()替换与正则表达式匹配的子串
search()检索与正则表达式相匹配的值
slice()提取字符串的片断,并在新的字符串中返回被提取的部分
split()把字符串分割为子字符串数组
substr()从起始索引号提取字符串中指定数目的字符
substring()提取字符串中两个指定的索引号之间的字符
toLocaleLowerCase()根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射
toLocaleUpperCase()根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射
toLowerCase()把字符串转换为小写
toString()返回字符串对象值
toUpperCase()把字符串转换为大写
trim()移除字符串首尾空白
valueOf()返回某个字符串对象的原始值
注意:
* 如需把两个或多个字符串变量连接起来,使用 + 运算符。
* 要想在两个字符串之间增加空格,需要把空格插入一个字符串之中。
* 如果把数字与字符串相加,结果将成为字符串!
5、对象

JavaScript 对象是拥有属性和方法的数据,也是属性变量的容器,还是键值对的容器。如:

var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

键值对在 JavaScript 对象通常称为对象属性。
通常写法为 name : value (键与值以冒号分割)。
可以通过两种方式访问对象属性:

person.lastName;
person["lastName"];

创建对象方法:

methodName : function() {
    // 代码 
}

JS函数

函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。

函数就是包裹在花括号中的代码块,前面使用了关键词 function:

function functionname(){
    // 执行代码
}

希望函数将值返回调用它的地方。通过使用 return 语句就可以实现。在使用 return 语句时,函数会停止执行,并返回指定的值。

function myFunction(){
    var x=5;
    return x;
}

注意:整个 JavaScript 并不会停止执行,仅仅是函数。JavaScript 将继续执行代码,从调用函数的地方。

仅仅希望退出函数时 ,也可使用 return 语句。返回值是可选的。

注意:JS函数内部使用var定义的是局部变量,适用范围仅限函数内部。而在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。

局部变量会在函数运行以后被删除。
全局变量会在页面关闭后被删除。
在 HTML 中, 全局变量是 window 对象: 所有数据变量都属于 window 对象。

非严格模式下给未声明变量赋值创建的全局变量,是全局对象的可配置属性,可以删除。

JS作用域

作用域是可访问变量的集合。
在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

常见的HTML事件

时间描述
onchangeHTML 元素改变
onclick用户点击 HTML 元素
onmouseover鼠标指针移动到指定的元素上时发生
onmouseout用户从一个 HTML 元素上移开鼠标时发生
onkeydown用户按下键盘按键
onload浏览器已完成页面的加载

JS特殊字符

代码输出
单引号
"双引号
\反斜杠
\n换行
\r回车
\ttab(制表符)
\b退格符
\f换页符
===绝对相等(数据类型与值都必须相等)
!==不绝对等于(值和类型有一个不相等,或两个都不相等)

JS循环

JavaScript 支持不同类型的循环,如:for、for/in、while、do/while

//for循环
for (var i=0;i<cars.length;i++){ 
    document.write(cars[i] + "<br>");
}
//For/In 循环
var person={fname:"Bill",lname:"Gates",age:56}; 
for (x in person) {  // x 为属性名
    txt=txt + person[x];
}
//while循环
while (i<5){
    x=x + "The number is " + i + "<br>";
    i++;
}
//do...while循环
do{
    x=x + "The number is " + i + "<br>";
    i++;
} while (i<5);

JS语句标识符

语句描述
var声明一个变量。
function定义一个函数
return退出函数
if … else用于基于不同的条件来执行不同的动作。
switch用于基于不同的条件来执行不同的动作。
for在条件语句为 true 时,可以将代码块执行指定的次数。
for … in用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。
while当条件语句为 true 时,执行语句块。
do … while执行一个语句块,在条件语句为 true 时继续执行该语句块。
break用于跳出循环,也跳出switch语句。
continue跳过循环中的一个迭代。
throw抛出(生成)错误 。
try实现错误处理,与 catch 一同使用。
catch语句块,在 try 语句块执行出错时执行 catch 语句块。

正则表达式

正则表达式是由一个字符序列形成的搜索模式,可用于所有文本搜索和文本替换的操作。

语法:
/正则表达式主体/修饰符(可选)
实例:
var patt = /runoob/i

正则表达式通常用于两个字符串方法 : search() 和 replace()。

search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置。

replace() 方法用于在字符串中用一些字符串替换另一些字符串,或替换一个与正则表达式匹配的子串。

JavaScript 错误

try 语句测试代码块的错误。
catch 语句处理错误。
throw 语句创建自定义错误。
finally 语句在 try 和 catch 语句之后,无论是否有触发异常,该语句都会执行。

JavaScript 函数

函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。JS 使用关键字 function 定义函数,以下是一个函数示例:

function sayHi(name, message) {
    console.log('Hello ' + name + ',' + message);
}
sayHi('Gridwang', '你好。');

JS 函数可以通过一个表达式定义。在函数表达式存储在变量后,变量也可作为一个函数使用:

var x = function (a, b) {return a * b};
var z = x(4, 3);

函数表达式可以 “自调用”,自调用表达式会自动调用。如果表达式后面紧跟 () ,则会自动调用。不能自调用声明的函数,通过添加括号,来说明它是一个函数表达式:

(function () {
    var x = "Hello!!";      // 我将调用自己
})();

以上函数实际上是一个 匿名自我调用的函数 (没有函数名)。

函数可作为一个值使用,当JavaScript 函数作为一个值使用:

function myFunction(a, b) {
    return a * b;
}
var x = myFunction(4, 3);

JavaScript 函数可作为表达式使用:

function myFunction(a, b) {
    return a * b;
}
var x = myFunction(4, 3) * 2;

函数是对象,
在 JavaScript 中使用 typeof 操作判断函数类型将返回 “function” 。
但是JavaScript 函数描述为一个对象更加准确。JavaScript 函数有属性和方法。
arguments.length 属性返回函数调用过程接收到的参数个数,toString() 方法将函数作为一个字符串返回:

function myFunction(a, b) {
    return arguments.length;
}
function myFunction(a, b) {
    return a * b;
}
var txt = myFunction.toString();

Note函数定义作为对象的属性,称之为对象方法。
函数如果用于创建新的对象,称之为对象的构造函数。

箭头函数

箭头函数表达式的语法比普通函数表达式更简洁。

(参数1, 参数2, …, 参数N) => { 函数声明 }
(参数1, 参数2, …, 参数N) => 表达式(单一)
// 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }

当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}

没有参数的函数应该写成一对圆括号:
() => {函数声明}
// ES5
var x = function(x, y) {
     return x * y;
}
// ES6
const x = (x, y) => x * y;

有的箭头函数都没有自己的 this。 不适合定义一个对象的方法。

当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的。

箭头函数是不能提升的,所以需要在使用之前定义。

使用 const 比使用 var 更安全,因为函数表达式始终是一个常量。

如果函数部分只是一个语句,则可以省略 return 关键字和大括号 {},这样做是一个比较好的习惯:

const x = (x, y) => { return x * y };
函数参数

函数显式参数(Parameters)与隐式参数(Arguments)
函数显式参数在函数定义时列出。
函数隐式参数在函数调用时传递给函数真正的值。
如果函数在调用时未提供隐式参数,参数会默认设置为: undefined

参数规则
JavaScript 函数定义显式参数时没有指定数据类型。
JavaScript 函数对隐式参数没有进行类型检测。
JavaScript 函数对隐式参数的个数没有进行检测。

如果函数调用时设置了过多的参数,参数将无法被引用,因为无法找到对应的参数名。 只能使用 arguments 对象来调用。

arguments 对象

JavaScript 函数有个内置的对象 arguments 对象。
argument 对象包含了函数调用的参数数组。
通过这种方式你可以很方便的找到最大的一个参数的值:

x = findMax(1, 123, 500, 115, 44, 88);
function findMax() {
    var i, max = arguments[0];
    if(arguments.length < 2) return max;
    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}

或者创建一个函数用来统计所有数值的和:

x = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() {
    var i, sum = 0;
    for (i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}

通过值传递参数,在函数中调用的参数是函数的隐式参数。
JS 隐式参数通过值来传递:函数仅仅只是获取值。
如果函数修改参数的值,不会修改显式参数的初始值(在函数外定义)。
隐式参数的改变在函数外是不可见的。

通过对象传递参数
在JavaScript中,可以引用对象的值。

因此我们在函数内部修改对象的属性就会修改其初始的值。

修改对象属性可作用于函数外部(全局变量)。
修改对象属性在函数外是可见的。

JS对象Object

对象 Object 是JS 中使用最多的一个类型。我们常将数据和方法封装在对象中。

创建对象有如下两种方式,我们常用第二种。

//方式一new
var person = new Object();//生成空对象
person.name = 'Elon Musk';//设置对象的属性
person.age = 46;
person.job = 'SpaceX Rocket';
person.sayName = function(){    //设置对象的方法/函数,注意此处
    console.log(this.name);
};
//方式二字面量
var person = {
    name: 'Lary Page',
    age: 47,
    job: 'Software Engineer',
    sayName: function(){        //注意此处
        console.log(this.name);
    }
};
console.log(person.job);
person.sayName();

虽然 Object 构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码。

代码如下:
function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        console.log(this.name);
    };
    return o;
}
var person1 = createPerson('Steve Jobs',56 , 'Inventor');
var person2 = createPerson('Linus Torvalds', 49, 'Software Engineer');
var person2 = createPerson('Julian Assange', 47, 'Ethical Hacker');

这样可以较好的解决之前的问题。

JS数组Array

除了 Object 之外, Array 类型是JS中最常用的类型了。

JS中的数组与其他多数语言中的数组有着相当大的区别。虽然 JS 数组与其他语言中的数组都是数据的有序列表,但与其他语言不同的是,JS 数组的每一项可以保存任何类型的数据(不建议!)。

也就是说,可以用数组的第一个位置来保存字符串,用第二位置来保存数值,用第三个位置来保存对象,以此类推。而且,JS 数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容纳新增数据。

创建数组有以下两种方法,我们常用第二种。

//方式一new
var colors = new Array('red', 'blue', 'green');
//方式二字面量
var colors = ['red', 'blue', 'green']; // 创建一个包含 3 个字符串的数组
console.log(colors[1]);
colors[3] = 'brown';
console.log(colors.length);
var names = []; // 创建一个空数组
var hyBird = [1, 2, 'haha', {firstName: 'Yong', lastName: 'Wang'}]; //不推荐!
console.log(hyBird[3].firstName);

常用的数组方法如下:

1、元素联合

var colors = ['red', 'green', 'blue'];
console.log(colors.join(',')); //red,green,blue
console.log(colors.join('||')); //red||green||blue

2、堆栈方法
栈是一种 LIFO(Last-In-First-Out,后进先出)的数据结构,也就是最新添加的项最早被移除。而栈中项的插入和移除,只发生在一个位置——栈的顶部。

JS为数组专门提供了 push() 和 pop() 方法,以便实现类似栈的行为。

var colors = []; // 创建一个数组
var count = colors.push('red', 'green'); // 末尾推入两项
console.log(count); //2
colors.push('black'); // 末尾推入另一项
console.log(colors); //3
var item = colors.pop(); // 末尾弹出最后一项
console.log(item); //'black'
console.log(colors); //2

3、队列方法

队列数据结构的访问规则是 FIFO(First-In-First-Out,先进先出)。队列在列表的末端添加项,从列表的前端移除项。

由于 push() 是向数组末端添加项的方法,因此要模拟队列只需一个从数组前端取得项的方法。实现这一操作的数组方法就是 shift() ,它能够移除数组中的第一个项并返回该项,同时将数组长度减1。

var colors = new Array(); //创建一个数组
colors.push('red', 'green'); //推入两项
console.log(colors); //2
count = colors.push('black'); //推入另一项
console.log(colors); //3
var item = colors.shift(); // 前端弹出第一项
console.log(item); //'red'
console.log(colors);

JS 还为数组提供了一个 unshift() 方法。它能在数组前端添加任意个项并返回新数组的长度。

var colors = new Array(); //创建一个数组
var count = colors.unshift('red', 'green'); // 推入两项
console.log(colors);
count = colors.unshift('black'); // 推入另一项
console.log(colors);
var item = colors.pop(); // 取得最后一项
console.log(item); //'green'
console.log(colors);

总结:由上可知, push、pop操作在数组末,而 unshift、shift操作在数组头;push、unshift压入而pop、shift弹出。

4、反转数组项
var values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values); //5,4,3,2,1
5、链接方法

var colors1 = ['red', 'green', 'blue'];
var colors2 = ['yellow', 'black'];
console.log(colors1.concat(colors2));
console.log(colors2.concat(colors1));
console.log(colors2.concat('brown'));
console.log(color2)//注意:concat返回一个新数组,原数组没改变

6、分片方法
slice() ,它能够基于当前数组中的一或多个项创建一个新数组。 slice() 方法可以接受一或两个参数,即要返回项的起始和结束位置。

在只有一个参数的情况下, slice() 方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。

注意, slice() 方法不会影响原始数组。

var colors1 = ['red', 'green', 'blue', 'yellow', 'purple'];
var colors2 = colors1.slice(1);
var colors3 = colors1.slice(2, 4);
var colors4 = colors1.slice(2, 2);//结果是什么?
console.log(colors1);
console.log(colors2);
console.log(colors3);

7、splice方法
splice() 方法恐怕要算是最强大的数组方法了,它可对数组如下3种操作。

注意, splice() 方法直接更改原始数组。

1.删除:可以删除任意数量的项,只需指定 2 个参数:要删除的第一项的位置和要删除的项数。 例如, splice(0,2) 会删除数组中的前两项。

2.插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数) 和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项。例如, splice(2,0,‘red’,‘green’) 会从当前数组的位置 2 开始插入字符串 ‘red’ 和 ‘green’ 。

3.替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起 始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。例如, splice (2,1,‘red’,‘green’) 会删除当前数组位置 2 的项,然后再从位置 2 开始插入字符串 ‘red’ 和 ‘green’ 。

var colors = ['red', 'green', 'blue'];
var removed = colors.splice(0,1); // 删除第一项
console.log(colors); // green,blue
console.log(removed); // red,返回的数组中只包含一项
removed = colors.splice(1, 0, 'yellow', 'orange'); // 从位置 1 开始插入两项
console.log(colors); // green,yellow,orange,blue
console.log(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, 'red', 'purple'); // 插入两项,删除一项
console.log(colors); // green,red,purple,orange,blue
console.log(removed); // yellow,返回的数组中只包含一项
JS链式语法

链式语法已变得非常流行。实际上这是一种非常容易实现的模式。基本上,你只需要让每个函数返回 this代表包含该函数的对象,这样其他函数就可以立即被调用。

//链式语法
var bird = {//定义对象字面量
  catapult: function() {
    console.log( 'Yippeeeeee!' );
    return this;//返回bird对象自身
  },
  destroy: function() {
    console.log( "That'll teach you... you dirty pig!" );
    return this;
  }
};
JS闭包

闭包是Closure,这是静态语言所不具有的一个新特性。所谓闭包就是:函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
闭包就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。

当在一个函数内定义另外一个函数就会产生闭包。

function greeting(name) {
    var text = 'Hello ' + name; // local variable
    // 每次调用时,产生闭包,并返回内部函数对象给调用者
    return function() { console.log(text); }//注意该函数无名称,称为匿名函数
}
var sayHello = greeting('Closure');//调用greeting()返回了什么?
sayHello();  // 注意此处的使用方法。通过闭包访问到了局部变量text

上述代码的执行结果是:Hello Closure,
因为sayHello指向了greeting函数对象,sayHello()则对其进行调用,greeting函数执行完毕后将返回greeting函数内定义的匿名函数对象,而该匿名函数仍然可以访问到了定义在greeting之内的局部变量text,注意此时我们已从greeting函数中退出了。

var scope = 'global scope';	//全局变量
function checkScope(){
    var scope = 'local scope';	//局部变量
    function f(){
        return scope;
    }
    return f;
}
checkScope()();		//注意此处的使用方法。返回值为local scope而非global scope

JS相关注意

HTML 中的 Javascript 脚本代码必须位于<script> 与 </script>标签之间。

js会忽略多余的空格

Javascript 脚本代码可被放置在 HTML 页面的 <body> 和 <head> 部分中。

在标签中填写 onclick 事件调用函数时,不是 οnclick=函数名, 而是 οnclick=函数名+(),

可以在文本字符串中使用反斜杠对代码行进行换行。

单行注释以 // 开头。
多行注释以 /* 开始,以 */ 结尾。

语句是用分号分隔,注释用双斜杠

引用一个函数 = 调用函数(执行函数内的语句)。

当您向变量分配文本值时,应该用双引号或单引号包围这个值。

当您向变量赋的值是数值时,不要使用引号。如果您用引号包围数值,该值会被作为文本来处理。

使用内置属性 length 来计算字符串的长度。

typeof 操作符来检测变量的数据类型。
在JavaScript中,数组是一种特殊的对象类型。 因此 typeof [1,2,3,4] 返回 object。
用 typeof 检测 null 返回是object。

NULL与undefined区别:null 和 undefined 的值相等,但类型不等:

var person = null;      // 值为 null(空), 但类型为对象
var person = undefined;     // 值为 undefined, 类型为 undefined。任何变量都可以通过设置值为 undefined 来清空。 类型为 undefined.

TS

TypeScript是JavaScript类型的超集(当前我们处于ES5),它可以编译成纯JavaScript。TypeScript可以构建大型程序,并在任何浏览器、任何计算机和任何操作系统上运行,且是开源的。

TS声明变量

在TS中,不使用var,使用let或const申明变量,并加上类型说明,且作用域为块级即以{}为界。

let lang: string = 'TypeScript';//如果省略类型说明,TS也可进行自动推断
lang = 1010;//error! 如果需要可以使用联合类型:let lang: number | string = 'TS';
let age: number = 89;
let age = 64;//error!

const pi: number = 3.14159;//pi以后不可改变,类似常量
pi = 3.14;//error!
TS解构

将对象、数组中的元素拆分到指定变量中,以方便使用

//解构数组
let input = [89, 64, 2018, 10];
let [first, second] = input;//注意使用[]
console.log(first); // 89
console.log(second); // 64
let [one, ...others] = input; //剩余变量
console.log(...others);
//展开
let newArr = [89, ...others, 18];
console.log(newArr);
//解构对象
let o = {
  a: "foo",
  b: 12,
  c: "bar"
};
let {a, b} = o;//注意使用{},且变量名需与对象中道属性名一致
console.log(a, b);
TS函数
使用完整函数类型定义
//命名函数,有完整的参数和返回类型。可以不用,TS将自动进行类型推断但推荐使用!
function add(x: number, y: number): number {
  return x + y;
}
//匿名函数
let myAdd = function(x: number, y: number): number { return x + y; };
console.log(myAdd(1, '2'));//error
console.log(myAdd(1));//error
console.log(typeof myAdd(1, 2));//number 
可选参数
//可选参数,必须放在必要参数后
function greeting(firstName: string, lastName?: string) {
  if(lastName) {
      return `Hello ${firstName} ${lastName}!`;
  }
  return `Hello ${firstName}!`;
}
console.log(greeting('QiGe'));
console.log(greeting('QiGe', 'Wang'));
console.log(greeting('QiGe', 'Wang', 'Yong'));//error!
默认参数
//默认参数,不必在必要参数后
function greeting(firstName: string, lastName = 'Wang') {
  return `Hello ${firstName} ${lastName}!`;
}
console.log(greeting('QiGe'));
console.log(greeting('QiGe', 'HaHaHa'));
console.log(greeting('QiGe', 'HaHaHa', 'Yong'));//error!
剩余参数

必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来, 在TypeScript里,你可以把所有参数收集到一个变量里

//剩余参数,会被当做个数不限的可选参数。可以一个都没有,也可以有任意个
function greeting(firstName: string, ...restName: string[]) {
  return `Hello ${firstName} ${restName.join(' ')}!`;
}
console.log(greeting('Osama', 'bin', 'Muhammad', 'bin', 'Awad', 'bin', 'Laden'));
console.log(greeting('Laden'));
          
###### 箭头函数
特点:简化函数定义、解决this问题,与上述的箭头函数大同小异。
```ts
//无参数,函数体代码只有一行,则该行结果即为函数返回值
let greeting1 = () => `Hello TS!`;
console.log(greeting1());
//一个参数,函数体代码只有一行,则该行结果即为函数返回值
let greeting2 = (name: string) => `Hello ${name}`;
console.log(greeting2('QiGe'));
//两个及以上的参数,函数体代码只有一行,则该行结果即为函数返回值
let add1 = (n1: number, n2: number) => n1 + n2;
console.log(add1(1, 2));
//两个及以上的参数,函数体代码多于一行,则必须用{}包裹,且显式给出return
let add2 = (n1: number, n2: number) => {
  let sum = n1 + n2;
  return sum;//改为sum++结果如何?
}
console.log(add2(1, 2));
泛型
泛型的定义

使用类型变量,它是一种特殊的变量,只用于表示类型而不是值。

function identity<T>(arg: T): T {
    return arg;
}

我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。

我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。它不会丢失信息,可以保持准确性,传入数值类型并返回数值类型。

使用方法

我们定义了泛型函数后,可以用两种方法使用。

第一种是,传入所有的参数,包含类型参数:

let output = identity<string>("myString");  // type of output will be 'string'

这里我们明确的指定了T是string类型,并做为一个参数传给函数,使用了<>括起来而不是()。

第二种方法更普遍。利用了类型推论 – 即编译器会根据传入的参数自动地帮助我们确定T的类型:

let output = identity("myString");  // type of output will be 'string'

注意:我们没必要使用尖括号(<>)来明确地传入类型;编译器可以查看myString的值,然后把T设置为它的类型。

使用泛型变量

使用泛型创建像identity这样的泛型函数时,你必须把这些参数当做是任意或所有类型。

function identity<T>(arg: T): T {
    return arg;
}

如果我们想同时打印出arg的长度。 我们很可能会这样做:

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length);  // Error: T doesn't have .length
    return arg;
}

如果这么做,编译器会报错说我们使用了arg的.length属性,但是没有地方指明arg具有这个属性。
记住,这些类型变量代表的是任意类型,所以使用这个函数的人可能传入的是个数字,而数字是没有 .length属性的。

function loggingIdentity<T>(arg: T[]): T[] {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}

你可以这样理解loggingIdentity的类型:泛型函数loggingIdentity,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型是T的数组。 如果我们传入数字数组,将返回一个数字数组,因为此时 T的的类型为number。 这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型。

function loggingIdentity<T>(arg: Array<T>): Array<T> {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}
类class

类是属性和函数的集合,是生成对象(Object)或类实例的模板。

类的定义和使用
//类的定义和使用
class MyInfo { //class是关键字,类名默认全部大写首字母
  name: string; //属性
  weather: string; //属性
  constructor(name: string, weather: string){ //构造函数,一般用于初始化。如果没有,TS会自动生成一个,以备用new创建类实例时调用。
    this.name = name;
    this.weather = weather;
  }
  printInfo(): void { //其它函数,无返回值
    console.log(`Hello, ${this.name}.`);
    console.log(`Today is ${this.weather}.`);
  }
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象,即该类的实例
myData.printInfo();
类的属性和函数的访问权限

类中的属性和函数都有访问权限,默认为public即全局可访问,其次为protected即可在类的内部和其子类的内部可访问,最后为private,只能在该类内部可访问。

//访问权限
class MyInfo { //class是关键字,类名默认全部大写首字母
  public name: string; //public属性,可省略
  private _weather: string; //私有属性,习惯以_开头进行命名
  
  constructor(name: string, weather: string){ //构造函数,一般用于初始化
    this.name = name;
    this._weather = weather;
  }
  printInfo(): void { //其它函数
    this._test();
    console.log(`Hello, ${this.name}.`);
    console.log(`Today is ${this._weather}.`);
  }
  private _test(): void {
    console.log('You can not call me outside!');
  }
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象
console.log(myData._weather); //error!
myData._test(); //error
myData.printInfo();
存取器-getter、setter

当在类外部时,建议设置getter和setter操作其private属性,即使public属性也如此。

//getter和setter
class MyInfo { //class是关键字,类名默认全部大写首字母
  private readonly _name: string; //私有属性,外部不可访问。readonly使其只能在初始化时赋值,以后不可更改。    
  private _weather: string; //私有属性,习惯以_开头进行命名
  constructor(name: string, weather: string){ //构造函数,一般用于初始化
    this._name = name;
    this._weather = weather;
  }
  get name(): string {
    return this._name;
  }
  set name(value: string) {  //error! _name有readonly属性
    this._name = value;
  }
  get weather(): string {
    return this._weather;
  }
  set weather(value: string) {
    this._weather = value;
  } 
}
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象
console.log(myData.name, myData.weather);
myData.weather = 'sunny'; //OK
myData.name = 'Wang'; //error!
console.log(myData);
静态属性

类中的属性或函数有static修饰,则可直接使用而不需要实例化

//静态属性,内建或自定义,无需new即可使用
console.log(Math.round(89.64)); //90
console.log(Math.pow(2, 8)); //256
class MyStaticClass {
  static place = 'Earth';
  static printInfo() {
    console.log('We have only one Earth!');
  }
}
console.log(MyStaticClass.place);
MyStaticClass.printInfo();
继承

可以通过extends关键字继承其它类,从而成为其子类

class Animal {
  // 当构造函数传入的参数加上了“访问权限控制符”,则同时会声明同名类属性,并赋值
  constructor(public name: string) { }
  protected log(message: string) {
    console.log(message);
  }
  move(distanceInMeters: number = 0) {        
    this.log(`${this.name} moved ${distanceInMeters}m.`);//请注意name来自何处
    this.log('==============');
  }
}
class Horse extends Animal {
  constructor(name: string) { 
    super(name); // 通过super调用父类构造器
  }
  run(distanceInMeters = 50) { //自己独有的函数
    this.log("Clop, clop..."); 
    super.move(distanceInMeters); // 通过super调用父类方法
  }
}
class Eagle extends Animal {
  constructor(name: string) { super(name); }
  reborn() { //自己独有的函数
    console.log('Reborn? It is a joke, hahaha!');
  }
}
let tom: Horse = new Horse("Tommy the Palomino");
tom.run(8964);
let sam: Eagle = new Eagle("Sammy the Hawk");
sam.move(1024);//sam的move函数来自何处?
sam.reborn();
模块Module

对于大型的项目,我们需要使用模块进行管理。每个 .ts 文件就是一个模块,通过 export 来对外部模块暴露元素,通过 import 来引入模块。

在项目文件夹下新建目录modules和文件main.ts,并在modules下新建name.ts和weather.ts文件。

modules/name.ts

export class Name { //用export对外部暴露该类
  constructor(private first: string, private second: string) {}
  get nameMessage() {
    return `Hello ${this.first} ${this.second}`;
  }
}           

modules/weather.ts

export class WeatherLocation { //用export对外部暴露该类
  constructor(private weather: string, private city:string) {}
  get weatherMessage() {
    return `It is ${this.weather} in ${this.city}`;
  }
}   

main.ts

//用import从外部模块文件导入,默认后缀.ts去掉
import { Name } from "./modules/name";
import { WeatherLocation } from "./modules/weather";
let name = new Name('Wang', 'Yong');
let loc = new WeatherLocation('raining', 'ChongQing');
console.log(name.nameMessage);
console.log(loc.weatherMessage);         
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值