JavaScript原始数据类型Symbol的用法详解

目录
  • Symbol介绍与创建
  • 设置Symbol属性的注意点
  • Symbol属性名的遍历
  • Symbol内置值
    • Symbol.hasInstance
    • Symbol.isConcatSpreadable
    • Symbol.unscopables
    • Symbol.match
    • Symbol.replace
    • Symbol.search
    • Symbol.split
    • Symbol.iterator
    • Symbol.toPrimitive
    • Symbol.toStringTag
    • Symbol.species

Symbol介绍与创建

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值,它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。

Symbol特点:

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

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

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

Symbol值通过Symbol()函数生成,也就是说,对象的属性名可以有两种类型,一种就是原来就有的字符串,另一种就是新增的Symbol类型。

创建Symbol有俩种方式,Symbol和Symbol.for(),这两种方式的区别前者不能登记在全局环境中供搜索,后者却可以,所有Symbol.for()不会每次调用就返回一个新的Symbol类型值,而是先检查给定的key值是否存在,不存在才会新建一个值。

<script>
    // 创建Symbol
    let s = Symbol()
    console.log(s,typeof s);//Symbol() 'symbol'
    //Symbol()函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
    //Symbol()函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
    let s1 = Symbol('张三')
    let s2 = Symbol('张三')
    console.log(s1 === s2);//false
    // 创建Symbol的另一种方法:Symbol.for() 该方法创建的字符串参数相等,Symbol也相等
    let s3 = Symbol.for('张三')
    let s4 = Symbol.for('张三')
    // Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key。
    console.log(Symbol.keyFor(s3));//张三
    console.log(s3 === s4);//true
</script>

Symbol 值不能与其他类型的值进行运算,否则会报错,但是Symbol值可以显示转换为字符串,而且Symbol也可以转为布尔值。

<script>
    let s = Symbol('My Symbol')
    // let result = s + 100
    // console.log(result);//Cannot convert a Symbol value to a number
    // 转字符串
    console.log(String(s));//Symbol(My Symbol)
    // 转布尔值
    console.log(Boolean(s));//true
</script>

当然如果你想直接返回 Symbol 的字符串参数的值的话,可以借用 Symbol 的实例属性:description,直接返回 Symbol 值的描述。

<script>
    let s = Symbol('My Symbol')
    console.log(s.description);//My Symbol
</script>

针对数据类型的类别可以总结以下方式:(面试官问你JS有哪几种数据类型好用到)

USONB (you are so niubility)

u:undefined

s:string、Symbol

o:object

n:null、number

b:boolean

设置Symbol属性的注意点

为了保证不会出现同名的属性,防止对象的某一个键不小心被改写或覆盖。使用作为属性名的Symbol 进行操作。设置Symbol的方式如下:

注意:我们在进行设置Symbol值作为对象属性名时,是不能用点运算符,因为点运算符后面总是字符串,所以不会读取作为Symbol标识名所指代的那个值,导致Symbol的属性名实际上是一个字符串,而不是一个Symbol值,所以在对象内部使用Symbol值定义属性时,Symbol值必须放在方括号里面。

<script>
    let s = Symbol('My Symbol')
    // 第一种
    let a = {}
    a[s] = 'hello world'
    // 第二种
    let b = {
        [s]:'hello people'
    }
    // 第三种
    let c = {}
    Object.defineProperty(c,s,{value:'hello animal'})
    // 以上结果都能达到相同的效果,举例
    console.log(c);
</script>

Symbol属性名的遍历

如果想遍历Symbol的属性名,正常的方法是办不到的,需要使用特定的方法,有一个方法可以获取指定对象的所有键名并返回一个数组,方法为:Object.getOwnPropertySymbols()方法。

<script>
    let obj = {}
    let a = Symbol('a')
    let b = Symbol('b')
    obj[a] = 'hello'
    obj[b] = 'world'
    const objectSymbols = Object.getOwnPropertySymbols(obj)
    console.log(objectSymbols);//[Symbol(a), Symbol(b)]
</script>

上面的方法能够返回Symbol的键名,还有一个方法能够返回Symbol键名,但不只有Symbol键名而是所有的键名都被返回出来。该方法为:Reflect.ownKeys(obj)。

<script>
    let obj = {
        name:'张三',
        age:18,
        [Symbol('mySymbol')]:1,
        gender:'男'
    }
    console.log(Reflect.ownKeys(obj));//['name', 'age', 'gender', Symbol(mySymbol)]
</script>

Symbol内置值

