JavaScript—浅谈ES6新特性(速记版)-上

1,965 阅读9分钟
今天复习一下ES6的新语法

一、let与const

  1. let只在代码块中有效,var在全局有效
  2. let不能重复声明,var可以
  3. let适合for循环
  4. let不存在变量提升,var有
  5. const声明常量时必须初始化
  6. const保证的是变量指向的内存地址的数据不变,而不是变量的值不变。
  7. const的暂时性死区:代码块内如果存在let或者const声明,则代码块会对这些声明的变量从代码块开始就形成了一个封闭的作用域,在代码块内,声明变量之前使用会报错
var PI = "a";
    if (true) {
      console.log(PI); // ReferenceError:无法在初始化之前访问“PI”
      const PI = "3.1415926";
    }
-----------------------------
var str = "Hi!";
    if (true) {
      console.log(str); // ReferenceError:无法在初始化之前访问“str”
      let str = "Hello World!";
    }

二、解构赋值

  1. 解构源:表达式右边
  2. 解构目标:表达式左边
  3. 解构目标=解构源
  4. 数组解构:
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]
  1. 字符串解构:
let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'
  1. 解构默认值: let [a = 2] = [undefined]; // a = 2 当匹配结果未undefined时才会触发返回默认值
  2. 对象解构:

基本

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;
  1. 其实解构赋值就是一次性按照一定的赋值方式把右边对应值赋值到左边。配合...展开运算符更香。

三、Symbol

  1. 原始数据类型Symbol表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
let sy = Symbol("KK");
console.log(sy);   // Symbol(KK)
typeof(sy);        // "symbol"
 
// 相同参数 Symbol() 返回的值不相等
let sy1 = Symbol("kk"); 
sy === sy1;       // false
  1. 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"}
  1. Symbol作为对象属性名时不能使用.运算符,因为.运算符后的是字符串,需要使用[]取值
  2. Symbol的值作为属性名时是公有属性,不会出现在for..in、for..of中,也不会被Object.keys()、Object.getOwnPropertyNames()返回。可以通过Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
  3. 同字符串定义的常量会冲突,用Symbol定义的不会
  4. 用单例模式定义的Symbol和用Symbol.for()定义的Symbol不同值。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.for()定义,如果有对应字符串的Symbol就返回,没有就新建。在Symbol.for()定义的时候会把对应字符串的Symbol登记在全局环境中,给之后搜索用。

  1. Symbol.keyFor()返回的是已经登记的key。类似JSON转换一样,可以这么理解:Symbol.for(字符串),把字符串转换成一个唯一标识,字符串是密钥,Symbol.for(字符串)返回的是密文,同一个密钥对应的密文相同,Symbol.keyFor(密文)返回的是密钥。

四、Map与Set

Map

  1. 用new Map()实例化一个map对象
  2. map.set(键,值)设置对象的键与值,与Object不同,这里Map的键可以是任何类型,这就是Map对象最大的亮点
  3. map.get(键)获取对应的值
  4. NaN作为键时,获取到的值是相同的(虽然NaN!==NaN,但是这里作为键是相等的)
  5. 可用for..of 和 forEach遍历
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);
}
--------------------------
// 将会显示两个 logs。 一个是 "0 = zero" 另一个是 "1 = one"
myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
  1. Map与Array互转
var kvArray = [["key1", "value1"], ["key2", "value2"]];
 
// Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象
var myMap = new Map(kvArray);
 
// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组
var outArray = Array.from(myMap);
  1. Map克隆新对象
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);
var myMap2 = new Map(myMap1);
 
console.log(myMap1 === myMap2); 
// 打印 false。 Map 对象构造函数生成实例,迭代出新的对象。
  1. 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

  1. Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
  2. 几个特殊相同情况:
    • +0与-0相同
    • undefined与undefined相同
    • NaN与NaN不相等,但是在Set中只能存一个
  3. set对象只存值
  4. new Set()实例化set对象
  5. set.add(值)添加值
  6. set.has(值)判断值是否存在
  7. array=[...set]可用...将set转成数组

五、字符串

  1. includes()判断是否找到参数字符串
  2. startsWith()判断参数字符串是否在原字符串的头部。
  3. endsWith()判断参数字符串是否在原字符串的尾部。
  4. 以上都可接收第二参数,即起始搜索位置,都返回boolean,不可传入正则表达式
let string = "apple,banana,orange";
string.includes("banana");     // true
string.startsWith("apple");    // true
string.endsWith("apple");      // false
string.startsWith("banana",6)  // true
  1. repeat()重复字符串指定次数并返回
  2. padStart()、padEnd()返回新的字符串,表示用参数字符串从头部/尾部补全字符串,第一参数为返回字符串的最小长度,第二参数为用来补全的字符串,默认用空格。常用于补全位数。
