ECMAScript是什么
简单来说就是JavaScript具有划时代意义的一个版本(2015 年 6 月正式发布),具体为什么叫ECMAScript,可以看阮一峰的《ECMAScript6入门》。
本文的写作目的其实是回忆起一些常用的ES6变量、方法,作为一个个人的学习记录。本机使用的是Node.js v18.15.0
关于版本的兼容性问题可以看: https://compat-table.github.io/compat-table/es6
变量与常量 let const
早期学习过js或者看了老资料的都看过一个关键字——var
,这个关键字存在变量提升的问题,这时候就容易出现指针混乱。
在ES6中使用更加规范的const
和let
作为var
关键字的替代,将声明的变量都限制在代码块中且不允许变量的提升。
- let 变量 可后期修改,只服务于当前的块级作用域{ }
- const 常量 不可后期修改,在声明后即可使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| let name = "gcnanmu"; console.log(name) console.log(typeof name)
let balance = 100; console.log(balance) console.log(typeof balance)
const pi = 3.14 console.log("PI",pi)
name = "gcnanmu2" console.log(name)
pi=3 console.log(pi)
|
提一嘴,在ES6之后都不用在代码的末尾添加;
数据类型 typeof
我们日常说ES6基本指的是2015年之后的所有版本,所以网上对ES6有几种数据类型说法很多,但是常用的就那么几个数据类型,分别是数组(array),数字(number)、字符串(string)、对象(object)、集合(set)、布尔(boolen),函数(function),类(class),map等八种类型。
想要查看当前的数据类型,有三种常用的方法:
- typeof 变量
- Object.prototype.toString.call(变量)
- 变量.constructor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| let name = "gcnanmu";
let balance = -100; let weight = 60.5;
let tv1 = true; let tv2 = false; console.log("tv1", tv1, typeof tv1) console.log("tv2", tv2, typeof tv2)
let boy = { name: "gcnanmu", age: 20, weight: 60.5 } console.log("boy", boy, typeof boy)
let girl = new Map([ ["name", "luna"], ["age", 18] ]) console.log("girl", girl, typeof girl)
let number = new Set([1, 2, 3, 2, "2"]) console.log("number", number, typeof number)
let arr = ["a", "b", "c", "b", "c"] console.log("arr", arr, typeof arr)
function myFunction(a, b) { console.log(a, b) return a + b }
let result = myFunction(1, 2) console.log("result", result)
class Person { constructor(name, age) { this.name = name this.age = age }
info() { console.log("name", this.name, "age", this.age) } }
let my = new Person("gcnanmu", 23) my.info()
|
其中数据类型又可以继续划分为两种:
- 基本数据类型:number,string,boolen等
- 引用数据类型:object,map,function等
对于这两种数据类型,需要注意的就是引用数据类型的赋值操作赋值的是地址,而不是数据本身。
函数 function
函数很像数学的概念,输入一个x,根据编写的逻辑处理得到一个新的值。在ES6中为了方便函数的书写(偷懒),引入了箭头函数和隐士返回两个新特性。
箭头函数是为了方便匿名函数书写的,有了箭头函数后,可以将匿名函数省略大半:
1 2 3 4 5 6 7 8 9
| let sub = function (x, y) { return x - y }
let plus = (a, b) => { return a + b; }
|
如果你只有一个返回值,那么还可以进一步将return省略(即隐士返回):
1 2 3 4 5 6 7
| let plus = (a, b) => { return a + b; }
let plus = (a , b) => (a+b)
|
数组 Array
数组可能是我们编写函数最常用的数据类型。因为使用的评率太高,所以方法都必须要牢记。基本操作分为增删改查和排序。常用的属性为length。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| let arr = [10, 11]; console.log("arr", arr)
let arrlength = arr.push(12, 13) console.log("arr", arr) console.log("arrlength", arrlength)
arrlength = arr.unshift(8, 9); console.log("arr", arr) console.log("arrlength", arrlength)
let delElement = arr.shift() console.log("delElement", delElement)
delElement = arr.pop() console.log("delElement", delElement)
let delArr = arr.splice(2, 2) console.log("arr", delArr)
arr.reverse() console.log("arr", arr)
let arr2 = ["banana", "apple", "orange"] arr2.sort() console.log("arr2", arr2)
let arr3 = [5, 20, 13, 1, 4] arr3.sort((a, b) => (a - b)) console.log("arr3", arr3)
let arr4 = [10, 11, 12, 13, 14, 15] let newArr = arr4.filter((value) => { return value > 12 }) console.log("newArr", newArr)
for (let item of arr2) { console.log(item) }
arr2.forEach((value, index) => { console.log(index, value) })
console.log(arr2.slice(0, 1)); console.log(arr2.slice(0, 2));
|
这边要提一嘴两个不同的for循环:
for of 取出的是其中的元素
1 2 3
| for (let num of number) { console.log(num); }
|
for in 按顺序遍历下标,而不是元素
1 2 3 4 5 6 7
| for (let num in number) { console.log(number[num]); }
for (let i = 0; i < number.length; i++) { console.log(number[i]); }
|
在很多公司的面试题中还出现了reduce方法,这个方法常见的用法是累计的计算:
1 2 3 4 5 6 7 8
| let number = [1, 1, 2, 3];
let result = number.reduce((pre, cur) => { console.log(pre, cur); return pre + cur; });
console.log(result);
|
输出为:
另外,个人感觉js的循环也挺反直觉的,一般的语言都是(index,key,value)组合,而js是(value,key,index)
集合 Set
集合和数学上的集合一样,常用来存储简单的数据类型,里面不存在重复的元素,常见的用法是用来去重。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| let fruits = new Set(["apple", "banana", "orange"]) console.log(fruits)
fruits.add("mango") console.log(fruits)
fruits.delete("banana") console.log(fruits)
console.log(fruits.has("apple")); console.log(fruits.has("banana"));
console.log(fruits.size)
console.log(typeof fruits) let arr = Array.from(fruits) console.log(typeof arr)
let web = "gcnanmu3125.xyz" let web2 = "工程楠木" let webArr = [...web] let webArr2 = [...web2] console.log(webArr) console.log(webArr2)
console.log([...fruits])
for (let item of fruits) { console.log(item) }
fruits.forEach((value, index) => { console.log(index, value) })
let numberArr = [1, 2, 3, 3, 2, 1] let numberSet = new Set(numberArr) console.log( numberSet )
|
这边有提到一个打散的语法,可以将string这种对象直接打散为列表形式:
1 2 3 4 5 6 7 8 9 10
| let name = "gcnanmu"
console.log([...name]);
|
字符串 String
字符串和array的使用频率差不了太多,因此也需要单独记忆。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| let web = "www.BaiDu.com"
console.log(web.length)
console.log(web.toLowerCase())
console.log(web.toUpperCase())
console.log(web[2])
let strArr = [...web] console.log(strArr)
let number = parseInt("168") console.log(number)
let str1 = web.replaceAll("co", "y") console.log("替换全部", str1)
let str2 = web.replace("co", "y") console.log("替换第一个出现", str2)
let str3 = " baidu.com ".trim() console.log(str3)
let result = web.includes("Baidu") console.log("是否包含某个字符串:", result)
let result2 = web.indexOf("Baidu") console.log("返回字符串中第一次出现某个字符串的位置:", result2)
let result4 = "www.baidu.com".startsWith("www") console.log("判断一个字符串是否以指定的前缀开头:", result4)
let result5 = "www.baidu.com".endsWith("net") console.log("判断一个字符串是否以指定的后缀结尾:", result5)
let arr = "a,b,c,d".split(",") console.log("将字符串按照指定字符分割成数组:", arr)
let subStr = web.substring(0, 7) console.log("截取字符串的前7个字符:", subStr)
let subStr2 = web.substring(web.length - 3) console.log("截取字符串的最后3个字符:", subStr2)
let subStr3 = web.substring(4) console.log("从字符串的第5个位置开始截取直至字符串末尾:", subStr3)
let repeatstr = "David".repeat(3) console.log("重复3次字符串", repeatstr)
let padStart = "David".padStart(15, "-")
console.log("padStart:", padStart)
let padEnd = "David".padEnd(15, "-") console.log("padEnd:", padEnd)
|
集合 Map
Map集合存储键值对的数组,使用键值对来存储信息。下面是一个例子:
1 2 3 4 5 6 7 8 9 10
| let website = new Map([ ["百度", "https://www.baidu.com"], ["谷歌", "https://www.google.com"], ["bing", "https://www.bing.com"], ]);
console.log(website.keys()); console.log(website.values()); console.log(website.entries());
|
打印的输出为:
1 2 3 4 5 6 7 8 9 10 11
| [Map Iterator] { '百度', '谷歌', 'bing' } [Map Iterator] { 'https://www.baidu.com', 'https://www.google.com', 'https://www.bing.com' } [Map Entries] { [ '百度', 'https://www.baidu.com' ], [ '谷歌', 'https://www.google.com' ], [ 'bing', 'https://www.bing.com' ] }
|
一些常见的操作如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
let teacher = new Map([ ["name", "gcnanmu"], ["gender", "man"], ["web", "baidu.com"] ]) console.log(teacher)
teacher.set("height", 175) console.log(teacher)
teacher.delete("gender") console.log(teacher)
console.log(teacher.has("gender")) console.log(teacher.has("web"))
teacher.set("web", "www.baidu.com") console.log(teacher)
console.log(teacher.size)
let arr = Array.from(teacher) console.log(arr)
let arr2 = [...teacher] console.log(arr2)
for (let item of teacher) { console.log(item) }
for (let [key, value] of teacher) { console.log(key, value) }
teacher.forEach((value, key) => { console.log(key, value) })
teacher.clear() console.log(teacher)
|
对象 object
这个对象挺像Python中的dict,更像Python的数据类(@dataclass),使用.来获取属性值,它是不可迭代的,写法也很简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| let teacher = { name: "gcnanmu", gender: "man", web: "baidu.com" }
console.log(teacher)
teacher.height = 175 console.log(teacher)
teacher.web = "www.baidu.com" console.log(teacher)
delete teacher.gender console.log(teacher)
let has = "gender" in teacher console.log(has)
let has2 = "name" in teacher console.log(has2)
console.log(Object.keys(teacher)); console.log(Object.keys(teacher).length);
for (let key in teacher) { console.log("for……in key", key, teacher[key]) }
console.log(Object.entries(teacher));
Object.entries(teacher).forEach(([key, value]) => { console.log("foreach ",key, value) })
teacher = {} console.log(teacher)
|
类和私有属性 class
类是面向对象的起始方法,用于将具有相同属性或相同方法的数据结构放在一起,一般来说构造方法(constructor)内都是可访问的数据,也可以使用语法将其私有化。
方法有两种:
- 变量名前加#,此方法前面不能加this
- 变量前加_
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Person { #web = "www.baidu.com"; constructor(name, age) { this.name = name; this._age = age; }
sayHello() { console.log( `Hello, my name is ${this.name}, I am ${this.age} years old.` ); }
get web() { return this.#web; }
set web(value){ this.#web = value; }
get age() { return this._age; }
set age(value) { this._age = value; } }
|
语法和Python十分相似,甚至私有化也非常相似。
类的继承 extends
在数学中,集合与集合之间肯定存在交集的情况,类与类也是类似,比如我属于Person类,我有人一些共有的属性,比如我要吃饭和睡觉,这时候就不需要再重写编写相应的函数,只需要从父类中继承即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Person { name gender
constructor(name, gender) { this.name = name this.gender = gender }
sleep() { return `${this.name}休息中……` } }
class Me extends Person { web
constructor(name, gender, web) { super(name, gender); this.web = web }
eat() { return `${this.name}在吃饭……` }
sleep() { return `${this.name}在睡觉……` }
}
let person = new Me("wo", "男", "baidu.com")
console.log(person.name) console.log(person.eat()) console.log(person.sleep())
|
打印的结果是:
解构 {属性名}
解构的作用是将对象中的部分元素或者数组通过命名提取的方法来取出个别元素(可非连续)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| let [x, y] = [1, 2] console.log(`x:${x} y:${y}`)
let [, , c] = [10, 20, 30] console.log("c", c)
let [A, ...B] = [1, 2, 3, 4, 5, 6] console.log(A, B)
let [x2, y2 = 200] = [100] console.log(x2, y2)
let x3 = 10 let y3 = 20; [x3, y3] = [y3, x3] console.log(x3, y3)
let person = { name: "gcnanmu", gender: "man", web: "baidu.com" }
let {name} = person console.log(name)
let {name: userName, gender, web} = person console.log(userName, gender, web)
|
promise
promise是异步编程操作函数,和Python的try用法相同。promise是通过fulfilled和reject来判断是否成功运行,当然也可以直接不写,交给函数来判断。
- fulfill - 走then(resolve)
- reject - 走catch(reject)
- pending - 正在处理中
- finally - 无论是fulfill还是reject都会执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| let promise = new Promise((resolve, reject) => { reject("没有还钱") }).then(result => { console.log(result) }).catch(error => { console.log(error) }).finally(() => { console.log("异步执行结束") })
promise.then(result => { console.log(result) }).catch(error => { console.log(error) }).finally(() => { console.log("异步执行结束") })
|
fetch
fetch 是用于异步网络请求的函数,可以用来获取或发送数据,接收后会返回promise对象。常见的请求方式有get和post两种,因为网络中一般都发送json格式的数据,接收后还需要转化一下格式。
这里需要展示一下API请求工具,来自邓瑞。
访问http://127.0.0.1/get可看到数据的格式:
1 2 3 4 5 6 7 8 9
| { "data": { "gender": "男", "name": "邓瑞", "web": "dengruicode.com" }, "msg": "get请求", "status": "success" }
|
data为具体的数据,msg为请求的描述,status用来展示请求是否有效
安装Node.js
Node.js其实是JavaScript的一个解释器,npm则是Node Package Manager的缩写,就是一个Node.js的一个管理包的工具,网站为npmjs.com,可以从上面下载包,也可以使用命令进行下载。
下载Node.js,LTS是稳定版,Current是最新发行版。
Node.js — Download Node.js® (nodejs.org)
下载后使用下面的命令查看node.js版本和npm版本
查看当前npm的镜像源:
默认输出是 https://registry.npmjs.org
和Python一样,如果想要访问默认的镜像源下载,很容易出现超时的问题,这里推荐更换镜像源。
1
| npm config set registry https://registry.npmmirror.com/
|
这里更换的是淘宝的镜像源。
Axios
axios是基于promise的请求库,他可以发送http请求并接受服务器返回相应的数据,返回的是一个Promise对象 既可以应用于浏览器,也可用于[Node.js](Node.js — Run JavaScript Everywhere (nodejs.org))。
可以通过npm命令进行下载:
可能发现下载了很多模块,只需要导入名为axios.min.js
文件即可。
1
| <script src="../js/axios.js"></script>
|
也可以直接使用cdn
1
| <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
模块化开发 export import
模块化开发的本质就是将需要使用的数据或方法使用export导出,后续就可以在其他js中使用import导入export导出的数据或者方法
先创建一个index.js文件
1 2 3 4 5 6 7 8 9
| let title = "百度" let web = "baidu.com"
let getWeb = () => { return `title: ${title}, web: ${web}` }
export {title,web,getWeb}
|
后续便可以在html模版中导入(Node.js不支持在模版之外的其他地方使用import)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="module"> import {title as webTitle, web, getWeb} from "./index.js"
console.log(webTitle) console.log(web) console.log(getWeb())
</script> </body> </html>
|
如果想要将导入的数据作为一个对象整体使用可以在导入时候作为一个obj:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="module"> import * as obj from "./index.js"
console.log(obj.title) console.log(obj.web) console.log(obj.getWeb())
</script> </body> </html>
|
也可以修改index.js
1 2 3 4 5 6 7 8 9
| let title = "百度" let web = "baidu.com"
let getWeb = () => { return `title: ${title}, web: ${web}` }
export default {title,web,getWeb}
|
后续就可以直接导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="module"> import obj from "./index.js"
console.log(obj.title) console.log(obj.web) console.log(obj.getWeb())
</script> </body> </html>
|
异步 async
async关键字一般要配合await关键字使用,用来完成异步请求操作。使用异步的好处是不会因为等待耗时的操作而影响主线程的执行(主线程阻塞)。可以使用同步的方式编写异步代码。
- 当一个函数被标记为async后,该函数会返回一个Promise对象
- await只能在async内部使用,加上await关键字后,会执行到这一行暂停函数的部分
- 等到网络请求完成,然后继续执行并获取到请求返回的数据
非异步操作的话是这样写的:
1 2 3 4 5 6 7
| axios.get("https://localhost/get").then(response => { console.log("get_data", response.data) }).catch(error => { console.log("get_error", error) }).finally(() => { console.log("get.finally") })
|
如果使用异步关键字,可改为如下形式:
1 2 3 4 5 6 7 8 9 10 11
| const getData = async () => { try { const response = await axios.get("https://localhost/get") console.log("async.get.data", response.data) } catch (error) { console.log("async.get_error", error) } finally { console.log("async.get.finally") } } getData()
|
还有一个作用是避免回调地狱,。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| axios.get('http://127.0.0.1/get').then(response => { console.log("get.data:", response.data) if (response.data.data.web == "dengruicode.com") {
return axios.get('http://127.0.0.1/article/get/id/1').then(response2 => { console.log("get2.data:", response2.data) if (response2.data.data.name == "邓瑞") {
return axios.get('http://127.0.0.1/article/get/search/title/入门').then(response3 => { console.log("get3.data:", response3.data) }) } }) } }).catch(error => { console.log("get.error:", error) }).finally(() => { console.log("get.finally") })
|
使用async和wait后会变成如下,简洁了不少:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
const getData = async () => { try { const response = await axios.get('http://127.0.0.1/get') console.log("async.get.data:", response.data) if (response.data.data.web === "dengruicode.com") {
const response2 = await axios.get('http://127.0.0.1/article/get/id/1') console.log("async.get2.data:", response2.data) if (response2.data.data.name === "邓瑞") {
const response3 = await axios.get('http://127.0.0.1/article/get/search/title/入门') console.log("async.get3.data:", response3.data) } }
} catch (error) { console.log("async.get.error:", error) } finally { console.log("async.get.finally") } }
getData()
|