编程技术文章分享与教程

网站首页 > 技术文章 正文

Javascript ES6新引入的类型Symbol详解以及示例

hmc789 2024-11-26 03:40:50 技术文章 2 ℃

ES6引入的新的原始数据类型Symbol,表示独一无二的值,它是js中的第7种数据类型,是一种类似于字符串的数据类型。

Symbol特点:

1、Symbol的值是唯一的,用来解决命名冲突的问题。

2、Symbol值不能与其他数据进行运算。

3、Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。然后遍历。

如何创建?

可以使用函数创建。

let s = Symbol('demo');

或者

let s1 = Symbol.for('demo');

使用for函数可以得到某个字符串唯一的symbol值,例如下面的比较是相等的。

let s2 = Symbol.for('demo');

s1 === s2 返回的就是true。

Symbol内置的值

用做对象的属性。通过对这些内置值的设置,来改变对象在某些特定场景下的表现。

最常用的有:

  • Symbol.hasInstance

在使用instanceof操作符时调用。

class Person{

  static [Symbol.hasInstance](param){

  console.log(param);

  console.log('我被用来检查类型了')

  return false;

  }

}

let obj = {}

console.log(obj instanceof Person)
  • Symbol.isConcatSpreadable

使用concat来合并两个数组的时候,js会默认将数组内的元素展开然后合并为一个数组返回(原数组不变),这个行为es6以后可以使用Symbol.isConcatSpreadable改变,将其置为false就可以将数组作为一整个对象合并到过去。

let animals = ['cat','dog','panda']

let fruit = ['apple','pear']

fruit[Symbol.isConcatSpreadable] = true

console.log(animals.concat(fruit)) // 结果是['cat','dog','panda','apple','pear']

fruit[Symbol.isConcatSpreadable] = false

console.log(animals.concat(fruit)) // 结果是['cat','dog','panda', Array(2)]
  • Symbol.iterator

用于给对象定义迭代方法,这样就可以使用es6中新提供的for...of语法,需要注意的是,自定义的这个迭代器方法,需要按照一定的规范来写,需要返回一个具有next方法的对象,next方法需要返回具有value和done两个属性的对象。done会被用来判断什么时候结束迭代。

const banji = {

name: "终极一班",

stus: [ 'xiaoming', 'xiaoning', 'xiaotian', 'knight' ],

[Symbol.iterator]() {

// 索引变量

let index = 0;

// 保存this

let _this = this;

return {

next: function() {

if (index < _this.stus.length) {

const result = { value: _this.stus[index], done: false };

// 下标自增

index++;

// 返回结果

return result;

} else {

return { value: undefined, done: true };

}

}

};

}

}

// 遍历这个对象

for (let v of banji) {

console.log(v);

}
  • Symbol.match

一个在调用 String.prototype.match() 方法时调用的方法, 直白点说就是如果你定义一个字符串strValue,当你调用strValue.match(ObjectCase),如果ObjectCase这个对象定义了Symbol.match方法时,就会执行这个方法。

let animal = {

  [Symbol.match](str){

    console.log(str) //打印出字符串 cat

    return str.indexOf('animal');

  }

}

let kitty = "cat"

console.log(kitty.match(animal)) //返回值-1,这里打印出-1


  • Symbol.replace

一个在调用 String.prototype.replace() 方法时调用的方法,和上面的一样,当一个字符串调用strValue.replace(ObjectCase)时,会去执行ObjectCase中的Symbol.replace方法。

let animalName = {

  /* strValue 会返回调用者本身,replacement为调用repalce方法时传入的第二个参数 */

  [Symbol.replace](strValue, replacement){

    console.log("strValue: " + strValue,"replacement: " + replacement) //strValue: cat, its name is {params} replacement: {params}

    return strValue.replace("{params}", "kitty")

  }

}

let kitty = "cat, its name is {params}"

console.log(kitty.replace(animalName, "{params}")) //cat, its name is kitty
  • Symbol.search

一个在调用 String.prototype.search() 方法时调用的方法,用于在字符串中定位子串,这个也和上面str相关扩展一样直接看示例。

