ES6 let 与 const
- var 声明变量是在全局范围内有效。(可以重复使用,存在变量提升)
- let 声明的变量只在 let 命令所在的代码块内有效。((只能声明一次,for循环很适合用let,不存在变量提升)
- const 声明一个只读的常量,一旦声明,常量的值就不能改变。
ES6 明确规定,代码块内如果存在 let 或者 const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。
ES6 解构赋值
数组模型的解构(Array)
//基本
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]
//字符串等
//在数组的解构中,解构的目标若为可遍历对象,皆可进行解构赋值。可遍历对象即实现 Iterator 接口的数据。
let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'
//解构默认值
let [a = 2] = [undefined]; // a = 2
对象模型的解构(Object)
//基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'
//可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;
// x = 'hello'
// y = 'world'
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { }] } = obj;
// x = 'hello'
//不完全解构
let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
// x = undefined
// y = 'world'
//剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40}
//解构默认值
let {a = 10, b = 5} = {a: 3};
// a = 3; b = 5;
let {a: aa = 10, b: bb = 5} = {a: 3};
// aa = 3; bb = 5;
ES6 Symbol 基本数据类型
ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
ES6 数据类型除了 Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol 。
Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。
let sy = Symbol("KK");
console.log(sy); // Symbol(KK)
typeof(sy); // "symbol"
// 相同参数 Symbol() 返回的值不相等
let sy1 = Symbol("kk");
sy === sy1; // false
由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。
let 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"}
// 写法3
let syObject = {};
Object.defineProperty(syObject, sy, {value: "kk"});
console.log(syObject); // {Symbol(key1): "kk"}
Symbol 作为对象属性名时不能用.运算符,要用方括号。因为.运算符后面是字符串,所以取到的是字符串 sy 属性,而不是 Symbol 值 sy 属性
let syObject = {};
syObject[sy] = "kk";
syObject[sy]; // "kk"
syObject.sy; // undefined
Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。
但是不会出现在 for…in 、 for…of 的循环中,也不会被 Object.keys() 、Object.getOwnPropertyNames() 返回。如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
let 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()
Symbol.for() 类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
let yellow = Symbol("Yellow");
let yellow1 = Symbol.for("Yellow");
yellow === yellow1; // false
let yellow2 = Symbol.for("Yellow");
yellow1 === yellow2; // true
Symbol.keyFor()
Symbol.keyFor() 返回一个已登记的 Symbol 类型值的 key ,用来检测该字符串参数作为名称的 Symbol 值是否已被登记。
let yellow1 = Symbol.for("Yellow");
Symbol.keyFor(yellow1); // "Yellow"
ES6 Map 与 Set的方法
Map
Map 对象(保存键值对)
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
Maps 和 Objects 的区别
一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
Map 中的 key
//key 是字符串
var myMap = new Map();
var keyString = "a string";
myMap.set(keyString, "和键'a string'关联的值");
myMap.get(keyString); // "和键'a string'关联的值"
myMap.get("a string"); // "和键'a string'关联的值"
// 因为 keyString === 'a string'
//key 是对象
var myMap = new Map();
var keyObj = {},
myMap.set(keyObj, "和键 keyObj 关联的值");
myMap.get(keyObj); // "和键 keyObj 关联的值"
myMap.get({}); // undefined, 因为 keyObj !== {}
//key 是函数
var myMap = new Map();
var keyFunc = function () {}, // 函数
myMap.set(keyFunc, "和键 keyFunc 关联的值");
myMap.get(keyFunc); // "和键 keyFunc 关联的值"
myMap.get(function() {}) // undefined, 因为 keyFunc !== function () {}
//key 是 NaN
var myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN); // "not a number"
var otherNaN = Number("foo");
myMap.get(otherNaN); // "not a number"
//虽然 NaN 和任何值甚至和自己都不相等(NaN !== NaN 返回true),NaN作为Map的键来说是没有区别的。
Map 的迭代(遍历)
for…of
forEach()
//第一种:for...of
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 将会显示两个 log。 一个是 "0 = zero" 另一个是 "1 = one"
for (var [key, value] of myMap) {
console.log(key + " = " + value);
}
//第二种:forEach()
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 将会显示两个 logs。 一个是 "0 = zero" 另一个是 "1 = one"
myMap.forEach(function(value, key) {
console.log(key + " = " + value);
}, myMap)
Map 对象的操作
//----------------Map 与 Array的转换
var kvArray = [["key1", "value1"], ["key2", "value2"]];
// Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象
var myMap = new Map(kvArray);
// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
var outArray = Array.from(myMap);
//---------------------Map 的克隆
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);
var myMap2 = new Map(myMap1);
console.log(original === clone);
// 打印 false。 Map 对象构造函数生成实例,迭代出新的对象。
//-------------------Map 的合并
var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);
var second = new Map([[1, 'uno'], [2, 'dos']]);
// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的,对应值即 uno,dos, three
var merged = new Map([...first, ...second]);
Set 对象
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
let mySet = new Set();
mySet.add(1); // Set(1)---- {1}
mySet.add(5); // Set(2)---- {1, 5}
mySet.add(5); // Set(2)---- {1, 5} 这里体现了值的唯一性
mySet.add("some text");
// Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2};
mySet.add(o);
mySet.add({a: 1, b: 2});
// Set(5) {1, 5, "some text", {…}, {…}}
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储
类型转换 Array
// Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,将 Set 转 Array
var myArray = [...mySet];
// String 转 Set
var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能将 Set 转换成 String
Set 对象作用
//数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
//并集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
//交集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
//差集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}
ES6 Reflect 与 Proxy
Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的。
Proxy
//一个 Proxy 对象由两个部分组成: target 、 handler 。在通过 Proxy 构造函数生成实例对象时,需要提供这两个参数。 target 即目标对象, handler 是一个对象,声明了代理 target 的指定行为。
let target = {
name: 'Tom',
age: 24
}
let handler = {
get: function(target, key) {
console.log('getting '+key);
return target[key]; // 不是target.key
},
set: function(target, key, value) {
console.log('setting '+key);
target[key] = value;
}
}
let proxy = new Proxy(target, handler)
proxy.name // 实际执行 handler.get
proxy.age = 25 // 实际执行 handler.set
// getting name
// setting age
// 25
//------------- target 可以为空对象
let targetEpt = {}
let proxyEpt = new Proxy(targetEpt, handler)
// 调用 get 方法,此时目标对象为空,没有 name 属性
proxyEpt.name // getting name
// 调用 set 方法,向目标对象中添加了 name 属性
proxyEpt.name = 'Tom'
// setting name
// "Tom"
// --------------handler 对象也可以为空,相当于不设置拦截操作,直接访问目标对象
let targetEmpty = {}
let proxyEmpty = new Proxy(targetEmpty,{})
proxyEmpty.name = "Tom"
targetEmpty) // {name: "Tom"}
ES6 字符串方法
- **includes():返回布尔值,判断是否找到参数字符串**。
- **删除线格式~~ startsWith():返回布尔值,判断参数字符串是否在原字符串的头部**。
- **endsWith():返回布尔值,判断参数字符串是否在原字符串的尾部**。
- **repeat():返回新的字符串,表示将字符串重复指定次数返回**。
- **padStart:返回新的字符串,表示用参数字符串从头部(左侧)补全原字符串**。
- **padEnd:返回新的字符串,表示用参数字符串从尾部(右侧)补全原字符串(一个参数是指定生成的字符串的
- 最小长度,第二个参数是用来补全的字符串。如果没有指定第二个参数,默认用空格填充。)**。
let string = "apple,banana,orange";
string.includes("banana"); // true
string.startsWith("apple"); // true
string.endsWith("apple"); // false
string.startsWith("banana",6) // true
console.log("Hello,".repeat(2)); // "Hello,Hello,"
//如果参数是小数,向下取整
//如果参数是 0 至 -1 之间的小数,会进行取整运算,0 至 -1 之间的小数取整得到 -0 ,等同于 repeat 零次
//如果参数是 NaN,等同于 repeat 零次
//如果参数是负数或者 Infinity ,会报错:
//如果传入的参数是字符串,则会先将字符串转化为数字
console.log("h".padStart(5,"o")); // "ooooh"
console.log("h".padEnd(5,"o")); // "hoooo"
console.log("h".padStart(5)); // " h"
这三个方法只返回布尔值
ES6 数值方法
方法
Number.isFinite():
用于检查一个数值是否为有限的( finite ),即不是 Infinity
console.log( Number.isFinite(1)); // true
console.log( Number.isFinite(Infinity)); // false
Number.parseInt():
用于将给定字符串转化为指定进制的整数。
Number.parseInt('12.34'); // 12
Math.cbrt
用于计算一个数的立方根。
Math.cbrt(1); // 1
Math.imul
两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
// 大多数情况下,结果与 a * b 相同
Math.imul(1, 2); // 2
Math.hypot
用于计算所有参数的平方和的平方根。
Math.hypot(3, 4); // 5
Math.hypot(true); // 1
Math.hypot(false); // 0
// 空值会被转换为 0
Math.hypot(); // 0
Math.hypot([]); // 0
// 参数为 Infinity 或 -Infinity 返回 Infinity
Math.hypot(Infinity); // Infinity
Math.hypot(-Infinity); // Infinity
// 参数中存在无法转换为数值的参数时返回 NaN
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot({}); // NaN
Math.clz32
用于返回数字的32 位无符号整数形式的前导0的个数。
Math.clz32(0); // 32
Math.clz32(1); // 31
Math.clz32(0b01000000000100000000000000000000); // 1
// 当参数为小数时,只考虑整数部分
Math.clz32(0.5); // 32
// 对于空值或非数值,会转化为数值再进行计算
Math.clz32('1'); // 31
Math.clz32(); // 32
Math.clz32([]); // 32
Math.clz32({}); // 32
Math.clz32(NaN); // 32
Math.clz32(Infinity); // 32
Math.clz32(-Infinity); // 32
Math.clz32(undefined); // 32
Math.clz32('hhh'); // 32
Math.trunc
用于返回数字的整数部分。
Math.trunc(12.3); // 12
Math.trunc(12); // 12
// 整数部分为 0 时也会判断符号
Math.trunc(-0.5); // -0
Math.trunc(0.5); // 0
// Math.trunc 会将非数值转为数值再进行处理
Math.trunc("12.3"); // 12
// 空值或无法转化为数值时时返回 NaN
Math.trunc(); // NaN
Math.trunc(NaN); // NaN
Math.trunc("hhh"); // NaN
Math.trunc("123.2hhh"); // NaN
Math.fround
用于获取数字的32位单精度浮点数形式。
// 对于 2 的 24 次方取负至 2 的 24 次方之间的整数(不含两个端点),返回结果与参数本身一致
Math.fround(-(2**24)+1); // -16777215
Math.fround(2 ** 24 - 1); // 16777215
// 用于将 64 位双精度浮点数转为 32 位单精度浮点数
Math.fround(1.234) // 1.125
// 当小数的精度超过 24 个二进制位,会丢失精度
Math.fround(0.3); // 0.30000001192092896
// 参数为 NaN 或 Infinity 时返回本身
Math.fround(NaN) // NaN
Math.fround(Infinity) // Infinity
// 参数为其他非数值类型时会将参数进行转换
Math.fround('5'); // 5
Math.fround(true); // 1
Math.fround(null); // 0
Math.fround([]); // 0
Math.fround({}); // NaN
Math.sign
判断数字的符号(正、负、0)。
Math.sign(1); // 1
Math.sign(-1); // -1
// 参数为 0 时,不同符号的返回不同
Math.sign(0); // 0
Math.sign(-0); // -0
// 判断前会对非数值进行转换
Math.sign('1'); // 1
Math.sign('-1'); // -1
// 参数为非数值(无法转换为数值)时返回 NaN
Math.sign(NaN); // NaN
Math.sign('hhh'); // NaN
对数
Math.expm1()
用于计算 e 的 x 次方减 1 的结果,即 Math.exp(x) - 1 。
Math.expm1(1); // 1.718281828459045
Math.expm1(0); // 0
Math.expm1(-1); // -0.6321205588285577
// 会对非数值进行转换
Math.expm1('0'); //0
// 参数不为数值且无法转换为数值时返回 NaN
Math.expm1(NaN); // NaN
Math.log1p(x)
用于计算1 + x 的自然对数,即 Math.log(1 + x) 。
Math.log1p(1); // 0.6931471805599453
Math.log1p(0); // 0
Math.log1p(-1); // -Infinity
// 参数小于 -1 时返回 NaN
Math.log1p(-2); // NaN
Math.log10(x)
用于计算以 10 为底的 x 的对数。
Math.log10(1); // 0
// 计算前对非数值进行转换
Math.log10('1'); // 0
// 参数为0时返回 -Infinity
Math.log10(0); // -Infinity
// 参数小于0或参数不为数值(且无法转换为数值)时返回 NaN
Math.log10(-1); // NaN
Math.log2()
用于计算 2 为底的 x 的对数。
Math.log2(1); // 0
// 计算前对非数值进行转换
Math.log2('1'); // 0
// 参数为0时返回 -Infinity
Math.log2(0); // -Infinity
// 参数小于0或参数不为数值(且无法转换为数值)时返回 NaN
Math.log2(-1); // NaN
双曲函数方法
- Math.sinh(x): 用于计算双曲正弦。
- Math.cosh(x): 用于计算双曲余弦。
- Math.tanh(x):用于计算双曲正切。
- Math.asinh(x): 用于计算反双曲正弦。
- Math.acosh(x): 用于计算反双曲余弦。
- Math.atanh(x): 用于计算反双曲正切。
指数运算符
1 ** 2; // 1
// 右结合,从右至左计算
2 ** 2 ** 3; // 256
// **=
let exam = 2;
exam ** = 2; // 4