1. 数据类型Symbol
// // 1. 创建Symbol
// let firstName = Symbol('first name');
// let person = {};
// person[firstName] = 'Matthew';
// console.log('person', person); // {Symbol(first name): "Matthew"}
// console.log(firstName in person); // true
// console.log('first name' in person); // false
// // 2. 识别Symbol
// console.log(typeof Symbol()); // symbol
// // 3. 使用Symbol
// let firstName = Symbol('first name');
// let person = {
// [firstName]: 'Matthew',
// };
// Object.defineProperty(person, firstName, { writable: false });
// let lastName = Symbol("last name");
// Object.defineProperties(person, {
// [lastName]: {
// value: 'Zoey',
// writable: false,
// }
// });
// console.log(person[firstName]);
// console.log(person[lastName]);
// // 4. Symbol全局共享 for()和keyFor()
// let guid = Symbol.for('guid'); // 全局Symbol中注册guid键,l类似于全局作用域
// let guid2 = Symbol.for('guid');
// let guid3 = Symbol('guid');
// console.log(guid === guid2); // true 类似于单例模式
// console.log(Symbol.keyFor(guid)); // guid 检索键
// console.log(Symbol.keyFor(guid3)); // undefined
// // 5. Symbol类型转换
// // Symbol没有与之等价的逻辑字符串或者数字,所以不可强制转换为字符串或者数字
// // Symbol等价布尔值为true
// // 6. 属性检索
// // 对象通过Object.keys()或者Object.getOwnPropertyNames()检索其属性名称
但是Symbol只能通过Object.getOwnPropertySymbols()来检索自有属性
// let guid = Symbol.for('guid');
// let obj = {
// [guid]: '123456789',
// };
// let symbols = Object.getOwnPropertySymbols(obj);
// console.log('keys', Object.keys(obj)); // [] 无法识别Symbol
// console.log('propertyNames', Object.getOwnPropertyNames(obj)); // [] 无法识别Symbkol
// // 7. well-known Symbol
// // 7.1 Symbol.hasInstance方法 控制有无实例
// let obj = { name: 'Matthew', age: 23 };
// obj instanceof Object // true 等价于下面的写法:
// Object[Symbol.hasInstance](obj); // true
// // 7.2 Symbol.isConcatSpreadable属性 改变concat数组的默认行为
// let collection = {
// 0: 'hello',
// 1: 'world',
// length: 2,
// [Symbol.isConcatSpreadable]: false,
// };
// let msg = ['Hi'].concat(collection);
// console.log(msg);
// // 7.3 Symbol.match, Symbol.replace, Symbol.search, Symbol.split
// // 等价于/^.{10}$/
// let hasLengthOf10 = {
// // 接受字符串参数,匹配成功返回匹配元素数组,否则返回null
// [Symbol.match]: (value) => value.length === 10 ? [value] : null,
// // 接受一个原始字符串和替换字符串参数,替换成功返回替换字符串,否则返回原始字符串
// [Symbol.replace]: (value, replacement) => value.length === 10 ? replacement : value,
// // 接受一个字符串参数,如果匹配到内容,则返回数字类型的索引位置,否则返回-1
// [Symbol.search]: (value) => value.length === 10 ? 0 : -1,
// // 接受一个字符串参数,根据匹配内容将字符串分解,并返回一个包含分解后片段的数组
// [Symbol.split]: (value) => value.length === 10 ? [,] : [value],
// };
// let msg1 = 'Hello World', msg2 = 'Hello John';
// let mch = msg1.match(hasLengthOf10), mch2 = msg2.match(hasLengthOf10);
// console.log(mch, mch2); // null ["Hello John"]
// let replace = msg1.replace(hasLengthOf10, 'Matthew'), replace2 = msg2.replace(hasLengthOf10, 'Matthew');
// console.log(replace, replace2); // Hello World Matthew
// let search = msg1.search(hasLengthOf10), search2 = msg2.search(hasLengthOf10);
// console.log(search, search2); // -1 0
// let split = msg1.split(hasLengthOf10), split2 = msg2.split(hasLengthOf10);
// console.log(split, split2); // ["Hello World"] [empty] // 注意[]和[,]不同
// // 总结:上述4个方法都是通过Symbol方法实现的,尽管这只是一个简单实例,但是它是的自定义模式匹配变得更加可行
// // ......
2. 数据类型Map和Set
// // 1. Set与Map出现原因
// var map = Object.create(null);
// map[5] = 'foo';
// console.log(map['5']); // foo
// // map[5]被自动转换为map['5'], 如果你想分别使用数字和字符串作为对象键名,则内部的自动转换会导致很多问题
// var set = Object.create(null), key1 = {}, key2 = {};
// set[key1] = 'foo';
// console.log(set[key2]); // foo
// // set[{}]被自动转换为set["[object Object]"],按理说key1和key2应该不同的
// var collection = Object.create(null);
// collection.sum = 1;
// // 本意是检测collection的键sum是否存在,时间上检测的是改制是否非0
// if (collection.sum) {
// // do something
// }
// // 总结:Map集合常用于获取已存在的信息,而Set常用于检查对象是否存在某个键名
// // 2. Set集合
// // 2.1 不会对存值进行强制转换(+0和-0会被认为是相同的),添加的多个对象之间保持独立
// let set = new Set(); // 构造函数还可以接收人以迭代对象
// set.add(1);
// set.add(2);
// set.add(1);
// console.log(set.size); // 2 自动去重
// set.add(+0);
// set.add(-0);
// set.add(0);
// console.log(set.size); // 3 +0和-0只会添加一个0
// set.add(NaN)
// set.add(NaN)
// console.log(set.size); // 4 尽管NaN !=== NaN, 但是在此处也只会添加一个
// set.add(undefined)
// set.add(null)
// console.log(set.size); // 6 null和undefined也可添加
// set.add({});
// set.add({});
// console.log(set.size); // 8 对象之间独立
// set.add(5);
// set.add('5');
// console.log(set.size); // 10 无强制转换
// // 2.2 检测是否存在某个值 has()
// // 2.3 移除元素 delete(), clear()
// // 2.3 遍历元素 forEach()
// // set.forEach((v, k, set) => console.log(k, v)); // k和v相同
// // 2.4 Set转数组Array [...new Set([1, 2, 3])]
// // 2.5 entries(), keys(), values()
// let entries = set.entries();
// let keys = set.keys();
// let values = set.values();
// console.log(entries, keys, values);
// 2.6 集合基本操作
let set = new Set([1, 2, 3, 4, 5, 6]);
let set2 = new Set([1, 7, 8, 9, 0, 6]);
// 2.6.1 求交集差集
// let intersection = new Set([...set].filter(x => set2.has(x)));
// let difference = new Set([...set].filter(x => !set2.has(x)));
// console.log(intersection, difference); // Set(2) {1, 6} Set(4) {2, 3, 4, 5}
// 2.6.2 集合基本操作
function isSuperSet(set, subSet) {
for (let ele of subSet) {
if (!set.has(ele)) {
return false;
}
}
return true;
}
function union(setA, setB) {
let _union = new Set(setA);
for (let ele of setB) {
_union.add(ele); // 检测到重复元素则忽略此次add操作
}
return _union;
}
function intersection(setA, setB) {
let _intersection = new Set();
for (let ele of setB) {
if (setA.has(ele)) {
_intersection.add(ele);
}
}
return _intersection;
}
function difference(setA, setB) {
let _difference = new Set(setA);
for (let elem of setB) {
_difference.delete(elem);
}
return _difference;
}
function symetricDifference(setA, setB) {
let _difference = new Set(setA);
for (let ele of setB) {
if (setA.has(ele)) {
_difference.delete(ele);
} else {
_difference.add(ele);
}
}
return _difference;
}
console.log(isSuperSet(set, set2));
console.log(intersection(set, set2));
console.log(union(set, set2));
console.log(difference(set, set2));
console.log(symetricDifference(set, set2));
// 2.6.3 String相关
console.log(new Set('China')); // Set(5) {"C", "h", "i", "n", "a"}
// // 3. WeakSet集合
// // 方法:仅支持add(),has()和delete()方法set.has()set.has()
// // 区别:WeakSet存储对象值的弱引用,不接受任何原始值
// let set = new WeakSet(), key = {};
// set.add(key);
// console.log(set.has(key)); // true
// key = null;
// console.log(set.has(key)); // false 弱引用被移除,而使用Set做不到这一点
// // 与Set区别:
// // 在WeakSet的add方法中传入费对象参数报错,向has和delete方法中传入飞对象参数返回false
// // WeakSet集合不可迭代,不能用于for-of循环
// // WeakSet集合不暴露任何迭代器
// // WeakSet不支持forEach()方法
// // WeakSet不支持size属性
// 使用场景:检测循环引用
// function execRecursively(func, obj, _refs = null) {
// if (!_refs) {
// _refs = new WeakSet();
// }
// // 避免无限递归
// if (_refs.has(obj)) {
// return;
// }
// debugger
// func(obj);
// if ('object' === typeof obj) {
// for (let key in obj) {
// execRecursively(func, obj[key], _refs);
// }
// }
// }
// const foo = {
// foo: 'Foo',
// bar: {
// bar: 'Bar',
// },
// };
// foo.bar.baz = foo;
// function print(o) {
// console.log(o);
// }
// execRecursively(print, foo);
// // 4. Map集合
// let map = new Map();
// map.set('name', 'Matthew');
// map.set('gender', 'female');
// console.log(map.has('name')); // true
// console.log(map.get('name')); // Matthew
// console.log(map.size); // 2
// for (let s of map) { console.log(s) } // ["name", "Matthew"] ["gender", "female"]
// map.forEach((v, k, map) => console.log(k, v));
// // 特殊的初始化
// let map2 = [['name', 'Nikholas'], ['gender', 'male']];
// // console.log(map instanceof Map); // true
// // console.log(map2 instanceof Map); // false
// // 4.1 键值对的集合,键的集合,值的集合 entries(), keys(), values()
// // 5. WeakMap集合
// // 存储键值对的无序列表,列表的键名是非null类型对象,键名对应的值可以是任何类型
// // 仅支持两个方法:has和delete方法
// // 5.1 私有对象数据
// // 6. 如何选择
// // 当只用对象做集合的键名时优先采用WeakMap, 如果要遍历元素则使用Map
// // WeakSet与Set的选择相同标准
3. ES6对字符串类型做了哪些升级优化?
优化:
- 模板字符串,可以保留空格和换行,优雅易读;
升级:
- 新增includes(),startsWith(), endsWith(),padStart(), padEnd(), repeat()等方法
4. ES6对数组类型做了哪些升级优化?
优化:
- 解构赋值,扩展运算符
升级:
- 新增find(), copyWithin(), includes(), fill()和flat()方法
5. ES6对数字类型做了哪些升级优化?
优化:
- 原型上新增isFinite(), isNaN()方法,有别于传统全局的isFinite(), isNaN()方法
升级:
- 新增Math.cbrt(),trunc()和hypot()等科学计算方法
6. ES6对对象类型做了哪些升级优化?
优化:
- 对象属性变量式声明
- 解构赋值
- 扩展运算符
- super关键字
升级:
- 新增is()方法解决NaN===NaN返回false得bug
- 新增assign()方法用于对象属性新增和合并
- 新增getOwnPropertyDescriptions()方法,可以获取指定对象所有自身属性的描述对象。结合defineProperties()方法,可以完美复制对象,包括复制get和set属性
- 新增getPropertyOf()和setPropertyOf()方法
- 新增Object.keys(),Object.values(),Object.entries()等方法、
7. ES6对函数类型做了哪些升级优化?
优化:
- 箭头函数
- 函数默认赋值
升级:
- 新增双冒号运算符,用以取代以往的bind,call和apply(浏览器在不支持,但是Babel以支持转码)
foo::bar;
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);