Когда мы уже упоминали примитивные типы данных JavaScript, мы знаем, что существуютNumber,String,Null,Boolean,UndefinedЭти виды. ES6 представляет новые примитивные типы данныхSymbolа такжеBigInt. Сегодня мы узнаемSymbolТипы.SymbolТип предназначен для решения проблемы конфликта имен атрибутов, а также имеет функцию имитации частных атрибутов.
Введение
СоздайтеsymbolСамый простой способ использовать переменную — использоватьSymbol()функция.sysmbolПеременные являются особыми двумя способами:
- Его можно использовать как имя свойства объекта. только струны и
symbolтипы могут использоваться как имена свойств объекта. - нет двух
symbolзначения равны.
const symbol1 = Symbol();
const symbol2 = Symbol();
symbol1 === symbol2; // false
const obj = {};
obj[symbol1] = 'Hello';
obj[symbol2] = 'World';
obj[symbol1]; // 'Hello'
obj[symbol2]; // 'World'
Хотя звонитSymbol()сделать его похожим на объект, на самом делеsymbolявляется примитивным типом данных JavaScript. ПучокSymbolиспользовать как конструкторnewсообщит об ошибке.
const symbol1 = Symbol();
typeof symbol1; // 'symbol'
symbol1 instanceof Object; // false
// Throws "TypeError: Symbol is not a constructor"
new Symbol();
Описание
Symbol()Функция только один параметр, строкаdescription. Единственная роль этого строкового параметра — помощь в отладке, т. е.toString()стоимость. Однако обратите внимание, что оба имеют одинаковыеdescriptionизsymbolСлишкомне равныйиз.
const symbol1 = Symbol('my symbol');
const symbol2 = Symbol('my symbol');
symbol1 === symbol2; // false
console.log(symbol1); // 'Symbol(my symbol)'
иметь глобальныйsymbolреестр, сSymbol.for()созданныйsymbolбудут добавлены в этот реестр и будут использовать егоdescriptionкак индексный ключ. То есть, если вы используетеSymbol.for()Создать с тем жеdescriptionдваsymbol, они равны.
const symbol1 = Symbol.for('test');
const symbol2 = Symbol.for('test');
symbol1 === symbol2; // true
console.log(symbol1); // 'Symbol(test)'
Вообще говоря, если у вас нет очень веской причины, в противном случае не следует использовать глобальный реестр, потому что это вызовет конфликты имен.
конфликт имен
JavaScript имеет встроенныйsymbol, то есть в ES6Symbol.iterator . имеютSymbol.iteratorОбъект функции называетсяповторяемый объект, то есть можно использовать на объектеfor/ofцикл.
const fibonacci = {
[Symbol.iterator]: function*() {
let a = 1;
let b = 1;
let temp;
yield b;
while (true) {
temp = a;
a = a + b;
b = temp;
yield b;
}
}
};
// Prints every Fibonacci number less than 100
for (const x of fibonacci) {
if (x >= 100) {
break;
}
console.log(x);
}
Зачем использовать это здесьSymbol.iteratorвместо струн? Предположим, что нетSymbol.iterator, итерируемый объект должен иметь строковое имя свойства'iterator', как следующий класс итерируемых объектов:
class MyClass {
constructor(obj) {
Object.assign(this, obj);
}
iterator() {
const keys = Object.keys(this);
let i = 0;
return (function*() {
if (i >= keys.length) {
return;
}
yield keys[i++];
})();
}
}
MyClassЭкземпляр — это итерируемый объект, который может перемещаться по свойствам объекта. Но у приведенного выше класса есть потенциальный изъян.Предположим, что злоумышленник даетMyClassКонструктору передаетсяiteratorСвойства объекта:
const obj = new MyClass({ iterator: 'not a function' });
Как и тыobjиспользовать наfor/of, JavaScript выдастTypeError: obj is not iterableаномальный. Видно, что входящий объектiteratorФункция переопределяет классiteratorАтрибуты. Это какЗагрязнение прототипаПроблемы с безопасностью, бездумное копирование пользовательских данных повлияет на некоторые специальные свойства, такие как__proto__а такжеconstructorвызвать проблемы.
Суть здесь в том, чтоsymbolПусть хорошо поливают внутренние данные объекта и пользовательские данные. из-заsysmbolНе может быть представлен в формате JSON, поэтому не беспокойтесь о передаче неуместныхSymbol.iteratorатрибутивные данные. Кроме того, для объектов, которые смешивают встроенные функции и пользовательские данные, напримерMongoose model, вы можете использовать егоsymbolчтобы пользовательские данные не конфликтовали со встроенными свойствами.
частная собственность
из-за любых двухsymbolне равны, и их можно легко использовать для моделирования частных свойств в JavaScript.symbolне появится вObject.keys(), поэтому, если вы явноexport Одинsymbolили сObject.getOwnPropertySymbols() функцию, иначе другой код не сможет получить доступ к этому свойству.
function getObj() {
const symbol = Symbol('test');
const obj = {};
obj[symbol] = 'test';
return obj;
}
const obj = getObj();
Object.keys(obj); // []
// 除非有这个 symbol 的引用,否则无法访问该属性
obj[Symbol('test')]; // undefined
// 用 getOwnPropertySymbols() 依然可以拿到 symbol 的引用
const [symbol] = Object.getOwnPropertySymbols(obj);
obj[symbol]; // 'test'
Другая причинаsymbolне появится вJSON.stringify()в итоге точноJSON.stringify()будет игнорироватьsymbolИмя свойства и значение свойства:
const symbol = Symbol('test');
const obj = { [symbol]: 'test', test: symbol };
JSON.stringify(obj); // "{}"
Суммировать
использоватьSymbolПредставляет внутреннее состояние объекта и обеспечивает хорошую изоляцию пользовательских данных и состояния программы. С ним нам больше не нужны определенные соглашения об именах, такие как внутренние свойства с'$'начало. В следующий раз, когда вам понадобится определить частную собственность, попробуйтеSymbolВведи это!
Увидев этот довольно темпераментный логотип, почему вы не обращаете внимания?