还记得我在Lodash专栏深拷贝部分提到的Symbol属性吗?它是ES6引入的一种新的原始数据类型,表示独一无二的值。你可以使用Symbol来创建对象的唯一属性键。我们往往希望创建私有属性,或者向第三方对象动态添加属性(防止属性名冲突)的时候,会使用Symbol。 另外,javascript中还提供了一些与定语的Symbol值,称为 Well-know Symbols,如Symbol.iterator
、Symbol.toStringTag
等。
以下是一个使用Symbol定义对象属性的例子:
javascript
let symbolKey = Symbol('key');
let obj = {};
obj[symbolKey] = 'value';
console.log(obj[symbolKey]); // 输出 'value'
在这个例子中,我们创建了一个symbolKey
作为obj
的属性键。你可以看到,这个属性的键是独一无二的,并且不会与obj
的其他属性产生冲突。我们称这样的属性为Symbol属性。
当我们说 "克隆对象的符号属性" 时,我们是指复制对象的所有 Symbol 类型的属性键及其对应的值。
Symbol 属性在前端工程中的使用场景
Symbol 类型的属性键在 JavaScript 中的使用并不是非常常见,但在某些特定的场景下,它们可以提供很大的帮助。以下是一些可能的使用场景:
-
创建私有属性 :在 JavaScript 中,对象的所有属性都是公开的,任何代码都可以访问和修改它们。然而,有时我们可能希望创建一些私有属性,只能通过对象的方法来访问和修改。Symbol 可以帮助我们实现这一点,因为 Symbol 类型的属性键不能被常规的遍历操作(如
for...in
循环、Object.keys
方法等)访问到。javascriptconst privateProperty = Symbol('privateProperty'); const createMyObject = () => { const obj = {}; obj[privateProperty] = 'This is private'; obj.getPrivateProperty = function() { return this[privateProperty]; }; return obj; } const instance = createMyObject(); console.log(instance.getPrivateProperty()); // 'This is private' console.log(Object.keys(instance)); // ['getPrivateProperty'],私有属性不会被遍历到
这里我们复习下 this 指向性的问题。
this
关键字的值取决于函数的调用方式。在 createMyObject
函数中,this
在 getPrivateProperty
方法中被使用。
javascript
obj.getPrivateProperty = function() {
return this[privateProperty];
};
在这个例子中,getPrivateProperty
是作为 obj
对象的一个方法被定义的。当一个函数作为对象的方法被调用时,this
通常指向调用该方法的对象。因此,当我们调用 instance.getPrivateProperty()
时,this
在 getPrivateProperty
方法中指向 instance
对象。
javascript
const instance = createMyObject();
console.log(instance.getPrivateProperty()); // 'This is private'
在这个调用中,this[privateProperty]
就等同于 instance[privateProperty]
,因此它返回的是 instance
对象的私有属性的值。
需要注意的是,this
的值并不是在函数定义时确定的,而是在函数调用时确定的。如果我们以不同的方式调用 getPrivateProperty
方法,this
的值可能会不同。例如,如果我们直接调用 getPrivateProperty
函数,而不是作为 instance
的方法调用它,那么 this
就会指向全局对象(在浏览器中是 window
对象,在 Node.js 中是 global
对象)。
javascript
const getPrivateProperty = instance.getPrivateProperty;
console.log(getPrivateProperty()); // undefined,因为 this 指向全局对象,全局对象没有 privateProperty 属性
这就是为什么我们通常需要小心处理 this
的值,特别是在事件处理器和回调函数中。在这些情况下,我们可能需要使用 bind
、call
或 apply
方法来显式地设置 this
的值。
-
防止属性名冲突:如果你正在编写一个库或框架,你可能需要向用户提供的对象添加一些属性。使用 Symbol 类型的属性键可以防止你添加的属性与用户的属性发生冲突。
javascriptconst libraryProperty = Symbol('libraryProperty'); function enhanceObject(obj) { obj[libraryProperty] = 'Enhanced by library'; // 添加其他属性和方法... return obj; }
-
使用 Well-known Symbols :JavaScript 提供了一些预定义的 Symbol 值,称为 Well-known Symbols,如
Symbol.iterator
、Symbol.toStringTag
等。这些 Symbol 值在 JavaScript 的内部机制中有特殊的用途。例如,你可以使用Symbol.iterator
来定义一个对象的默认迭代行为。javascriptconst myIterable = { [Symbol.iterator]: function* () { yield 1; yield 2; yield 3; } }; for (let value of myIterable) { console.log(value); // 1, 然后 2, 然后 3 }
以上就是一些在前端业务中可能会使用到 Symbol 类型的属性键的场景。然而,需要注意的是,虽然 Symbol 可以提供一些有用的功能,但它们也会增加代码的复杂性,所以在不需要的情况下,最好避免使用它们。