ES6 基础
简单的特性

符号(Symbol)
Symbol 解决了对象属性命名冲突的问题,通过 Symbol 创建的数据是互不相等的(即使参数一样,也不会相等)
注意的点:
- Symbol 没有字面量
- 使用 Symbol 做属性,则该属性不可被枚举(for...in、Object.keys、Object.getOwnPropertyNames),可以通过 Object.getOwnPropertySymbols 读取符号属性
- Symbol 不能被隐式转换(数字、字符串拼接等),但可以显示转换为字符串(String(Symbol("111")))
共享符号
通过 Symbol.for(符号描述)创建,只要 符号描述 相等,则生成的符号也互等
// 读取符号属性
const obj = {
a: 1,
b: 2,
[Symbol.for("c")]: 3
}
console.log(obj[Symbol.for("c")]); // 3
知名符号
概念: 是一种特殊的共享符号,知名符号可以暴露 js 对象的一些内部实现方法,通过自定义这些暴露的方法就可以改写 js 的默认实现逻辑
常见的知名符号 有以下几种
- Symbol.hasInstance: 该符号用于定义构造函数的静态成员,它将影响 instanceof 的判定
- Symbol.isConcatSpreadable: 该知名符号会影响数组的 concat 方法
- Symbol.toPrimitive: 该知名符号会影响类型转换的结果
- Symbol.toStringTag: 该知名符号会影响 Object.prototype.toString 的返回值([object Xxxx])
一些例子
// ----------------- Symbol.species 为构造函数创建派生对象,从当前对象新派生对象的构造函数可以通过 Symbol.species 改变
class MyArray extends Array {
// static [Symbol.species] = Array;
// 等同于上面效果
static get [Symbol.species]() {
return Array;
}
}
const array = new MyArray();
array.push(1);
array.push(2);
console.log(array instanceof Array); // true
console.log(array instanceof MyArray); // true
// 从 array 派生一个 mapArray 数组,mapArray 的构造函数是 Symbol.species 的返回值
const mapArray = array.map((item) => item);
console.log(mapArray instanceof Array); // true
console.log(mapArray instanceof MyArray); // false
// --------------------- Symbol.split 自定义字符串的 split 方法 -------------
const exp = {
pat: "in",
[Symbol.split](str) {
return str.split(this.pat);
},
};
console.log("1dqwinqwdwq".split(exp));
// --------------------- Symbol.asyncIterator 自定义对象的异步迭代器 -------------
const myAsyncIterable = new Object();
// 异步迭代器 Symbol.asyncIterator
myAsyncIterable[Symbol.asyncIterator] = async function*() {
yield "hello";
yield "async";
yield "iteration!";
};
(async () => {
for await (const x of myAsyncIterable) {
// console.log(x);
// expected output:
// "hello"
// "async"
// "iteration!"
}
})();
// ---------------------- Symbol.toPrimitive 自定义对象转换规则 ----------
const obj = {
a: 1,
b: 2,
[Symbol.toPrimitive](hint) {
// hint obj 通过运算符要转换的目标类型,来定制返回的原始值
// default 默认的转换方式
if (hint === "number") {
return 4;
} else if (hint === "string") {
return "string";
}
return 1;
},
};
console.log(+obj, "" + obj);
// -------------------------- Symbol.hasInstance,自定义 instanceof 判断规则 ------
const arr = [1, 2, 3];
arr[Symbol.hasInstance] = function(instance) {
console.log("wef2f", instance);
// return "svs";
return false; // 若返回值不是布尔类型会被转为 boolean 类型
};
console.log([] instanceof arr); // wef2f [] false
// ------------------------- Symbol.isConcatSpreadable 自定义数组被 concat 拼接时是否可以展开 ------
const arrConcat = [1, 2, 3];
arrConcat[Symbol.isConcatSpreadable] = true; // true-可展开,不可展开
console.log([4, 5, 6, ...arrConcat]); // [ 4, 5, 6, 1, 2, 3 ]
console.log([4, 5, 6].concat(arrConcat)); // [ 4, 5, 6, [1, 2, 3]]
// ---------------------- Symbol.replace 自定义 String.prototype.replace 匹配规则 -------
class Replace {
constructor(value) {
this.value = value;
}
[Symbol.replace](string) {
return `${string}--${this.value}`;
}
}
const str = String("123");
console.log(str.replace(new Replace("456")));
// ---------------------- Symbol.toStringTag 自定义 Object.prototype.string 返回的类型标签 -------
class Persion {
constructor(value) {
this.value = value;
}
[Symbol.toStringTag] = "Persion"; // 默认值是 Object
}
const persion = new Persion("123");
console.log(Object.prototype.toString.call(persion)); // [object Persion]
// ------------------------ Symbol.match 标识对象是否有正则表达式的行为 --------------------------------
const regexp1 = /foo/;
regexp1[Symbol.match] = false;
console.log("/foo/".startsWith(regexp1)); // true
console.log("/baz/".endsWith(regexp1)); // false