除了定义自己使用的 Symbol 值以外,ES6还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。方法如下:

Symbol.hasInstance

当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法。

<script>
    class Person {
        static [Symbol.hasInstance](param){
            console.log(param);
            console.log('我被用来检测类型了');
            //return true
        }
    }
    let o = {}
    console.log(o instanceof Person);
</script>

当出现 instanceof 时,symbol 的 hasInstance 属性就会被触发,并且可以把要判断的实例对象传进来。也就是说将 instanceof 前面的值传递到 param 形参这个方法,由它来决定返回的true还是false。说白了就是可以自己控制类型检测。

Symbol.isConcatSpreadable

对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于数组上面时Array.prototype.concat()语句,判断数组是否可以展开。false为不展开。

<script>
    const arr = [1,2,3]
    const arr1 = [4,5,6]
    console.log(arr.concat(arr1));
    // 将arr1设置为不展开,作为一个整体与arr进行合并
    arr1[Symbol.isConcatSpreadable] = false
    console.log(arr.concat(arr1));
</script>

类似数组的对象正好相反,默认不展开,它的 Symbol.isConcatSpreadable 属性设为 true,才能展开。

<script>
    let obj = {
        0:'a',
        1:'b',
        2:'c',
        length:3
    }
    console.log([1,2].concat(obj,'d'));
    // 将该属性设置为true,进行展开
    obj[Symbol.isConcatSpreadable] = true
    console.log([1,2].concat(obj,'d'));
</script>

Symbol.unscopables

该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除。

<script>
    // 将排除的键名以数组方式打印出来
    console.log(Object.keys(Array.prototype[Symbol.unscopables]));
</script>

// 没有 unscopables 时
class MyClass {
  foo() { return 1; }
}
var foo = function () { return 2; };

with (MyClass.prototype) {
  foo(); // 1
}
// 有 unscopables 时
// 通过指定Symbol.unscopables属性,使得with语法块不会在当前作用域寻找foo属性,即foo将指向外层作用域的变量
class MyClass {
  foo() { return 1; }
  get [Symbol.unscopables]() {
    return { foo: true };
  }
}
var foo = function () { return 2; };
with (MyClass.prototype) {
  foo(); // 2
}

Symbol.match

JavaScript中的Symbol.match属性是well-known符号,用于标识正则表达式与字符串的匹配,当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。

<script>
    const reg = /hello world/
    reg[Symbol.match] = false
    console.log('/hello/'.startsWith(reg));//false
    console.log('/hello world/'.startsWith(reg));//true
</script>

Symbol.replace

当该对象被 str.replace(myObject) 方法调用时,会返回该方法的返回值。

<script>
    const x = {};
    // Symbol.replace方法会收到两个参数,第一个参数是replace方法正在作用的对象,第二个参数是替换后的值。
    x[Symbol.replace] = (...s) => console.log(s); // ["Hello", "World"]
    'Hello'.replace(x, 'World')
</script>

Symbol.search

指定了一个搜索方法,这个方法接受用户输入的正则表达式,返回该正则表达式在字符串中匹配到的下标,这个方法由以下的方法来调用 String.prototype.search()。该属性指向一个方法,当该对象被 str.search(myObject)方法调用时,会返回该方法的返回值。

<script>
    class caseInsensitiveSearch {
    constructor(value) {
        this.value = value.toLowerCase();
    }
    [Symbol.search](string) {
        return string.toLowerCase().indexOf(this.value);
    }
    }
    console.log('foobar'.search(new caseInsensitiveSearch('BaR')));
    // expected output: 3
</script>

Symbol.split

Symbol.split 这个属性方法 指向的是一个正则表达式的索引处分割字符串的方法,这个方法通过 String.prototype.split() 调用;该属性指向一个方法,当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值。

<script>
    var exp =  {
        pat:'in',
        [Symbol.split](str) {
        return str.split(this.pat);
        }
    }
    // "dayinlove".split(exp)调用[Symbol.split](str)处理,并把实参"dayinlove"传给形参str
    console.log("dayinlove".split(exp));//["day", "love"]
</script>

Symbol.iterator

对象进行 for...of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器。

<script>
    const myIterable = {};
    myIterable[Symbol.iterator] = function* () { //function*这种声明方式会定义一个生成器函数,它返回一个对象。
        yield 1;
        yield 2;
        yield 3;
    };
    console.log([...myIterable]);// [1, 2, 3]
</script>

Symbol.toPrimitive

作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。该函数被调用时,会传递一个字符粗参数 hint ,表示要转换到的原始值的预期类型。hint参数的取值是:number、string 和 default 中的任意一个。

// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果
var obj1 = {};
console.log(+obj1);     // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
var obj2 = {
  [Symbol.toPrimitive](hint) {
    if (hint == "number") {
      return 10;
    }
    if (hint == "string") {
      return "hello";
    }
    return true;
  }
};
console.log(+obj2);     // 10      -- hint 参数值是 "number"
console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"
console.log(obj2 + ""); // "true"  -- hint 参数值是 "default"

Symbol.toStringTag

通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签。

<script>
    class Person {
        get [Symbol.toStringTag](){
            return 'xxx'
        }
    }
    let per = new Person()
    console.log(Object.prototype.toString.call(per));//[object xxx]
</script>

Symbol.species

指定构造函数用于创建派生对象的函数值属性,即创建衍生对象时,会使用该属性。作用:实例对象在运行过程中,会调用该属性指定的构造函数,用来返回基类的实例而不是子类的实例。

<script>
    class Array1 extends Array {
        static get [Symbol.species]() { return Array; }
    }
    const a = new Array1(1, 2, 3);
    const mapped = a.map(x => x * x);
    // 定义了Symbol.species属性后,导致 a.map(x => x * x) 生成的衍生对象不在是Array1的实例而是Array
    console.log(mapped instanceof Array1);//false
    console.log(mapped instanceof Array);//true
</script>

