ES6&TS重点语法学习
以自己作为客户端RD的视角,列举了一些在实际使用中比较常见,而又比较陌生的语法(主要集中在ES6的特性上),做好一些铺垫和基础。
介绍
ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。在 ES5 的基础上新增了很多特性,完善了自身结构,解决了很多问题,更容易使用了。
TS - TypeScript,有类型的 JavaScript,通过增加静态类型检查来实现“强类型”特性,是 JavaScript 的超集,也可以通过被编译成低版本的 ES3 兼容所有运行环境。
TS 出现比ES6早,最初 TS 中添加了很多语法规范和特性,但随着 ES 的版本迭代,TS 的很多语法特性都被追平,目前集中在强类型上,对于客户端或熟悉使用编译型语言的同学来说,这种强类型模式比较熟悉,所以篇幅会比较小。
下面会先介绍 ES6,在此基础上,再介绍TS额外的部分。
ES6
一 变量声明
之前: var
现在:let(变量) 和 const(常量)
var 问题:
1.var 全局作用域,易出错;let const 块级作用域
{
let a = 10;
var b =20;
}
a //调用失败 let 声明的变量的为局部变量,只在{....}的块作用域生效。
b //20 var 声明的变量为全局变量,在全局作用域生效
// example 2
var s = "foo"
if (true) {
var s = "bar"
}
s // s=bar
2.const可定义常量
const a = 10;
a = 20; //再次赋值失败 const创建的变量为常量,一旦声明了就不能改变
二 解构赋值
变量的解构赋值为ES新推出的特性,指的是ES6允许按照一定的模式,从数组或对象中取出值,对变量进行赋值。 如果解构不成功,变量的值就等于undefined。
# 数组解构
let [a,b,c] = [1,2,3] 这种写法称为模式匹配,只要 “两边” 结构一致即可赋值。
console.log(a) //1
console.log(b) //2
console.log(c) //3
# 部分解构不成功
let [a,b] = [1]
console.log(a) //1
console.log(b) //undefined 部分解构不成功
// 默认值
let [a,b=3] = [1]
console.log(a) //1
console.log(b) //3
# 对象解构
let node = {
sex:'fmale',
age:10
}
let {sex,age} = node;
console.log(sex) //fmale 对象解构,对于内置对象同样可以。
console.log(age) //10
# 函数参数的解构赋值
function add([x,y]){
return x + y;
}
let value = add([1,2,3,4,5,6])
value //3 函数的参数解构赋值 形容 let [x,y] = [1,2,3,4,5,6]
# 数值的解构赋值
let [a,b,c] = 123
console.log(a) //1 数值解构
console.log(b) //2
console.log(c) //3
# 字符串的解构赋值
let [a,b,c] = '123';
console.log(a) //1
console.log(b) //2
console.log(c) //3
//原则上 只要两边的结构一致都可以进行解构赋值。
三 函数
箭头函数
去掉function,用箭头链接方法体
- 有且仅有一个参数,()可以不写
- 如果有且只一个语句,return 和 {}可以不写
let a = function(x){
return x * 2
}
a(4) // 8
// 变化1
let a = (x)=>{
return x * 2
}
a(4) // 8
// 变化2
let a = x=>{
return x * 2
}
a(4) // 8
// 变化3
let a = x=> x * 2
a(4) // 8
// 作为回调,在入参中简洁表达
setTimeout(() => {
// to do
}, 500)
this
js 里 this 使用非常复杂,就不展开说。直接说结论:
普通函数里 this 在函数调用时才被赋值,this 等于函数执行时候的执行环境;
使用箭头函数时,this 等于定义时的环境;
详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions
四 参数扩展
打开参数
数组展开
var arr = [1, 2, 3];
var arr2 = [...arr]; // ...arr 等价 [1,2,3]
arr2.push(4);
console.log(arr2)// [1, 2, 3, 4]
json展开
let obj1 = {
foo: 'bar',
x: 42
};
let obj2 = {
foo: 'new bar',
y: 13
};
let clonedObj = { ...obj1 };
let mergedObj = { ...obj1, ...obj2 }; // merge 后加的参数会覆盖先加入的参数
console.log(clonedObj) // {foo: "bar", x: 42}
console.log(mergedObj) // {foo: "new bar", x: 42, y: 13}
收集参数
函数的剩余参数
function add(a,...values){
var total = 0;
for(var val of values){
total +=val;
}
return total;
}
add(1,2,3,4,5); //2+3+4+5 = 14
五 数组的操作方法
这里记录的很全: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
挑几个常见的说下:
map() 映射 一一对应
reduce() 收集 出一个结果
filter() 过滤 留下一部分
foreach() 遍历 每一个都访问
let array = [1, 4, 9, 16];
// pass a function to map
let map1 = array.map(x => x * 2)
let map2 = array.reduce((x, y) => x + y)
let map3 = array.filter(x => x > 4)
let map4 = array.forEach(x => console.log(x))
console.log(map1);// expected output: Array [2, 8, 18, 32]
console.log(map2);// 30
console.log(map3);// [9, 16]
console.log(map4);// 1, 4, 9, 16
六 字符串模板
反单引号 `` 围起来字符串,可以动态添加变量
# 模板字符串中 嵌入变量
let [a,b] = ['jack','Bob']
let text = `hello ${a},I'm ${b}` // 美元符+花括号将变量替换到字符
text //hello jack, I'm Bob
# 模板字符串中进行逻辑运算
let [a,b] = [1,2]
let result = `${a} + ${b} = ${a+b}`
result //1 + 2 = 3
七 JSON 序列化操作
调试的时候很常用,有坑点单独说下。
JSON.stringify()
JSON.parse() // 需要标准化的JSON
// 不是标准化json,key不是字符串
let json = {
a:'foo',
b:'bar',
c:100
}
JSON.stringify(json) //"{"a":"foo","b":"bar","c":100}"
let str = '{"a":"foo","b":"bar","c":100}'
// let str = "{'a':'foo','b':'bar','c':100}" key一定要有"双引号",反过来也不行
JSON.parse(str)
八 异步编程
异步操作,回调地狱
代码块
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
let user
// ajax get请求数据
$.get('https://api.github.com/users', data=>{
console.log('fetched all users')
user = data[0].login
// 数据校验正确,再请求下一步
$.get(`https://api.github.com/users/${user}/repos`, data=>{
console.log('fetched all repos')
console.log(data)
})
})
</script>
回调地狱
promise
作用:进行统一的异步封装
let promise = new Promise(function (resolve, reject) {
// 做一些异步操作
if(/*异步操作成功*/){
//该value传入回调函数中
resolve(result);
}else{
//该error传入回调函数
reject(error);
}
})
promise.then(result=>{
console.log(result)
}).catch(err => {
console.log(err)
}).finally(()=>{
// 最终执行的代码段
})
//其他
1.Promise.all(arry) // all 等待所有异步操作执行完成 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
2.Promise.race(arry) // race 任一执行完成后就结束 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
再看上面的回调地狱,可以用阶段性返回 promise 对象来解决循环嵌套
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.2/axios.min.js"></script>
<script>
axios.get('https://api.github.com/users') // 返回一个 Promise
.then(reponse => {
let username = reponse.data[0].login
// 解析正确返回下一个请求的Promise
return axios.get(`https://api.github.com/users/${username}/repos`)
})
.then(reponse => {
console.log(reponse.data)
})
.catch(err => {
console.log(err)
})
</script>
async/await
更直观的语法,将异步变同步,ES2017(es8)
async function myFetch() {
let reponse = await axios.get('https://api.github.com/users') // 返回一个 Promise
let username = reponse.data[0].login
let repos = await axios.get(`https://api.github.com/users/${username}/repos`)
// 操作 repos ...
}
async/await 原理:可以将函数执行暂停,通过将函数切换成多个小函数来实现。
更多参考:https://developer.mozilla.org/zh-CN/docs/learn/JavaScript/%E5%BC%82%E6%AD%A5/Async_await
九 模块
导出 export:独立模块的对象、函数、值是无法被其他文件访问到的,如果要让外部访问到,需要使用 export 导出
相对的,要使用其他模块内容,就需要导入 import 相关内容
// module "my-module.js"
function cube(x) {// 函数
return x * x * x;
}
const foo = Math.PI + Math.SQRT2;// 常量
var graph = {
options: {
color:'white',
thickness:'2px'
},
draw: function() {
console.log('From graph draw function');
}
}
export { cube, foo, graph };
// --------------- another file ---------------
import { cube, foo, graph } from 'my-module.js';
graph.options = {
color:'blue',
thickness:'3px'
};
graph.draw();
console.log(cube(3)); // 27
console.log(foo); // 4.555806215962888
此外还有默认导出,即我们在 vue 里常见的 export default ,只是将当前模块做默认导出,没有其他特殊含义。
// module "my-module.js"
export default function cube(x) {
return x * x * x;
}
// --------------- another file ---------------
import cube from './my-module.js';
console.log(cube(3)); // 27
TS
列举下实际开发中,常遇见的TS里有的,但是 ES6 所没有的特性,总结下来就是:
- 类型(核心)
- 面向对象增强
这里只是简单列举,一些细节和JAVA或OC使用都类似,如果遇到报错,再查文档 https://www.tslang.cn/docs/handbook/basic-types.html 找找原因,会比较好懂
一 类型
1.强类型
不同于大部分编译型语言,TS 的类型是写在变量名后面,通过冒号: 连接的
const name:String = "Hello World"
TypeScript 里也有现代语言都具备的类型推断特性(Java要10以上的版本),不需要每一个变量都声明类型。
2.支持联合类型
多种类型用竖线 | 连接,表示该变量可以是多种类型的
function padLeft(value: string, padding: string | number) {
// ...
}
function getSmallPet(): Fish | Bird {
// ...
}
3.元组
swift 里也有,允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string和number类型的元组。
let x: [string, number] = ['hello', 10];
4.枚举
这个都懂
enum Color {Red, Green, Blue}
5.特殊类型
- any —— 表示任何类型
- void —— 表示没有类型,用于修饰函数返回值类型,作为变量类型时,没有什么用
- never —— 表示的是那些永不存在的值的类型,和 null 或 undefined 不同,他用来表示类型,而不是具体的值
6.函数类型
在基础函数上,多了入参类型和返回值类型
//函数类型(入参的类型,返回值类型): 返回值类型
function(x: number, y: number): number {
// 函数体
return x + y;
};
声明一个函数的变量 myAdd ,也需要指定这个函数的类型,函数类型比较复杂点,分成入参类型和返回值类型。
(入参1:入参1类型, 入参2:入参2类型) => 返回值类型
代码块
// 变量名 函数类型(入参的类型,返回值类型) = 入参的类型(俩 number) 返回值类型 函数体
let myAdd: (x: number, y: number) => number = function(x: number, y: number): number { return x + y; };
// 定义太长了,不写,也可以通过推断得出
let myAdd = function(x: number, y: number): number { return x + y; };
// 箭头函数基本没变,入参加了类型
let double = (e: number) => { return e * 2}
推断文档:https://www.tslang.cn/docs/handbook/type-inference.html
二 面向对象
1.接口
这个JAVA开发太熟悉了,但是在TS里,他更多的是用来创建 Model 数据模型
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
加上可选,这种感觉就更明显了
interface SquareConfig {
color?: string;
width?: number;
}
2.类的Field支持修饰符
public 、private 、protected 这些老朋友不用多做介绍,再来个 readonly,相当于 final。
class Demo {
private a: string;
public b: string;
protected c: string;
readonly name: string; //相当于Java里的final,在初始化或构造函数里一定要被初始化,至多赋值一次
}
3.抽象类
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('roaming the earch...');
}
}
参考内容
ES6:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference
TS手册:https://www.tslang.cn/docs/handbook/basic-types.html
TS参考: https://zhuanlan.zhihu.com/p/98709371