数据结构 Map 和 Set
跟数组和对象一样,map
和set
也是javascript
的复杂数据结构
Map
Map
和Object
一样,都是带有键的数据集合,跟Object
最大的区别就是Map
的键可以是任何类型,其常用属性和方法:
map.size
-------------------- 集合中元素的个数map.get(key)
--------------- 查看key
的值,若集合中不存在key
属性,则返回undefined
map.set(key, value)
------- 添加键值对map.has(key)
--------------- 检测集合中是否存在key
属性,若存在,返回true
,否则false
map.delete(key)
------------ 删除集合中key
属性map.clear()
---------------- 清空map
举个栗子:
// 创建一个 map
let map = new Map()
// Map 的键可以是任何类型, Object 则会自动转换成字符串
map.set('11', 'str') // 键可以是字符串
map.set(11, 'num') // 也可以是数字
map.set(true, 'bool') // 也可以是布尔值
alert(map.size) // 3
alert(map.get(11)) // num
alert(map.get(true)) // bool
注意: Map中不能使用map.key=value
或者map['key']=value
的方式添加属性,应该使用map
的 set
和 get
等方法
Map 还可以将对象作为键
let key = { name: 'jams' }
let map = new Map()
map.set(key, 111)
alert(map.get(key)) // 111
Set
Set
是一组保存唯一值的集合,与数组最大的区别是Set
里面的值只允许出现一次, 有以下常用属性和方法:
set.size
------------------元素个数set.add(value)
-----------添加值(如果已存在value
则不做任何操作), 返回值为set
本身set.delete(value)
--------删除值(若存在,返回true
,否则false
)set.has(value)
-----------检测是否存在value
,若存在,返回true
, 否则false
set.clear()
--------------清空set
// 创建 set
let set = new Set()
set.add('red')
set.add('blue')
set.add('green')
set.add('red') // 因为已存在'red',无效的操作
for(let key of set) {
alert(key) // red --> blue --> green
}
Set的这种特性被用来数组去重
let arr = ['red', 'green', 'blue', 'green', 'blue', 'red']
// 世上最简洁的数组去重方式
let newArr = [...new Set(arr)]
console.log(newArr) // ["red", "green", "blue"]
const 和 let
const
- 当可以确定这个变量永远不会改变的时候,就可以使用
const
来申明 - 使用大写字母和下划线来命名这些常量,以清楚地告知后来的开发者
- 常用于定义第三方模块或者常数(16进制的颜色,
PI
等)的变量
const COLOR_WHITE = '#FFF'
COLOR_WHITE = '#EEE' // 报错, 不能给常量重新赋值
let 和 var
1. var
没有块级作用域
用var
声明的变量不是全局作用域就是函数作用域,没有块级作用域
if (true) {
var test = 'hello'
}
alert (test) // hello
此时var
会忽略代码块,因此此时test
变量是作为一个全局变量存在
如果用let
声明,则只能在if
内部访问
if (true) {
let test = 'hello'
}
alert (test) // 报错, test is not defined
用var
声明的变量在循环结构中也是这样:
for(var i = 0; i < 10; i++) {
var test = 'hello'
}
alert (i) // 10
alert(test) // hello
用var
声明的变量存在函数作用域:
function sayHi() {
var test = 'hello'
console.log(test) // hello
}
sayHi()
alert(test) // 报错, test is not defined
2. var
允许被重新声明
var test = 'hello'
var test = '你好'
alert(test) // 你好
var
声明的变量可被重新赋值,而let
则会报错
let test = 'hello'
let test = '你好'
alert(test) // 报错, 'test'已经被声明
3. var
存在变量提升
alert(test) // undefined
var test = 'hello'
可以看到,这段代码,不会报错,其实相当于下面这段代码:
var test
alert(test) // undefined
test = 'hello'
模板字符串
解构赋值
在JavaScript
中,Array
和Object
是使用最多的数据类型,但是我们很多时候不需要使用到集合内部所有的数据,而是需要使用到其中的某一些数据,因此解构赋值可以让我们将数组/对象"拆包"为一系列变量中,因为使用变量可能会更方便一点.
数组解构
let arr = ['刘备', '关羽', '张飞', '黄忠', '赵云']
let [one, two, three, four, five] = arr
alert(one) // 刘备
alert(two) // 关羽
alert(three) // 张飞
alert(four) // 黄忠
alert(five) // 赵云
如果只需要其中的某一些数据
let arr = ['刘备', '关羽', '张飞', '黄忠', '赵云']
let [, one, , , two] = arr
alert(one) // 关羽
alert(two) // 赵云
还可以这样:
let arr = ['刘备', '关羽', '张飞', '黄忠', '赵云']
let [one, two, three, ...four] = arr
alert(one) // 刘备
alert(two) // 关羽
alert(three) // 张飞
console.log(four) // ['黄忠', '赵云']
注意: 因为数组是一个有序的数据集合,因此在解构的时候,需要注意等号左侧必须和等号右侧有相同的结构
对象解构
let userinfo = {
user_id: 1,
username: '张三',
password: '123456',
hobbies: ['吃饭', '睡觉', '打豆豆']
}
let { username, hobbies } = userinfo
console.log(username) // 张三
console.log(hobbies) // ["吃饭", "睡觉", "打豆豆"]
对象的解构中,变量的顺序不再重要,但是需要和对象中的属性名保持一致,如果会有变量命名冲突的情况,当然也可以将其赋值给新的变量名,比如这样:
let userinfo = {
user_id: 1,
username: '张三',
password: '123456',
hobbies: ['吃饭', '睡觉', '打豆豆']
}
let { username: name, hobbies: hobby } = userinfo
console.log(name) // 张三
console.log(hobby) // ["吃饭", "睡觉", "打豆豆"]
在解构的同时,也可以声明变量
let userinfo = {
user_id: 1,
username: '张三',
password: '123456',
hobbies: ['吃饭', '睡觉', '打豆豆']
}
let { username: name, hobbies: hobby, age = 18 } = userinfo
console.log(name) // 张三
console.log(hobby) // ["吃饭", "睡觉", "打豆豆"]
console.log(age) // 18
...
运算符在对象解构中同样适用
let userinfo = {
user_id: 1,
username: '张三',
password: '123456',
hobbies: ['吃饭', '睡觉', '打豆豆']
}
let { username: name, hobbies: hobby, ...info } = userinfo
console.log(name) // 张三
console.log(hobby) // ["吃饭", "睡觉", "打豆豆"]
console.log(info) // {user_id: 1, password: "123456"}
扩展运算符(三点运算符)
Class 类
箭头函数
let func = function (x) {
return x * x
}
// 将 func 函数用箭头函数进行改造
let func = (x) => {
return x * x
}
// 若函数体只有一行代码, 可将大括号和 return 关键字省略不写
let func = (x) => x * x
// 若函数只有一个参数,小括号可以省略
let func = x => x * x
// 如果没有参数或者有多个参数,小括号则不能省略
使用箭头函数应注意:
- 箭头函数没有自己的
this
对象,内部的this
就是定义时上层作用域中的this
- 不可以当作构造函数,也就是说,不可以对箭头函数使用
new
命令 - 箭头函数中没有
arguments
,如果要用,可以用rest
参数代替。
let func = (...argus) => console.log(argus) // [1, 2, 3]
func(1, 2, 3)
Promise 异步对象
在js
和node
中,都会使用回调函数嵌套的方式来解决异步操作返回结果的顺序不确定的问题,如果嵌套的层数特别多,就会形成回调地狱或者叫做横向金字塔,而Promise
对象,就是用来解决这个问题的.
Promise 简介
Promise
对象可以解决回调地狱的问题Promise
是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大Promise
可以理解为一个容器,里面可以编写异步程序的代码- 从语法上说,
Promise
是一个对象,使用的时候需要new
简单使用
let promise = new Promise((resolve, reject) => {
// 这里执行异步代码
})