到此这篇关于JavaScript原始数据类型Symbol的用法详解的文章就介绍到这了,更多相关JS Symbol内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入了解JavaScript中的Symbol的使用方法

    Symbol 是什么? Symbols 不是图标,也不是指在代码中可以使用小图片: 也不是指代其他一些东西的语法.那么,Symbol 到究竟是什么呢? 七种数据类型 JavaScript 在 1997 年被标准化时,就有 6 种数据类型,直到 ES6 出现之前,程序中的变量一定是以下 6 种数据类型之一: Undefined     Null     Boolean     Number     String     Object 每种数据类型都是一系列值的组合,前面 5 种数据类型值的数量都是

  • JavaScript第七种数据类型Symbol的用法详解

    目录 一.什么是Symbol 二.作为属性名的Symbol 三.Symbol中的方法 1.Symbol.for() 2.Symbol.keyFor() 一.什么是Symbol Symbol是ES6中引入的一种新的基本数据类型,用于表示一个独一无二的值.它是JavaScript中的第七种数据类型,与undefined.null.Number(数值).String(字符串).Boolean(布尔值).Object(对象)并列. Symbol特点: Symbol的值是唯一的,用来解决命名冲突问题 Sy

  • 详解JavaScript的Symbol类型、隐藏属性、全局注册表

    目录 Symbol类型的使用 Symbol简介 Symbol类型的描述 Symbol不会隐式转字符串 Symbol类似作为对象的属性键 创建Symbol键 for…in中被跳过 隐藏自定义属性 Symbol全局注册表 系统Symbol 总结 Symbol类型的使用 在前文<JavaScript的8种数据类型>中,我们已经简单的介绍过了JavaScript的Symbol类型,下面对其使用方法和使用场景做一个简单的介绍. Symbol简介 Symbol类型是JavaScript中的一种特殊的类型,

  • 详解JavaScript 为什么要有 Symbol 类型?

    Symbols 是 ES6 引入了一个新的数据类型 ,它为 JS 带来了一些好处,尤其是对象属性时. 但是,它们能为我们做些字符串不能做的事情呢? 在深入探讨 Symbol 之前,让我们先看看一些 JavaScript 特性,许多开发人员可能不知道这些特性. 背景 js 中的数据类型总体来说分为两种,他们分别是:值类型 和 引用类型 值类型(基本类型):数值型(Number),字符类型(String),布尔值型(Boolean),null 和 underfined 引用类型(类):函数,对象,数

  • 你知道JavaScript Symbol类型怎么用吗

    Symbol 类型 根据规范,对象的属性键只能是字符串类型或者 Symbol 类型.不是 Number,也不是 Boolean,只有字符串或 Symbol 这两种类型. 到目前为止,我们只见过字符串.现在我们来看看 Symbol 能给我们带来什么好处. Symbol "Symbol" 值表示唯一的标识符. 可以使用 Symbol() 来创建这种类型的值: // id 是 symbol 的一个实例化对象 let id = Symbol(); 创建时,我们可以给 Symbol 一个描述(也

  • 详解JavaScript原始数据类型Symbol

    简介 创建symbol变量最简单的方法是用Symbol()函数.sysmbol变量有两点比较特别: 1.它可以作为对象属性名.只有字符串和 symbol 类型才能用作对象属性名. 2.没有两个symbol 的值是相等的. const symbol1 = Symbol(); const symbol2 = Symbol(); symbol1 === symbol2; // false const obj = {}; obj[symbol1] = 'Hello'; obj[symbol2] = 'W

  • Javascript ES6中数据类型Symbol的使用详解

    介绍 Symbol 是一种特殊的.不可变的数据类型,可以作为对象属性的标识符使用,表示独一无二的值.Symbol 对象是一个 symbol primitive data type 的隐式对象包装器. 它是JavaScript语言的第七种数据类型,前6种分别是:Undefined.Null.Boolean.String.Number.Object. 语法 Symbol([description]) Parameters description : 可选的字符串.可用于调试但不访问符号本身的符号的说

  • Javascript Symbol原理及使用方法解析

    Symbol是ES6中新引入的一种基本数据类型,在此之前JavaScript中已有几种基本数据类型: Numberg String Boolean Null Undefined Object 不同于其他基本类型的通俗易懂,Symbol 是什么和有什么用一直有些让人困惑. 什么是Symbol JavaScript标准中规定对象的key只能是 String 或 Symbol 类型,区别在于 String 类型的key可以重复而 Symbol 类型的key是唯一的.Symbol 的本质是表示一个唯一标

  • JavaScript原始数据类型Symbol的用法详解

    目录 Symbol介绍与创建 设置Symbol属性的注意点 Symbol属性名的遍历 Symbol内置值 Symbol.hasInstance Symbol.isConcatSpreadable Symbol.unscopables Symbol.match Symbol.replace Symbol.search Symbol.split Symbol.iterator Symbol.toPrimitive Symbol.toStringTag Symbol.species Symbol介绍与

  • JavaScript中的splice方法用法详解

    JavaScript中的splice主要用来对js中的数组进行操作,包括删除,添加,替换等. 注意:这种方法会改变原始数组!. 1.删除-用于删除元素,两个参数,第一个参数(要删除第一项的位置),第二个参数(要删除的项数) 2.插入-向数组指定位置插入任意项元素.三个参数,第一个参数(插入位置),第二个参数(0),第三个参数(插入的项) 3.替换-向数组指定位置插入任意项元素,同时删除任意数量的项,三个参数.第一个参数(起始位置),第二个参数(删除的项数),第三个参数(插入任意数量的项) 示例:

  • JavaScript中window和document用法详解

    一.验证表单 封装一个函数用于验证手机号 /** * @param {String}eleId * @param {Object}reg */ function checkInput(eleId,reg) { var ele = document.getElementById(eleId); ele.onblur = function (ev) { if(!reg.test(this.value)){ //不匹配 this.style.borderColor = "#ff0000" /

  • JavaScript模板引擎原理与用法详解

    本文实例讲述了JavaScript模板引擎原理与用法.分享给大家供大家参考,具体如下: 一.前言 什么是模板引擎,说的简单点,就是一个字符串中有几个变量待定.比如: var tpl = 'Hei, my name is <%name%>, and I\'m <%age%> years old.'; 通过模板引擎函数把数据塞进去, var data = { "name": "Barret Lee", "age": "

  • javascript中instanceof运算符的用法详解

    概述 instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上 语法 obj instanceof Object;//true 实例obj在不在Object构造函数中 描述 instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上. 实例 1.instanceof的普通的用法,obj instanceof Object 检测Object.prototype是否存在于参数

  • JavaScript在XHTML中的用法详解

    编写XHTML代码的规则要比编写HTML要严格得多,类似下面的代码在HTML中是有效的,但在XHTML中则是无效的. [javascript] 复制代码 代码如下: <script type="text/javascript"> function compare(a, b) { if(a < b) { alert("a is less then b"); } else if(a > b) { alert("a is greater

  • JavaScript中document.referrer的用法详解

    前言 在JavaScript中,document对象有很多属性,其中有3个与对网页的请求有关的属性,它们分别是URL.domain和referrer. URL属性包含页面完整的URL,domain属性中只包含页面的域名,而referrer属性中则保存着链接到当前页面的那个页面的URL. 前面两个很好理解,而referrer属性简单来说就是上一个页面的URL.那么这个属性具体有什么用处呢? 在H5页面中,我们经常要在头部加个返回上一个页面按钮,就像下面这样的: 页面头部 点击左侧的元素可以返回到上

随机推荐