console.log("h".padStart(5,"o"));  // "ooooh"
console.log("h".padEnd(5,"o"));    // "hoooo"
console.log("h".padStart(5));      // "    h"
  1. 模板字符串`,可定义多行字符串保留空格和换行,也可在字符串中添加变量用${变量}表示
function f(){
  return "have fun!";
}
let string2= `Game start,${f()}`;
console.log(string2);  // Game start,have fun!
  1. 标签模板
alert`Hello world!`;
// 等价于
alert('Hello world!');

六、对象

  1. ES6允许对象的属性直接写变量,这时候属性名是变量名,属性值是变量值。
const person = {age, name};
//等同于
const person = {age: age, name: name}
  1. 方法也可简写
const person = {
  sayHi(){
    console.log("Hi");
  }
}
//等同于
const person = {
  sayHi:function(){
    console.log("Hi");
  }
}
  1. 属性名可以是表达式,但是需用[]包含,属性和属性名简写不可同时使用
const obj = {
 ["he"+"llo"](){
   return "Hi";
  }
}
  1. 对象的扩展运算符...
let person = {name: "Amy", age: 15};
let someone = { ...person };
someone;  //{name: "Amy", age: 15}
--------------------------
//合并对象
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person;  //{age: 15, name: "Amy"}

对象新方法

  1. Object.assign(目标对象,源对象...)用于将源对象的所有可枚举属性复制到目标对象中。属于浅拷贝。
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);  
// 第一个参数是目标对象,后面的参数是源对象
target;  // {a: 1, b: 2, c: 3}
-----------------
//非对象,先转为对象后返回
Object.assign(3);         // Number {3}
typeof Object.assign(3);  // "object"
  1. Object.is(值1,值2)比较2个值是否严格相等(与===类似)
  2. 与===的区别
//一是+0不等于-0
Object.is(+0,-0);  //false
+0 === -0  //true
//二是NaN等于本身
Object.is(NaN,NaN); //true
NaN === NaN  //false

七、数组

  1. Array.of()将参数中所有值作为原始形成数组console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
  2. Array.from()将类数组对象或可迭代对象转化为数组。参数Array.from(arrayLike[,mapFn[,thisArg]])
console.log(Array.from([1, , 3])); // [1, undefined, 3]
------------------------
console.log(Array.from([1, 2, 3], (n) => n * 2)); // [2, 4, 6]
------------------------
//thisArg用于指定map函数执行时的 this 对象。
let map = {
    do: function(n) {
        return n * 2;
    }
}
let arrayLike = [1, 2, 3];
console.log(Array.from(arrayLike, function (n){
    return this.do(n);
}, map)); // [2, 4, 6]

转换类数组必须含有length属性,也可用转换map、set、字符串

  1. find()查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素。
let arr = Array.of(1, 2, 3, 4);
console.log(arr.find(item => item > 2)); // 3
  1. findIndex()查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引。
let arr = Array.of(1, 2, 1, 3);
// 参数1:回调函数
// 参数2(可选):指定回调函数中的 this 值
console.log(arr.findIndex(item => item = 1)); // 0
  1. fill()将一定范围索引的数组元素内容填充为单个指定的值。
let arr = Array.of(1, 2, 3, 4);
// 参数1:用来填充的值
// 参数2:被填充的起始索引
// 参数3(可选):被填充的结束索引,默认为数组末尾
console.log(arr.fill(0,1,2)); // [1, 0, 3, 4]
  1. copyWithin()将一定范围索引的数组元素修改为此数组另一指定范围索引的元素。
// 参数1:被修改的起始索引
// 参数2:被用来覆盖的数据的起始索引
// 参数3(可选):被用来覆盖的数据的结束索引,默认为数组末尾
console.log([1, 2, 3, 4].copyWithin(0,2,4)); // [3, 4, 3, 4]
  1. entries()遍历键值对,keys()遍历键名,values()遍历键值
for(let [key, value] of ['a', 'b'].entries()){
    console.log(key, value);
}
// 0 "a"
// 1 "b"
 
// 不使用 for... of 循环
let entries = ['a', 'b'].entries();
console.log(entries.next().value); // [0, "a"]
console.log(entries.next().value); // [1, "b"]
---------------------------
for(let key of ['a', 'b'].keys()){
    console.log(key);
}
// 0
// 1
---------------------------
for(let value of ['a', 'b'].values()){
    console.log(value);
}
// "a"
// "b"
  1. includes()查找数组是否包含值
// 参数1:包含的指定值
[1, 2, 3].includes(1);    // true
 
// 参数2:可选,搜索的起始索引,默认为0
[1, 2, 3].includes(1, 2); // false
  1. flat()嵌套数组转为一维数组,flatMap()先对每个元素处理再执行flat()
console.log([1 ,[2, 3]].flat()); // [1, 2, 3]
 
// 指定转换的嵌套层数
console.log([1, [2, [3, [4, 5]]]].flat(2)); // [1, 2, 3, [4, 5]]
 
// 不管嵌套多少层
console.log([1, [2, [3, [4, 5]]]].flat(Infinity)); // [1, 2, 3, 4, 5]
 
// 自动跳过空位
console.log([1, [2, , 3]].flat());<p> // [1, 2, 3]
-------------------------------
// 参数1:遍历函数,该遍历函数可接受3个参数:当前元素、当前元素索引、原数组
// 参数2:指定遍历函数中 this 的指向
console.log([1, 2, 3].flatMap(n => [n * 2])); // [2, 4, 6]
参考自RUNOOB