symbol
. What for? There are three main reasons for the appearance of this data type.for-in
loops and methods like Object.keys
. var myObject = {firstName:'raja', lastName:'rao'}
Object.keys(myObject)
command, it returns the array [firstName, lastName]
.myObject
object, for example, newProperty
. In doing so, we need the Object.keys(myObject)
command to return the same values ​​as before (in other words, something should make this function ignore the new property newProperty
), that is, [firstName, lastName]
, and not [ firstName, lastName, newProperty]
. How to do it?symbol
data type, this could not be done. Now, if you add newProperty
as a symbol, the Object.keys(myObject)
command Object.keys(myObject)
ignore this property (since it simply does not know about it) and returns what is needed - [firstName, lastName]
.toUpperCase
method in Array.prototype
.Array.prototype.toUpperCase
method. This may well cause your code to stop working correctly. Array.prototype.toUpperCase = function(){ var i; for (i = 0; i<this.length; i++){ this[i] = this[i].toUpperCase(); } return this; } var myArray = ['raja', 'rao']; myArray.toUpperCase(); //['RAJA', 'RAO']
String.prototype.search
, to call your own function that implements your logic to search for something in the string. That is, for example, it is necessary that the construction 'somestring'.search(myObject);
would call the search
function of the myObject
object and pass it, as an argument, 'somestring'
. How to do it?Symbol
. This function will return a value of type symbol
. // mySymbol symbol var mySymbol = Symbol();
new
, a new object is expected to return, you cannot use the keyword new
to create entities of type symbol
. var mySymbol = new Symbol(); // ,
// mySymbol , // - "some text" const mySymbol = Symbol('some text');
const mySymbol1 = Symbol('some text'); const mySymbol2 = Symbol('some text'); mySymbol1 == mySymbol2 // false
symbol
type variables using the Symbol()
function, you can create them using the Symbol.for(<key>)
method Symbol.for(<key>)
. This method takes a key (string <key>
) and creates new characters. In this case, if this key is given a key already assigned to an existing symbol, it will simply return that existing symbol. Therefore, we can say that the behavior of Symbol.for
resembles a singleton design pattern. var mySymbol1 = Symbol.for('some key'); // var mySymbol2 = Symbol.for('some key'); // mySymbol1 == mySymbol2 //true
Symbol.for
method exists so that you can create characters in one place and work with them in another..for()
method .for()
transfer of a key that has already been used, it does not create a new character with such a key, but returns an existing one. Therefore, use it with caution.Symbol.for
construction, the symbols, even when using the same keys, will be unique. However, if you use Symbol.for
, then specifying non-unique keys and symbols returned by Symbols.for
will be non-unique. Consider an example. var mySymbol1 = Symbol('some text'); // "some text" var mySymbol2 = Symbol('some text'); // "some text" var mySymbol3 = Symbol.for('some text'); // "some text" var mySymbol4 = Symbol.for('some text'); // , mySymbol3 // true, // .for // mySymbol3 == mySymbol4 //true // mySymbol1 == mySymbol2 //false mySymbol1 == mySymbol3 //false mySymbol1 == mySymbol4 //false
const mySymbol = Symbol("Some car description"); const myObject = {name: 'bmw'}; myObject[mySymbol] = 'This is a car'; // // console.log(myObject[mySymbol]); //'This is a car'
let myCar = {name: 'BMW'}; let type = Symbol('store car type'); myCar[type] = 'A_1uxury_Sedan'; let honk = Symbol('store honk function'); myCar[honk] = () => 'honk'; // myCar.type; // myCar[type]; // 'store car type' myCar.honk(); // myCar[honk](); // 'honk'
for-in
loop loops over the properties of the obj
object, but it does not know about the prop3
and prop4
(or ignores these properties), since their identifiers are represented by characters. var obj = {}; obj['prop1'] = 1; obj['prop2'] = 2; // -, // ( // ) var prop3 = Symbol('prop3'); var prop4 = Symbol('prop4'); obj[prop3] = 3; obj[prop4] = 4; for(var key in obj){ console.log(key, '=', obj[key]); } // , // prop3 prop4 //prop1 = 1 //prop2 = 2 // prop3 prop4 , // console.log(obj[prop3]); //3 console.log(obj[prop4]); //4
Object.keys
and Object.getOwnPropertyNames
ignore property names represented by characters. const obj = { name: 'raja' }; // - obj[Symbol('store string')] = 'some string'; obj[Symbol('store func')] = () => console.log('function'); // - // console.log(Object.keys(obj)); //[name] console.log(Object.getOwnPropertyNames(obj)); //[name]
Array
object by adding our own Array.prototype.includes
method to its prototype. This method will conflict with the standard includes
method that is present in ES2018 JavaScript. How to equip a prototype with this method and avoid collisions?includes
and assign a symbol to it. Then you need to use this variable to add a new property to the global Array
object using the bracket notation. After that, it remains only to assign the necessary function to the new property.arr[includes]()
, and not a regular string. var includes = Symbol('will store custom includes method'); // Array.prototype Array.prototype[includes] = () => console.log('inside includes func'); // var arr = [1,2,3]; // // includes console.log(arr.includes(1)); //true console.log(arr['includes'](1)); //true // includes arr[includes](); // 'inside includes func', includes -
Symbol
object (this is the same object that we used to create new characters).String.prototype.search
and String.prototype.replace
standard objects like String
or Array
.Symbol.match
, Symbol.replace
, Symbol.search
, Symbol.iterator
and Symbol.split
.String.prototype.search
method of the String.prototype.search
object searches the string using a regular expression or a sample string, and if it managed to find what it needs, it returns the index of the search term in the analyzed string. 'rajarao'.search(/rao/); 'rajarao'.search('rao');
Symbol.search
method is Symbol.search
in a RegExp
object. If this is the case, then it is the method of the RegExp
object that is being searched for. Thus, the basic objects, like RegExp
, implement methods corresponding to Symbol.search
, which solve search problems.'rajarao'.search('rao');
command 'rajarao'.search('rao');
"rajarao"
converted to a String (new String("rajarao"))
object String (new String("rajarao"))
"rao"
character sequence is converted to a RegExp (new Regexp("rao"))
object RegExp (new Regexp("rao"))
search
method of a String
object based on the string "rajarao"
search
method of the "rajarao"
object "rajarao"
method of the "rao"
object is called (that is, the search operation is delegated to the "rao"
object). The string "rajarao"
passed to this method. If you schematically present this call, it can look something like this: "rao"[Symbol.search]("rajarao")
"rao"[Symbol.search]("rajarao")
returns, as a search result, the number 4 representing the index of the search
substring in the string of the search
function of the object "rajarao"
, and this function, in turn, returns 4 to our code . // String class String { constructor(value){ this.value = value; } search(obj){ // Symbol.search obj // value obj[Symbol.search](this.value); } } // RegExp class RegExp { constructor(value){ this.value = value; } // [Symbol.search](string){ return string.indexOf(this.value); } }
RegExp
object. The standard function String.prototype.search
can now correctly perceive any object that implements the Symbol.search
method, which returns what the developer needs, and this will not break the code. Let us dwell on this in more detail.String.prototype.search
the search function of our own class Product
. This is possible thanks to the global symbol Symbol.search
. class Product { constructor(type){ this.type = type; } // [Symbol.search](string){ return string.indexOf(this.type) >=0 ? 'FOUND' : "NOT_FOUND"; } } var soapObj = new Product('soap'); 'barsoap'.search(soapObj); //FOUND 'shampoo'.search(soapObj); //NOT_FOUND
'barsoap'.search(soapObj);
command 'barsoap'.search(soapObj);
"barsoap"
converted to a String
object ( new String("barsoap")
)soapObj
already an object, it is not converted.search
method of a String
object based on the string "barsoap"
Symbol.search
method of the Symbol.search
object is soapObj
(the search operation is delegated to this object), and the string "barsoap"
. In fact, we are talking about this command: soapObj[Symbol.search]("barsoap")
soapObj[Symbol.search]("barsoap")
soapObj[Symbol.search]("barsoap")
returns to the search
function a result that, in accordance with the internal logic of the soapObj
object, can be FOUND
and NOT_FOUND
. The search
function returns this result to our code.for-of
loop and an extension operator ( …
), designed to extract data sets from standard objects like arrays, strings, objects of type Map
. Why don't we use these standard methods to work with our own objects that store data sets?for-of
loop and the extension operator cannot be used to extract data from the User
class, which we have created ourselves. Here, to work with it, you have to use the get
method, which we also created ourselves. // // for-of // // Users, // class Users { constructor(users){ this.users = users; } // get() { return this.users; } } const allUsers = new Users([ { name: 'raja' }, { name: 'john' }, { name: 'matt' }, ]); // allUsers.get() , for (const user of allUsers){ console.log(user); } // TypeError: allUsers is not iterable // const users = [...allUsers]; // TypeError: allUsers is not iterable
iterables
.Symbol.iterator
symbol, which implements the method described in clauses 3-6.Symbol.iterator
method should return another object - an iterator.next
method.next
method should have access to the data described in clause 1.next
method is called, the data from point 1 should be returned, either in the format {value:<stored data>, done: false}
, if the iterator can return something else, or in the form {done: true}
, if The iterator has nothing more to return.Users
object iterable. // // Users , // Symbol.iterator, next, // class Users{ constructor(users){ this.users = users; } // Symbol.iterator - , // [Symbol.iterator](){ let i = 0; let users = this.users; // return { next(){ if (i<users.length) { return { done: false, value: users[i++] }; } return { done: true }; }, }; } } //allUsers const allUsers = new Users([ { name: 'raja' }, { name: 'john' }, { name: 'matt' }, ]); //allUsersIterator const allUsersIterator = allUsers[Symbol.iterator](); // next , // console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); // : //{ done: false, value: { name: 'raja' } } //{ done: false, value: { name: 'john' } } //{ done: false, value: { name: 'matt' } } // for-of for(const u of allUsers){ console.log(u.name); } // : raja, john, matt // console.log([...allUsers]); //
allUsers
) for-of
, <iterable>[Symbol.iterator]()
, ( allUsersIterator
), .*<myGenerator>
. - function * myGenerator(){}
myGenerator()
generator
, () , , , iterator
.yield
.yield
, .yield
, , next
.*getIterator()
) Symbol.iterator
next()
, . // , // - (*getIterator()) // class Users{ constructor(users) { this.users = users; this.len = users.length; } // , *getIterator(){ for (let i in this.users){ yield this.users[i]; // , //yield } } } const allUsers = new Users([ { name: 'raja' }, { name: 'john' }, { name: 'matt' }, ]); //allUsersIterator const allUsersIterator = allUsers.getIterator(); // next , // console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); // : //{ done: false, value: { name: 'raja' } } //{ done: false, value: { name: 'john' } } //{ done: false, value: { name: 'matt' } } //{ done: true, value: undefined } // for-of for(const u of allUsers.getIterator()){ console.log(u.name); } // : raja, john, matt // console.log([...allUsers.getIterator()]); //
*
) yield
. // Users - , function* Users(users){ for (let i in users){ yield users[i++]; // , //yield } } const allUsers = Users([ { name: 'raja' }, { name: 'john' }, { name: 'matt' }, ]); // next , // console.log(allUsers.next()); console.log(allUsers.next()); console.log(allUsers.next()); console.log(allUsers.next()); // : //{ done: false, value: { name: 'raja' } } //{ done: false, value: { name: 'john' } } //{ done: false, value: { name: 'matt' } } //{ done: true, value: undefined } const allUsers1 = Users([ { name: 'raja' }, { name: 'john' }, { name: 'matt' }, ]); // for-of for(const u of allUsers1){ console.log(u.name); } // : raja, john, matt const allUsers2 = Users([ { name: 'raja' }, { name: 'john' }, { name: 'matt' }, ]); // console.log([...allUsers2]); //
allUsers
, , , Generator
.Generator
throw
return
, next
. , , .yield
( , ) , , , yield
.yield
, . , generator.next("some new value")
, yield
. function* generator(a, b){ // a + b // , k , // a + b let k = yield a + b; // m let m = yield a + b + k; yield a + b + k + m; } var gen = generator(10, 20); // a + b // , done false, // yield console.log(gen.next()); //{value: 30, done: false} // , //a b, .next() , - //, , // // k 50 a + b + k console.log(gen.next(50)); //{value: 80, done: false} // , a, b k. // .next() , // , // m 100 a + b + k + m console.log(gen.next(100)); //{value: 180, done: false} // .next(), undefined, // yield console.log(gen.next()); //{value: undefined, done: true}
// // - function *myGenerator() {} // function * myGenerator() {} // function* myGenerator() {} // const myGenerator = function*() {} // , // let generator = *() => {} // //SyntaxError: Unexpected token * // ES2015 class MyClass { *myGenerator() {} } // const myObject = { *myGenerator() {} }
yield
, return
. , , return
, . , yield
, . function* myGenerator() { let name = 'raja'; yield name; console.log('you can do more stuff after yield'); } // const myIterator = myGenerator(); // .next() console.log(myIterator.next()); //{value: "raja", done: false} // .next() // // 'you can do more stuff after yield' //{value: undefined, done: true} console.log(myIterator.next());
yield
, , return
, , yield
. function* myGenerator() { let name = 'raja'; yield name; let lastName = 'rao'; yield lastName; } // const myIterator = myGenerator(); // .next() console.log(myIterator.next()); //{value: "raja", done: false} // .next() console.log(myIterator.next()); //{value: "rao", done: false}
.next()
..next()
, ( ). ( 23
), .next(23)
. function* profileGenerator() { // .next() , //, yield, . // , , // .next(), answer let answer = yield 'How old are you?'; // 'adult' 'child' // answer if (answer > 18){ yield 'adult'; } else { yield 'child'; } } // const myIterator = profileGenerator(); console.log(myIterator.next()); //{value: "How old are you?", done: false} console.log(myIterator.next(23)); //{value: "adult", done: false}
.next()
. , .co
.next(result)
â„–5 10, . co(function *() { let post = yield Post.findByID(10); let comments = yield post.getComments(); console.log(post, comments); }).catch(function(err){ console.error(err); });
co
, ,Post.findByID(10)
Post.findByID(10)
.next(result)
post
post.getComments()
post.getComments()
.next(result)
comments
console.log(post, comments);
co
. , — , ECMAScript , . async
await
.await
yield
.await
.async function
, function*
.async/await
— , « ».async
, , JavaScript- , -. , , await
. , await
, , .getAmount
— getUser
getBankBalance
. , async/await . // ES2015... function getAmount(userId){ getUser(userId) .then(getBankBalance) .then(amount => { console.log(amount); }); } // async/await ES2017 async function getAmount2(userId){ var user = await getUser(userId); var amount = await getBankBalance(user); console.log(amount); } getAmount('1'); //$1,000 getAmount2('1'); //$1,000 function getUser(userId){ return new Promise(resolve => { setTimeout(() => { resolve('john'); }, 1000); }); } function getBankBalance(user){ return new Promise((resolve, reject) => { setTimeout(() => { if (user == 'john'){ resolve('$1,000'); } else { reject('unknown user'); } }, 1000); }); }
Symbol.asyncIterator
, — for-await-of
, ..next()
{value: 'some val', done: false}
: iterator.next() //{value: 'some val', done: false}
.next()
, , , {value: 'some val', done: false}
. iterator.next().then(({ value, done })=> {//{value: 'some val', done: false}}
for-await-of
. const promises = [ new Promise(resolve => resolve(1)), new Promise(resolve => resolve(2)), new Promise(resolve => resolve(3)), ]; // , // async function test(){ for await (const p of promises){ console.log(p); } } test(); //1, 2, 3
Object.keys
for-in
.for-of
..next()
. .Source: https://habr.com/ru/post/359004/
All Articles