内置symbol
symbol内置属性通常用来改变对象的默认行为。由于浏览器的支持问题,可以把代码拷贝到Vue或者React框架内查看效果。
symbol.iterator
当使用for in时会调用该遍历器,举例:
class DefaultArray extends Array{
constructor(...args){
super(...args);
}
*[Symbol.iterator](){//对象的Symbol.iterator属性,指向该对象的默认遍历器方法
let i = 0;console.log("call iterator");
while (this[i] != undefined) {
yield this[i];
++i;
}
}
}
let arr=new DefaultArray(1,2,3);
for(let i of arr){
console.log(i);
}
//类似于generator函数
function *Iterator(arr){
for(let i=0;i<arr.length;i++){
yield arr[i];
}
return true;
}
let myarr=Iterator([5,4,3,2,1]);
console.log(myarr.next());
for(let j of myarr){
console.log(j);
}
//打印
//{value: 5, done: false}
// 4
//3
//2
//1
symbol.asyncIterator
当使用for await…of时会调用该遍历器,举例:
class DefaultArray extends Array{
constructor(...args){
let arr=super(...args);
this.realValue=arr;
}
makeAsyncName(str){//构造一个类似异步请求的方法
console.log("call asyncIterator:"+str);
return new Promise((rs,rj)=>{
setTimeout(()=>{rs(str)},5000);
});
}
*[Symbol.asyncIterator](){//定义异步遍历器
let i=0;
while (this[i] != undefined) {
yield this.makeAsyncName(this[i]);
++i;
}
}
}
let arr=new DefaultArray(1,2,3);
async function run() {
for await (const value of arr) {
console.log("async::"+value);
}
}
run();
//首先显示call asyncIterator:1
//五秒后显示下面两个,意味着只有取到了先前结果,才去获取下一个以此类推
//async::1
//call asyncIterator:2
symbol.toPrimitive
当使用各种显示或隐式转换时会调用该方法,当有这个属性时将不会调用toString或valueOf方法转换。举例:
class DefaultArray extends Array{
constructor(...args){
let arr=super(...args);
this.realValue=arr;
}
[Symbol.toPrimitive](hint){
//对象的Symbol.toPrimitive属性,指向ToPrimitive。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始值类型值。
//Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式:
// Number:该场合需要转换为数值。
// String:该场合需要转成字符串。
// Default:该场合可以转成数值,也可以转成字符串。
console.log(hint);
switch(hint){
case "number" :
return NaN;
case "string" :
return "[DefaultArray Array]";
case "default" :
return "default";
default :
throw new Error();
}
}
toString(){
console.log("get string");
return "[DefaultArray Array]";
}
valueOf(){
console.log("get value");
return NaN;
}
}
let arr=new DefaultArray(1,2,3);
console.log(Number(arr));//NaN
console.log(String(arr));//[DefaultArray Array]
console.log(`${arr}::es6string`);//[DefaultArray Array]::es6string
console.log(Boolean(arr));//true 没有经过调用
console.log(+arr);//NaN
//当使用+转换类型时无法判断转化为数字还是字符
console.log(arr+"");//default
console.log(arr+1);//default
console.log(!arr);//false 没有经过调用
symbol.species
species 访问器属性允许子类覆盖对象的默认构造函数。当使用数组方法如map,concat等返回一个新的数组,我们可以通过这个属性设置这些派生的类。
class DefaultArray extends Array{
constructor(...args){
super(...args);
}
static get [Symbol.species](){
//A function valued property that is the constructor function that is used to create derived objects.
//对象的Symbol.species属性,指向一个构造函数。创建衍生对象时,会使用该属性。
return this;//默认this也就是本身的构造函数 可设置为如Array等构造函数
}
}
let arr=new DefaultArray(1,2,3);
let extendArr=arr.concat([4,5,6]);
console.log(extendArr);//指向的this,DefaultArray(6) [1, 2, 3, 4, 5, 6]
console.log([...extendArr]);//(6) [1, 2, 3, 4, 5, 6] 只有使用继承Array的方法才有效
symbol.unscopables
对象属性,在使用with绑定环境的时候排除自身和继承的属性名。
class DefaultArray extends Array{
constructor(...args){
let arr=super(...args);
this.realValue=arr;
}
get [Symbol.unscopables](){//使用width时从对象中排除
return {
realValue:true //排除此选项
}
}
}
let arr=new DefaultArray(1,2,3);
with(arr){
console.log(realValue);//Uncaught ReferenceError: realValue is not defined
}
symbol.hasInstance
这个方法决定了构造函数是否识别一个对象为它的实例。使用instanceof 操作符时调用。
class DefaultArray extends Array{
constructor(...args){
super(...args)
}
static [Symbol.hasInstance](RightParam){//对象的Symbol.hasInstance属性,指向内部方法,当其他对象使用instanceOf运算符,判断是否为该对象的实例时,会调用这个方法。
console.log(RightParam);
return true
//RightParam instanceof DefaultArray;
}
}
let arr=new DefaultArray(1,2,3);
console.log(arr instanceof DefaultArray);
Symbol.isConcatSpreadable
一个值,指定了Array.prototype.concat是否能展开数组
class DefaultArray extends Array{
constructor(...args){
super(...args);
}
get [Symbol.isConcatSpreadable](){//对象的Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
return false;
}
}
let arr=new DefaultArray(1,2,3);
let extendArr=arr.concat([4,5,6]);
console.log(extendArr);//DefaultArray(4) [DefaultArray(3), 4, 5, 6]
console.log([...arr,4,5,6]);//(6) [1, 2, 3, 4, 5, 6]
调用原型方法时会被调用的一些属性
- Symbol.toStringTag 一个属性,Object.prototype.toString会被调用。
class DefaultString extends String{
constructor(str){
super(str);
}
get [Symbol.toStringTag](){
console.log("call tagString");
return "DefaultString"
}
}
console.log(Object.prototype.toString.call(new DefaultString()));//[object DefaultString]
2.Symbol.split 通过String.prototype.split调用
class Split1{
[Symbol.split](str){
console.log("call split",str);
return str.split("");
}
}
console.log("888".split(new Split1()));//(3) ["8", "8", "8"]
3.Symbol.search 通过String.prototype.search调用
class Split1{
[Symbol.search](str){
console.log("call search",str);
return 0;
}
}
console.log("888".search(new Split1()));//0
4.Symbol.replace 通过String.prototype.replace调用
class Split1{
[Symbol.replace](str,rep){
console.log("call replace",str,rep);//call replace 888 sss
return "sss";
}
}
console.log("888".replace(new Split1(),"sss"));//sss
5.Symbol.replace 通过String.prototype.match调用
class Split1{
[Symbol.match](str){
console.log("call match",str);//call match 888
return "000";
}
}
console.log("888".match(new Split1()));//000
6.Symbol.matchAll通过String.prototype.matchAll调用
class Split1{
[Symbol.matchAll](regexp){
console.log("call matchAll",regexp);//call matchAll 888
return regexp.match(/[0-9]/g);
}
}
console.log("888".matchAll(new Split1()));//(3) ["8", "8", "8"]