自动摘要: 1.let与const 1.let命令 1.所声明的变量,只在let命令所在的代码块内有效(for循环的计数器,很适合使用let命令) 2.不存在变量提升,变量需 ……..
- let与const
- let命令
- 所声明的变量,只在let命令所在的代码块内有效(for循环的计数器,很适合使用let命令)
- 不存在变量提升,变量需要在声明之后才能使用
- 暂时性死区(temporal dead zone TDZ),只要在块级作用域内存在let命令,它所声明的变量就绑定这个区域,不受外部影响,在代码块内,使用let命令声明变量前,该变量都是不可用的。
- 不允许重复声明,不允许在相同作用域内,重复声明同一个变量
- 块级作用域
- ES6在5的基础上增加了块级作用域
- ES6允许块级作用域的任意嵌套
- 内层作用域可以定义外层作用域的同名变量
- 以下三天规则只对ES6的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理
- 允许在块级作用域内声明函数
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部
- 同时,函数声明还会提升到所在的块级作用域的头部
- 考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,应该写成函数表达式,而不是函数声明语句(块级作用域内部,优先使用函数表达式)
- ES6的块级作用域必须有大括号,如果没有大括号,JavaScript引擎就认为不存在块级作用域
- const命令
- 声明一个只读常量,常量的值不能改变(本质:const实际上保证的,不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单的数据比如数值,字符串,布尔值。值就保存在变量指向的那个内存地址,因此等同于常量。但是对于复合类型的数据,主要是对象和数组。变量指向的内存地址,保存的只是一个指向实际数组的指针,const只能保证这个指针是固定的,即总是指向另一个固定的地址,至于它指向的数据结构是不是可变的,就完全不能控制了。所以使用const声明复杂类型数据时就要慎重)
- 如果常量是对象或数组,则常量存储的是一个地址,这个地址指向一个对象。不可变的是这个地址,即不能把常量指向另一个地址,但是对象本身是可以改变的,所以依然可以为其添加新的属性
- 声明一个只读常量,常量的值不能改变(本质:const实际上保证的,不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单的数据比如数值,字符串,布尔值。值就保存在变量指向的那个内存地址,因此等同于常量。但是对于复合类型的数据,主要是对象和数组。变量指向的内存地址,保存的只是一个指向实际数组的指针,const只能保证这个指针是固定的,即总是指向另一个固定的地址,至于它指向的数据结构是不是可变的,就完全不能控制了。所以使用const声明复杂类型数据时就要慎重)
- let命令
1 | const foo = {}; |
2. 如果真的想冻结对象,可以使用Object.freeze方法
1 | const foo = Object.freeze({}) |
2. const声明必需初始化常量,必需赋值
3. const作用域只在声明所在的块级作用域内有效;
4. 也存在暂时性死区
- ES6一共有六种声明变量的方法:var、function 、let 、const 、import 、class
- 解构赋值
解构赋值是对赋值运算符的扩展,是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
解构模型:解构的目标 = 解构的源 (解构的目标,解构赋值表达式的左边部分,解构的源是解构赋值表达式的右边部分)
数组模型的解构(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// 基本
let [a,b,c] = [1,2,3];
// a=1
// b=2
// c=3
// 可嵌套
let [a,[[b],c]] = [1,[[2],3]];
// a=1
// b=2
// c=3
// 可忽略
let [a, ,b] = [1,2,3];
// a=1
// b=3
// 不完全解构
let [a=1,b] =[];
// a=1
// b=undefined
// 剩余运算符
let [a,...b] = [1,2,3];
// a=1;
// b=[2,3]
// 字符串
let [a,b,c,d,e] = "hello"
// a='h'
// b='e'
// c='l'
// d='l'
// e='o'
// 解构默认值
let [a=2] = [];
// a=2
// 当解构模式有匹配结果,且匹配结果是undefined时,会触发默认值作为返回结果
let [a=3,b=a] = []; // a=3,b=3
let [a=3,b=a] = [1]; // a=1,b=1
let [a=3,b=a] = [1,2]; // a=1,b=2对象模型的解构(Object)
1 | // 基本 |
- Symbol
** 数据类型Symbol表示独一无二的值**
- 基本用法
tips
let sy = Symbol(“KK”);console.log(sy); // Symbol(KK)typeof(sy); // “symbol”
- Symbol 函数栈不能用new命令,因为Symbol是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的Symbol提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。
- 相同参数Symbol()返回的值不相等
使用场景
- 可以用作属性名,因为Symbol的值都是不相等的,所以可以保证属性的不重名💡 Symbol作为对象的属性名时,不能用 . 运算符,要用方括号,因为 . 运算符后面是字符串,所以取到的是字符串sy属性,而不是Symbol值sy属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19let sy = Symbol("key1");
// 写法1
let syObject = {};
syObject[sy] = "kk";
console.log(syObject); // {Symbol(key1): "kk"}
// 写法2
let syObject = {
[sy]: "kk"
};
console.log(syObject); // {Symbol(key1): "kk"}
let syObject = {};
syObject[sy] = 'kk';
syObject[sy]; // "kk"
syObject.sy; // undefined
- 可以用作属性名,因为Symbol的值都是不相等的,所以可以保证属性的不重名
注意点
- Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。但是不会出现在 for…in 、 for…of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
1
2
3
4
5
6
7
8
9
10
11let syObject = {};
syObject[sy] = "kk";
console.log(syObject);
for (let i in syObject) {
console.log(i);
} // 无输出
Object.keys(syObject); // []
Object.getOwnPropertySymbols(syObject); // [Symbol(key1)]
Reflect.ownKeys(syObject); // [Symbol(key1)]
- Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。但是不会出现在 for…in 、 for…of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
Symbol.for()
- 类似单例模式,首先会在全局搜索被登记的Symbol中是否有该字符串参数作为名称的Symbol值,如果有即返回该Symbol值,若没有则新建并返回一个以该字符串参数为名称的Symbol值,并登记在全局环境中供搜索
Symbol.keyFor()
- 返回一个已登记的Symbol类型值得key,用来检测该字符串参数作为名称得Symbol值是否已被登记
函数
- 函数参数的扩展
默认参数:注意在使用默认参数时,不允许有同名参数
只有在未传递参数,或者是参数为undefined时,才会使用默认参数,null值被认为是有效的值传递
函数参数默认值存在暂时性死区,在函数参数默认值表达式中,还未初始化赋值的参数值无法作为其他参数的默认值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function f(x,x=y){
console.log(x,y)
}
f(1); // 1,1
function f(x=y){
console.log(x);
}
f(); //ReferenceError: y is not defined
// 不定参数
function f(...values){
console.log(values.length);
}
f(1,2); // 2
f(1,3,5,6); //4不定参数:用来表示不确定参数个数。形如:…变量名。由…加上一个具名参数标识符组成,具名参数标识符只能放在最后,并且有且只有一个不定参数
- 箭头函数
- 更加简洁的函数书写方式
- 语法:参数=>函数体
- 当箭头函数没有参数或有多个参数,要用()括起来
- 当箭头函数函数体有多行语句,要用{},表示代码块,当只有一行语句,并且需要返回结果时,可以省略{},结果会自动返回
- 当箭头函数要返回对象时,为了区分于代码块,要用()将对象括起来
- 注意点:没有this、supper、arguments和new.target绑定
- 箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。
- 使用场景:需要维护一个this上下文的时候,就可以使用箭头函数
- 函数参数的扩展
字符串
- 字符串识别
- includes():返回布尔值,判断是否找到参数字符串
- startsWith():返回布尔值,判断参数字符串是否在原字符串的头部
- endsWith():返回布尔值,判断参数字符串是否在原字符串的尾部。
- 以上方法都可以接受两个参数,一个是需要搜索的字符串,一个是可选的搜索起始位置索引
- 这三个方法只返回布尔值,如果需要知道子串的位置,还是得用indexOf和lastIndexOf
- 字符串重复:repeat():返回新的字符串,表示将字符串重复指定次数返回。如果参数是小数,向下取整,如果参数是NaN,等同于零次,如果参数是负数或者Infinity,会报错。如果传入的参数是字符串,会先将字符串转化为数字。
- 字符串补全:
- padStart:返回新的字符串,表示用参数字符串从头部(左侧)补全原字符串
- padEnd:返回新的字符串,表示用参数字符串从尾部(右侧)补全字符串
- 以上两个方法接受两个参数,一个是指定生成的字符串的最小长度,第二个参数是用来补全的字符串
- 如果没有第二个参数,默认用空格补全。
- 如果指定的长度小于或等于字符串长度,则返回原字符串;
- 如果原字符串加上补全字符串的总长度大于指定长度,则截去超出位数的补全字符串
- 模板字符串:
- 相当于加强版的字符串,用反引号 ` 。除了作为普通字符串,还可以用来定义多行字符串,还可以在字符串中加入变量和表达式
- 字符串插入变量和表达式,变量名写在${}中,${}中可以放入JavaScript表达式
- 字符串中也可以调用函数
- 注意:模板字符串中的换行和空格都是会被保留的
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// 普通字符串
let string = `Hello'\n'world`;
console.log(string);
// Hello'
// 'world
//多行字符串
let string = `Hey,
Can you stop angry now?`;
console.log(string);
// Hey
// Can you stop angry now?
// 字符串中加入变量和表达式
let name = "Anne";
let age = 17;
let string = `My name is ${name},I am ${age+1} years old next year.`;
console.log(string);
// My name is Anne,I am 18 years old next year.
// 字符串中调用函数
function f(){
return "have fun";
}
let string = `Good Game! ${f()}`;
console.log(string)
// Good Game! have fun
- 字符串识别
Map 与 Set
Map对象保存的是键值对,任何值(对象或者原始值)都可以作为一个键或一个值
Maps和Objects区别
- Object的键只能是字符串或者Symbols,但是一个Map的键可以是任意值
- Map中的键值是有序的(FIFO原则),而添加到对象Object中的键则不是
- Map的键值对个数可以从size属性获取,而Object的键值对个数只能手动计算
- Object都有自己的原型。
Map的遍历
- for….of
- forEach()
1
2
3
4
5
6
7
8
9
10
11
12
13var myMap = new Map();
myMap.set(0,"zero");
myMap.set(1,"one");
// for...of
for(var [key,value] of myMap){
console.log(key+ "=" +value);
}
// forEach()
myMap.forEach(function(key,value){
console.log(key+"="+value);
},myMap)
Map对象的操作
- Map与Array的转换
- Map构造函数可以将一个二维键值对数组转换成一个Map对象
- var myMap = new Map(kvArray)
- 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组
- var outArray = Array.from(myMap)
- Map构造函数可以将一个二维键值对数组转换成一个Map对象
- Map的克隆
- var myMap2 = new Map(myMap1)
- Map克隆之后生成新的对象。两个对象不相等
- Map的合并
- 合并两个Map对象时。有重复的键值,则后面的会覆盖前面的.
- Set对象:允许存储任何类型的唯一值,无论是原始值或者是对象引用
- Set对象存储的值总是唯一的
- +0 与 -0在存储判断唯一性的时候是恒等,所以不重复
- undefined 与undefined是恒等的,所以不重复
- NaN 与 NaN是不恒等的,但是Set只能存一个,所以不重复
- 类型转换 var mySet = new Set([“value1”, “value2”, “value3”]);
- Array转Set:var myArray = […mySet];
- String转Set:var mySet = new Set(‘hello’)
- 在Set中toString方法是不能将Set转换成String
- Set对象作用
- 数组去重
- 并集
- 交集
- 差集
- Map与Array的转换
Promise对象
- 是异步编程的一种解决方案。Promise是一个对象,从它可以获取异步操作的信息。