let animalName = {

/* strValue就是调用者本身 */

  [Symbol.search](strValue){

    console.log(strValue) //cat, its name is kitty

    return strValue.split("name is")[1]

  }

}

let kitty = "cat, its name is kitty"

console.log(kitty.search(animalName)) //kitty
  • Symbol.split

一个在调用 String.prototype.split() 方法时调用的方法,用于分割字符串。

let animalName = {

  /* strValue就是调用者本身 */

  [Symbol.split](strValue){

    console.log(strValue) //cat, its name is kitty

    return strValue.indexOf("name")

  }

}

let kitty = "cat, its name is kitty"

console.log(kitty.split(animalName)) //8
  • Symbol.toPrimitive

这个方法决定了当一个对象被转换为原始值时的行为。JavaScript引擎在每个类型值的原型上定义了Symbol.toPrimitive方法。这个方法被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式:

number: 该场景下需要转换成数值.对应操作符:* / -

string: 该场景下需要转换成字符串,显示使用string的构造方法

default:该场景下可以转换成数值,也可以转换成字符串,对应操作符:+

let obj = {

  [Symbol.toPrimitive](hint){

    switch(hint){

    case 'number':

    	return 123;

    case 'string':

    	return 'str';

    case 'default':

    	return 'default';

    default:

    	throw new Error();

    }

  }

}

console.log(2 * obj) //246

console.log(3 + obj) //3default

console.log(obj == 'default') //true

console.log(String(obj)) //str
  • Symbol.species

对象的Symbol.species属性,指向一个构造函数,创建衍生对象时,会使用该属性。这个的主要用途是,有些类库是在基类的基础上修改的,那么子类使用继承的方法时,作者可能希望返回基类的实例,而不是子类的实例。

class MyArray extends Array {

  static get [Symbol.species](){

    return Array;

  }

}

//b,c是a的衍生对象

const a = new MyArray(1,2,3)

const b = a.map(x => x+1)

const c = a.filter(x => x > 0)

//如果没有定义上面的Symbol.species,那么下面的instanceof均返回true

console.log(b instanceof MyArray) //true

console.log(c instanceof MyArray) //true

//定义了上面的Symbol.species时,返回值是下面这样

console.log(b instanceof MyArray) //false

console.log(b instanceof Array) //true
  • Symbol.toStringTag

一个在调用 String.prototype.toString() 方法时使用的字符串,用于创建对象描述。在对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串中,表示对象的类型。

//第一种写法,注意这里的get关键字是必须的,call方法需要用到get取值器

let animal = {

  get [Symbol.toStringTag](){

    return 'animal'

  }

}

console.log(Object.prototype.toString.call(animal)) // [object animal]

//第二种写法

console.log({[Symbol.toStringTag]: 'tag'}.toString()) // [object tag]
  • Symbol.unscopables

一个定义了一些不可被 with 语句引用的对象属性名称的对象集合。集合中的属性名称,会在with环境绑定中被排除。

const animal = {

  type: 'animal',

  name: 'kitty'

}

with(animal){

  console.log(type, name) //animal kitty

}

//定义Symbol.unscopables以便在with环境中排除某些属性

animal[Symbol.unscopables] = {

  type: true

}

with(animal){

  console.log(type) //Uncaught ReferenceError: type is not defined

}

以上这些被称为众所周知的symbols,其实其中很多值并不常用,为了验证这些symbols的准确用法,我搜了很多资料,总算把每一个都亲自验证了一遍。

这里附上一个地址,这里面有特别详细的示例代码,我也是自己费了半天劲儿快验证完的时候才发现这个网址的,白白浪费了好多时间。

大家百度搜索一下关键字Symbol MDN ,可以看到有mozilla的一个开发者网站,这上面也有可以参考的示例。

另外,之所以要研究这个,主要是最近在学vue3 + typescript,身为一个没太多基础的前端小白,学习的过程中遇到一个知识点可能都会要查半天资料才能弄懂,不过我也乐在其中。

Tags:

标签列表
最新留言