记录-Symbol学习笔记
Posted 林恒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录-Symbol学习笔记相关的知识,希望对你有一定的参考价值。
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
Symbol是JavaScript中的原始数据类型之一,它表示一个唯一的、不可变的值,通常用作对象属性的键值。由于Symbol值是唯一的,因此可以防止对象属性被意外地覆盖或修改。以下是Symbol的方法和属性整理:
属性
Symbol.length
Symbol构造函数的length属性值为0。
示例代码:
console.log(Symbol.length); // 0
方法
Symbol.for()
Symbol.for()方法会根据给定的字符串key,返回一个已经存在的symbol值。如果不存在,则会创建一个新的Symbol值并将其注册到全局Symbol注册表中。
示例代码:
const symbol1 = Symbol.for(\'foo\'); const symbol2 = Symbol.for(\'foo\'); console.log(symbol1 === symbol2); // true
使用场景: 当我们需要使用一个全局唯一的Symbol值时,可以使用Symbol.for()方法来获取或创建该值。例如,在多个模块之间共享某个Symbol值时,我们可以使用Symbol.for()来确保获取到的Symbol值是唯一的。
Symbol.keyFor()
Symbol.keyFor()方法会返回一个已经存在的Symbol值的key。如果给定的Symbol值不存在于全局Symbol注册表中,则返回undefined。
示例代码:
const symbol1 = Symbol.for(\'foo\'); const key1 = Symbol.keyFor(symbol1); const symbol2 = Symbol(\'bar\'); const key2 = Symbol.keyFor(symbol2); console.log(key1); // \'foo\' console.log(key2); // undefined
使用场景: 当我们需要获取一个全局唯一的Symbol值的key时,可以使用Symbol.keyFor()方法。但需要注意的是,只有在该Symbol值被注册到全局Symbol注册表中时,才能使用Symbol.keyFor()方法获取到其key。
Symbol()
Symbol()函数会返回一个新的、唯一的Symbol值。可以使用可选参数description来为Symbol值添加一个描述信息。
示例代码:
const symbol1 = Symbol(\'foo\'); const symbol2 = Symbol(\'foo\'); console.log(symbol1 === symbol2); // false
使用场景: 当我们需要使用一个唯一的Symbol值时,可以使用Symbol()函数来创建该值。通常情况下,我们会将Symbol值用作对象属性的键值,以确保该属性不会被意外地覆盖或修改。
Symbol.prototype.toString()
Symbol.prototype.toString()方法会返回Symbol值的字符串表示形式,该表示形式包含Symbol()函数创建时指定的描述信息。
示例代码:
const symbol = Symbol(\'foo\'); console.log(symbol.toString()); // \'Symbol(foo)\'
使用场景: 当我们需要将一个Symbol值转换成字符串时,可以使用Symbol.prototype.toString()方法。
Symbol.prototype.valueOf()
Symbol.prototype.valueOf()方法会返回Symbol值本身。
示例代码:
const symbol = Symbol(\'foo\'); console.log(symbol.valueOf()); // Symbol(foo)
使用场景: 当我们需要获取一个Symbol值本身时,可以使用Symbol.prototype.valueOf()方法。
Symbol.iterator
Symbol.iterator是一个预定义好的Symbol值,表示对象的默认迭代器方法。该方法返回一个迭代器对象,可以用于遍历该对象的所有可遍历属性。
示例代码:
const obj = a: 1, b: 2 ; for (const key of Object.keys(obj)) console.log(key); // Output: // \'a\' // \'b\' for (const key of Object.getOwnPropertyNames(obj)) console.log(key); // Output: // \'a\' // \'b\' for (const key of Object.getOwnPropertySymbols(obj)) console.log(key); // Output: // No output obj[Symbol.iterator] = function* () for (const key of Object.keys(this)) yield key; for (const key of obj) console.log(key); // Output: // \'a\' // \'b\'
使用场景: 当我们需要自定义一个对象的迭代行为时,可以通过定义Symbol.iterator属性来实现。例如,对于自定义的数据结构,我们可以定义它的Symbol.iterator方法以便能够使用for...of语句进行遍历。
Symbol.hasInstance
Symbol.hasInstance是一个预定义好的Symbol值,用于定义对象的 instanceof 操作符行为。当一个对象的原型链中存在Symbol.hasInstance方法时,该对象可以被instanceof运算符使用。
示例代码:
class Foo static [Symbol.hasInstance](obj) return obj instanceof Array; console.log([] instanceof Foo); // true console.log( instanceof Foo); // false
使用场景: 当我们需要自定义一个对象的 instanceof 行为时,可以通过定义Symbol.hasInstance方法来实现。
Symbol.isConcatSpreadable
Symbol.isConcatSpreadable是一个预定义好的Symbol值,用于定义对象在使用concat()方法时的展开行为。如果一个对象的Symbol.isConcatSpreadable属性为false,则在调用concat()方法时,该对象不会被展开。
示例代码:
const arr1 = [1, 2]; const arr2 = [3, 4]; const obj = length: 2, 0: 5, 1: 6, [Symbol.isConcatSpreadable]: false ; console.log(arr1.concat(arr2)); // [1, 2, 3, 4] console.log(arr1.concat(obj)); // [1, 2, length: 2, 0: 5, 1: 6, [Symbol(Symbol.isConcatSpreadable)]: false ]
使用场景: 当我们需要自定义一个对象在使用concat()方法时的展开行为时,可以通过定义Symbol.isConcatSpreadable属性来实现。
Symbol.toPrimitive
Symbol.toPrimitive是一个预定义好的Symbol值,用于定义对象在被强制类型转换时的行为。如果一个对象定义了Symbol.toPrimitive方法,则在将该对象转换为原始值时,会调用该方法。
示例代码:
const obj = valueOf() return 1; , [Symbol.toPrimitive](hint) if (hint === \'number\') return 2; else if (hint === \'string\') return \'foo\'; else return \'default\'; ; console.log(+obj); // 2 console.log(`$obj`); // \'foo\' console.log(obj + \'\'); // \'default\'
使用场景: 当我们需要自定义一个对象在被强制类型转换时的行为时,可以通过定义Symbol.toPrimitive方法来实现。
Symbol.toStringTag
Symbol.toStringTag是一个预定义好的Symbol值,用于定义对象在调用Object.prototype.toString()方法时返回的字符串。如果一个对象定义了Symbol.toStringTag属性,则在调用该对象的toString()方法时,会返回该属性对应的字符串。
示例代码:
class Foo get [Symbol.toStringTag]() return \'Bar\'; console.log(Object.prototype.toString.call(new Foo())); // \'[object Bar]\'
使用场景: 当我们需要自定义一个对象在调用Object.prototype.toString()方法时返回的字符串时,可以通过定义Symbol.toStringTag属性来实现。
Symbol.species
Symbol.species是一个预定义好的Symbol值,用于定义派生对象的构造函数。如果一个对象定义了Symbol.species属性,则在调用该对象的派生方法(如Array.prototype.map())时,返回的新对象会使用该属性指定的构造函数。
示例代码:
class MyArray extends Array static get [Symbol.species]() return Array; const myArr = new MyArray(1, 2, 3); const arr = myArr.map(x => x * 2); console.log(arr instanceof MyArray); // false console.log(arr instanceof Array); // true
使用场景: 当我们需要自定义一个派生对象的构造函数时,可以通过定义Symbol.species属性来实现。
Symbol.match
Symbol.match是一个预定义好的Symbol值,用于定义对象在调用String.prototype.match()方法时的行为。如果一个对象定义了Symbol.match方法,则在调用该对象的match()方法时,会调用该方法进行匹配。
示例代码:
class Foo [Symbol.match](str) return str.indexOf(\'foo\') !== -1; console.log(\'foobar\'.match(new Foo())); // true console.log(\'barbaz\'.match(new Foo())); // false
使用场景: 当我们需要自定义一个对象在调用String.prototype.match()方法时的行为时,可以通过定义Symbol.match方法来实现。
Symbol.replace
Symbol.replace是一个预定义好的Symbol值,用于定义对象在调用String.prototype.replace()方法时的行为。如果一个对象定义了Symbol.replace方法,则在调用该对象的replace()方法时,会调用该方法进行替换。
示例代码:
class Foo [Symbol.replace](str, replacement) return str.replace(\'foo\', replacement); console.log(\'foobar\'.replace(new Foo(), \'baz\')); // \'bazbar\' console.log(\'barbaz\'.replace(new Foo(), \'baz\')); // \'barbaz\'
使用场景: 当我们需要自定义一个对象在调用String.prototype.replace()方法时的行为时,可以通过定义Symbol.replace方法来实现。
Symbol.search
Symbol.search是一个预定义好的Symbol值,用于定义对象在调用String.prototype.search()方法时的行为。如果一个对象定义了Symbol.search
class Foo [Symbol.search](str) return str.indexOf(\'foo\'); console.log(\'foobar\'.search(new Foo())); // 0 console.log(\'barbaz\'.search(new Foo())); // -1
使用场景: 当我们需要自定义一个对象在调用String.prototype.search()方法时的行为时,可以通过定义Symbol.search方法来实现。
Symbol.split
Symbol.split是一个预定义好的Symbol值,用于定义对象在调用String.prototype.split()方法时的行为。如果一个对象定义了Symbol.split方法,则在调用该对象的split()方法时,会调用该方法进行分割。
示例代码:
class Foo [Symbol.split](str) return str.split(\' \'); console.log(\'foo bar baz\'.split(new Foo())); // [\'foo\', \'bar\', \'baz\'] console.log(\'foobarbaz\'.split(new Foo())); // [\'foobarbaz\']
使用场景: 当我们需要自定义一个对象在调用String.prototype.split()方法时的行为时,可以通过定义Symbol.split方法来实现。
Symbol.iterator
Symbol.iterator是一个预定义好的Symbol值,用于定义对象在被遍历时的行为。如果一个对象定义了Symbol.iterator方法,则可以使用for...of循环、扩展运算符等方式来遍历该对象。
示例代码:
class Foo constructor() this.items = [\'foo\', \'bar\', \'baz\']; *[Symbol.iterator]() for (const item of this.items) yield item; const foo = new Foo(); for (const item of foo) console.log(item); // \'foo\' // \'bar\' // \'baz\'
使用场景: 当我们需要自定义一个对象在被遍历时的行为时,可以通过定义Symbol.iterator方法来实现。比如,我们可以通过实现Symbol.iterator方法来支持自定义数据结构的遍历。
Symbol.toPrimitive
Symbol.toPrimitive是一个预定义好的Symbol值,用于定义对象在被强制类型转换时的行为。如果一个对象定义了Symbol.toPrimitive方法,则可以通过调用该方法来进行强制类型转换。
示例代码:
const obj = valueOf() return 1; , [Symbol.toPrimitive](hint) if (hint === \'default\') return \'default\'; else if (hint === \'number\') return 2; else return \'foo\'; ; console.log(+obj); // 2 console.log(`$obj`); // \'foo\' console.log(obj + \'\'); // \'default\'
使用场景: 当我们需要自定义一个对象在被强制类型转换时的行为时,可以通过定义Symbol.toPrimitive方法来实现。
Symbol.toStringTag
Symbol.toStringTag是一个预定义好的Symbol值,用于定义对象在调用Object.prototype.toString()方法时返回的字符串。如果一个对象定义了Symbol.toStringTag属性,则在调用该对象的toString()方法时,会返回该属性对应的字符串。
示例代码:
class Foo get [Symbol.toStringTag]() return \'Bar\'; console.log(Object.prototype.toString.call(new Foo())); // \'[object Bar]\'
使用场景: 当我们需要自定义一个对象在调用Object.prototype.toString()方法时返回的字符串时,可以通过定义Symbol.toStringTag属性来实现。这样做有助于我们更清晰地表示对象的类型。
Symbol.unscopables
Symbol.unscopables是一个预定义好的Symbol值,用于定义对象在使用with语句时的行为。如果一个对象定义了Symbol.unscopables属性,则在使用with语句时,该对象的指定属性将不会被绑定到with语句的环境中。
示例代码:
const obj = a: 1, b: 2, c: 3, [Symbol.unscopables]: c: true ; with (obj) console.log(a); // 1 console.log(b); // 2 console.log(c); // ReferenceError: c is not defined
使用场景: 由于with语句会带来一些安全性问题和性能问题,因此在实际开发中不建议使用。但是,如果确实需要使用with语句,可以通过定义Symbol.unscopables属性来避免某些属性被误绑定到with语句的环境中。
Symbol.hasInstance
Symbol.hasInstance是一个预定义好的Symbol值,用于定义对象在调用instanceof运算符时的行为。如果一个对象定义了Symbol.hasInstance方法,则在调用该对象的instanceof运算符时,会调用该方法来判断目标对象是否为该对象的实例。
示例代码:
class Foo static [Symbol.hasInstance](obj) return Array.isArray(obj); console.log([] instanceof Foo); // true console.log( instanceof Foo); // false
使用场景: 当我们需要自定义一个对象在调用instanceof运算符时的行为时,可以通过定义Symbol.hasInstance方法来实现。比如,我们可以通过实现Symbol.hasInstance方法来支持自定义数据类型的判断。
总结
Symbol是ES6中新增的一种基本数据类型,用于表示独一无二的值。Symbol值在语言层面上解决了属性名冲突的问题,可以作为对象的属性名使用,并且不会被意外覆盖。除此之外,Symbol还具有以下特点:
- Symbol值是唯一的,每个Symbol值都是独一无二的,即使是通过相同的描述字符串创建的Symbol值,也不会相等;
- Symbol值可以作为对象的属性名使用,并且不会被意外覆盖;
- Symbol值可以作为私有属性来使用,因为无法通过对象外部访问对象中的Symbol属性;
- Symbol值可以被用作常量,因为它们是唯一的;
- Symbol值可以用于定义迭代器、类型转换规则、私有属性、元编程等高级功能。
在使用Symbol时需要注意以下几点:
- Symbol值不能使用new运算符创建;
- Symbol值可以通过描述字符串来创建,但是描述字符串并不是Symbol值的唯一标识符;
- Symbol属性在使用时需要用[]来访问,不能使用.运算符;
- 同一对象中的多个Symbol属性是独立的,它们之间不会互相影响。
总之,Symbol是一个非常有用的数据类型,在JavaScript中具有非常广泛的应用。使用Symbol可以有效地避免属性名冲突问题,并且可以为对象提供一些高级功能。熟练掌握Symbol,有助于我们写出更加健壮、高效和可维护的JavaScript代码。
本文转载于:
https://juejin.cn/post/7226193000496463928
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
JavaScript学习笔记
数据类型
1. 数据类型
ECMAScript 有 6 种简单数据类型(也称为原始类型): Undefined、 Null、Boolean、 Number、String 和 Symbol。
还有一种复杂数据类型叫 Object (一种无序名值对的集合)。
在 ECMAScript 中不能定义自己的数据类型,所有值都可以用上述 7 种数据类型之一来表示。
使用 typeof 操作符可以用来确定变量的数据类型。
2. Undefined 类型
Undefined 类型只有一个值,就是特殊值 undefined。
当使用 var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了 undefined 值
3. Null 类型
Null 类型只有一个值,就是特殊值 null。
给 typeof 传一个 null 会返回 object ,因为 null 被认为是一个对空对象的引用。
它的作用
在定义将来要保存对象值的变量时,建议使用 null 来初始化。
这样,只要检查这个变量的值是不是 null 就可以知道这个变量是否在后来被重新赋予了一个对象的引用.
4. Boolean 类型
Boolean 类型有两个字面值: true 和 false。
布尔值字面量 true 和 false 是区分大小写的,因此 True 和 False(及其他大小混写形式)是有效的标识符,但不是布尔值。
这两个布尔值不同于数值,因此 true 不等于 1, false 不等于 0。
要将一个其他类型的值转换为布尔值,可以调用特定的 Boolean() 转型函数:
不同类型与布尔值之间的转换规则:
数据类型 | 转换为 true 的值 | 转换为 false 的值 |
---|---|---|
Boolean | ture | false |
String 类型 | 非空字符串 | ”“(空字符串) |
Number | 非零数值(包括无穷值) | 0,NaN |
Object | 任意对象 | null |
Undefined | N/A(不存在) | undefined |
5. Number 类型
整数
// 十进制
let intNum = 10;
// 八进制,前缀 0o
let octalNum = 0o70; // 十进制是 56
// 十进制,前缀 0x(区分大小写) 十六进制数字(0~9 以及 A~F)。
let hexNum = 0xA; // 十进制下是 10
使用八进制和十六进制格式创建的数值在所有数学操作中都被视为十进制数值。
浮点数
要定义浮点数,数值中必须包含小数点,而且小数点后面必须至少有一个数字。
小数点前面可以没有整数,但推荐加上。
let floatNum1 = 0.1
// 科学计数法表示
// (一个数值(整数/浮点数)后跟一个大写/小写的字母e,再加上一个要乘的10的多少次幂)
let floatNum2 = 3.125e7 // 31250000
值的范围
在多数浏览器中:
- 最小值:Number.MIN_VALUE ,值为 5e-32
- 最大值:Number.MAX_VALUE ,值为 1.797 693 134 862 315 7e+308。
如果某个计算得到的数值结果超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为无穷值。
- 正无穷大:Infinity
- 负无穷大:-Infinity
要确定一个值是不是有限大,可以使用isFinite() 函数。
NAN
有一个特殊的数值叫 NaN,意思是“不是数值”( Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。
(用 0 除任意数值在其他语言中通常都会导致错误,从而中止代码执行。
但在 ECMAScript 中,0、+0 或 -0 相除会返回 NaN)
几个独特的属性:
- 任何涉及 NaN 的操作始终返回 NaN
- NaN 不等于包括 NaN 在内的任何值。
console.log(NaN == NaN); // false
我们可以用 isNaN() 函数来判断是否是 NaN。
数值转换
将非数值转换为数值:Number() 、 parseInt() 和 parseFloat() 。
(Number() 是转型函数,可用于任何数据类型。后两个函数主要用于将字符串转换为数值。)
Number() 空字符串返回0,paresInt() 返回 NaN。
parseInt() 可以接收第二个参数,用于指定底数(进制数)。
不传底数参数相当于让 parseInt() 自己决定如何解析,所以为避免解析出错,建议始终传给它第二个参数。
例如:
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
parseFloat() 只解析十进制值,因此不能指定底数。
如果字符串表示整数(没有小数点或者小数点后面只有一个零),则 parseFloat() 返回整数。
6. String 类型
String(字符串)数据类型表示零或多个 16 位 Unicode 字符序列。
ECMAScript 中的字符串是不可变的( immutable),意思是一旦创建,它们的值就不能变了。
要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量。
字符串可以使用双引号( ")、单引号( ')或反引号( `)标示.
(以某种引号作为字符串开头,必须仍然以该种引号作为字符串结尾)
字符串的长度可以通过其 length 属性获取。
(如果字符串中包含双字节字符,那么 length 属性返回的值可能不是准确的字符数。)
let text = "This is a sentence.";
console.log(text.length); // 19
字符串转义符
转义符 | 描述 |
---|---|
\\n | 换行符 |
\\\\ | 斜杆 \\ |
\\' | 单引号 |
\\" | 双引号 |
\\t | tab 缩进 |
\\b | 空格 |
这些字符字面量可以出现在字符串中的任意位置,且可以作为单个字符被解释。
转换为字符串
- toString()
toString() 方法可见于数值、布尔值、对象和字符串值。
null 和 undefined 值没有 toString() 方法。
let age = 11;
let ageAsString = age.toString(); // 字符串 "11"
let found = true;
let foundAsString = found.toString(); // 字符串 "true"
多数情况下, toString() 不接收任何参数。在对数值调用这个方法时, toString() 可以接收一个底数参数,即以什么底数来输出数值的字符串表示。
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
- String()
如果你不确定一个值是不是 null 或 undefined,可以使用 String() 转型函数。
String() 函数遵循如下规则:
- 如果值有 toString() 方法,则调用该方法(不传参数)并返回结果。
- 如果值是 null,返回"null" 。
- 如果值是 undefined,返回"undefined" 。
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
模板字面量
模板字面量会保持反引号内部的空格,可以保留换行符。
let thirdTemplateLiteral = `first line
second line`;
console.log(thirdTemplateLiteral);
/*
输出结果:
first line
second line
*/
7. Symbol 类型
Symbol(符号)是 ECMAScript 6 新增的数据类型。
符号是原始值,且符号实例是唯一、不可变的。
符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
符号需要使用 Symbol() 函数初始化。
let genericSymbol = Symbol();
console.log(genericSymbol); // Symbol()
let fooSymbol = Symbol('foo');
console.log(fooSymbol); // Symbol(foo);
8. Object 类型
ECMAScript 中的对象其实就是一组数据和功能的集合。
对象通过 new 操作符后跟对象类型的名称来创建。
let obj = new Object();
因为在 ECMAScript 中 Object 是所有对象的基类,所以任何对象都有 Object 属性和方法。
Object 实例有如下属性和方法:
- constructor:用于创建当前对象的函数。
(在前面的代码中,这个属性的值就是 Object()函数) - hasOwnProperty(propertyName) :用于判断当前对象实例(不是原型)上是否存在给定的属性。
(要检查的属性名必须是字符串,如 o.hasOwnProperty(“name”) 或 符号) - isPrototypeOf(object) :用于判断当前对象是否为另一个对象的原型。
- propertyIsEnumerable( propertyName) :用于判断给定的属性是否可以使用 for-in 语句枚举。
(与 hasOwnProperty() 一样,属性名必须是字符串) - toLocaleString() :返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
- toString() :返回对象的字符串表示。
- valueOf() :返回对象对应的字符串、数值或布尔值表示。通常与 toString() 的返回值相同。
以上是关于记录-Symbol学习笔记的主要内容,如果未能解决你的问题,请参考以下文章