深入理解ES6 006【学习笔记】

Symbol和Symbol属性

6种原始数据类型:Symbol。私有名称原本是为了让开发者们创建非字符串属性名称而设计的,但是一般的技术无法检测这些属性的私有名称

创建Symbol

let firstName = Symbol();
let person = {}
person[firstName] = "Nicholas";
console.log(person[firstName]); // Nicholas 

new Symbol() 会报错,Symbol函数接受一个可选参数,其可以让你添加一段文本描述即将创建的Symbol,这段描述不可用于属性访问,但是建议你在每次创建Symbol时都添加一段描述,以便于阅读代码和调试Symbol程序

let firstName = Symbol('first name');
let person = {}
person[firstName] = "Nicholas"
console.log("first name" in person); // false
console.log(person[firstName]); //Nicholas
console.log(firstName) // "Symbol(first name)"

Symbol的描述被存储在内部的[[Description]]属性中,只有当调用Symbol的toString()方法才可以读取这个属性,在执行console.log时,隐式调用了firstName的toString()方法,所以它的描述会被打印到日志中,但是不能直接在代码里访问[[Description]]

使用typeof symbol 如果是会返回'symbol',所有使用计算属性名的地方,都可以使用Symbol。

Symbol的使用方法

我们之前都是在括号中使用Symbol,事实上,Symbol也可以用于可计算对象字面量属性、Object.defineProperty()方法和Object.defineProperties()方法的调用过程

let fristName = Symbol("first name");
// 使用一个可计算对象这字面量属性
let person = {
  [firstName]:"Nicholas"
}
// 将属性设置为只读
Object.defineProperty(person,firstName,{writable:false})

let lastName = Symbol('last name');

Object.defineProperties(person,{
  [lastName]:{
    value:"Zakas",
    writable:false
  }
})
console.log(person[firstName]) //Nicholas
console.log(person[lastName]) //Zakas

虽然在所有使用可计算属性名的地方,都可以使用Symbol来替代,但是为了在不同的代码片段间有效地共享这些Symbol,需要建立一个体系

Symbol共享体系

例如我们想在不同的对象类型,想使用同一个Symbol属性来表示一个独特的标识符。在很大的代码库或跨文件追踪Symbol非常困难且容易出错,出于这些原因ES6提供了一个可以随时访问全局Symbol注册表。使用Symbol.for(xxx) 只接受一个参数。要创建Symbol的字符串描述类似Symbol('xxx')Symbol.for(xxx)会去全局注册表中找有没有注册这个Symbol,有就返回,没有就创建一个并注册到全局表中,下次不用再新建一个了。

Symbol与类型转换

我上面的示例使用console.log()方法来输出Symbol的内容,它会调用Symbol的String()方法输出有用信息,如果你试图将一个Symbol和一个字符串拼接,会导致程序抛出错误。

let uid = Symbol.for("uid"),
desc = String(uid);
console.log(desc); // Symbol(uid)

Symbol的属性检索

Object.keys()Object.getOwnPropertyNames()方法可以检索对象中所有的属性名,后一个方法不考虑属性的可枚举性一律返回。这两个方法都支持Symbol属性。所以又推出了一个Object.getOwnPropertySymbols()方法返回一个包含所有Symbole自有属性的值。

let uid = Symbol.for("uid");
let object = {
  [uid]:"12345"
}
let symbols = Object.getOwnPropertySymbols(object);
console.log(symbols.length) // 1
console.log(symbols[0]) // "Symbol(uid)"
console.log(object[symbols[0]]) //12345

通过well-know Symbol暴露内部操作

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.match
  • Symbol.replace
  • Symbol.species
  • Symbol.split
  • Symbol.species
  • Symbol.toPrimitive
  • Symbol.toStringTag
  • Symbol.unscopables
obj instanceof Array;
// 等价于
Array[Symbol.hasInstance](obj)
// 本质上,es6只是将instanceof操作符重新定义为此方法的简写语法,现在引入调用后,就可以随意改变instanceof的运行方式了。
// 假设你想定义一个无实例的函数,就可以将Symbol.hasInstance的返回值硬编码为false
function MyObject(){
  // 空函数
}
Object.defindProperty(MyObject,Symbol.hasInstance,{
  value:function(v){
    return false
  }
})
let obj = new MyObject()
console.log(obj instanceof MyObject) // false

Symbol.isConcatSpreadable

js数组的concat方法被设计用于拼接两个数组,使用如下方法:

let color1 =["red","green"],
color2 = color1.concat(["blue","black"])
console.log(color2.length) // 4
console.log(color2) // ["red","green","blue","black"]

// color1与一个临时数组拼接成两个数组
// concat方法也可以接受非数组参数,此时该方法只会将这些参数逐一添加到数组末尾如下
let color1 =["red","green"],
color2 = color1.concat(["blue","black"],"brown")
console.log(color2.length) // 5
console.log(color2) // ["red","green","blue","black","brown"]
// 这个属性可以设置或阻止调用concat方法时是否展开

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4332

(0)
Walker的头像Walker
上一篇 2025年3月8日 12:51
下一篇 2025年3月8日 12:51

相关推荐

  • 深入理解ES6 003【学习笔记】

    函数 参数默认值,以及一些关于arguments对象,如何使用表达式作为参数、参数的临时死区。 以前设置默认值总是利用在含有逻辑或操作符的表达式中,前一个值是false时,总是返回后面一个的值,但如果我们给参数传0时,就有些麻烦。需要去验证一下类型 function makeRequest(url,timeout,callback){ timeout = t…

    个人 2025年3月8日
    79400
  • 深入理解ES6 013【学习笔记】

    用模块封装代码 javascript用“共享一切”的方法加载代码,这是该语言中最容易出错且另人感到困惑的地方。其他语言使用诸如包这样的概念来定义代码作用域。在es6以前,在应用程序的每一个js中定义的一切都共享一个全局作用域。随着web应用程序变得更加复杂,js代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。es6的一个目标是解决作用域问题…

    个人 2025年3月8日
    75200
  • 深入理解ES6 011【学习笔记】

    Promise与异步编程 因为执行引擎是单线程的,所以需要跟踪即将运行的代码,那些代码被放在一个任务队列中,每当一段代码准备执行时,都会被添加到任务队列中,每当引擎中的一段代码结束执行,事件循环会执行队列中的一下个任务。 Promise相当于异步操作结果占位符,它不会去订阅一个事件,也不会传递一个回调函数给目标函数,而是让函数返回一个Promise,就像这样…

    个人 2025年3月8日
    72000
  • TS珠峰 003【学习笔记】

    装饰器 // 装饰器 // 只能在类中使用(类本身,类成员使用) // 装饰器,类的装饰器,属性装饰器,访问装饰器 参数装饰器 // 1. 类型装饰器 给类进行扩展,也可以返回一个子类 // 先要在tsconfig.json中开启experimentalDecorators const classDecorator1 = <T extends new …

    个人 2025年3月27日
    87300
  • 深入理解ES6 012【学习笔记】

    代理(Proxy)和反射(Reflection)API 代理是一种可以拦截并改变底层javascript引擎操作的包装器,在新语言中通过它暴露内部运作对象,从而让开发者可以创建内建的对象。 代理陷阱 覆写的特性 默认特性 get 读取一个属性值 Reflect.get() set 写入一个属性值 Reflect.set() has in操作符 Reflect…

    个人 2025年3月8日
    74000

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