admin管理员组文章数量:1336367
I recently came across some code that was using syntax that I wasn't too familiar with. At first, it appeared to be a function that was part of an object, but I can't seem to access it. I've found information here on it, but I'm still not sure why someone would use this over a standard function signature. This is an example of the code, and what I'm trying to do with it.
const secretFunction = Symbol('secretFunction');
class SecretController {
constructor(){
...
}
[secretFunction](){
console.log("I AM THE SECRET!");
}
}
So, what I am trying to do is test this code with a tool called jest. I'm doing so like:
let secretController = new SecretController();
let secretFunction = Symbol('secretFunction');
describe("TEST", function(){
it('What is this?', function(){
secretController[secretFunction](); // <-- doesn't work
})
})
I've tried this a few other ways, but I get the same type of result. That is:
TypeError: secretController[secretFunction] is not a function
What is the purpose of writing a function this way? How do you use functions like this? How do you test them?
I recently came across some code that was using syntax that I wasn't too familiar with. At first, it appeared to be a function that was part of an object, but I can't seem to access it. I've found information here on it, but I'm still not sure why someone would use this over a standard function signature. This is an example of the code, and what I'm trying to do with it.
const secretFunction = Symbol('secretFunction');
class SecretController {
constructor(){
...
}
[secretFunction](){
console.log("I AM THE SECRET!");
}
}
So, what I am trying to do is test this code with a tool called jest. I'm doing so like:
let secretController = new SecretController();
let secretFunction = Symbol('secretFunction');
describe("TEST", function(){
it('What is this?', function(){
secretController[secretFunction](); // <-- doesn't work
})
})
I've tried this a few other ways, but I get the same type of result. That is:
TypeError: secretController[secretFunction] is not a function
What is the purpose of writing a function this way? How do you use functions like this? How do you test them?
Share edited Feb 3, 2020 at 23:08 skyboyer 23.8k7 gold badges62 silver badges71 bronze badges asked Feb 3, 2020 at 22:26 Chloe BennettChloe Bennett 9712 gold badges12 silver badges28 bronze badges 2-
2
Did you import the symbol (
secretFunction
) from the file whereSecretController
is defined ? if you merely re-create a symbol with the same description in your test, it won't work. – Touffy Commented Feb 3, 2020 at 22:31 -
2
The idea behind this code was to make the method private. Unfortunately the author failed at it, nothing about
secretFunction
is really secret. You can access the symbol usingObject.getOwnPropertySymbols(SecretController.prototype)[0]
, and then invoke the method. Or really, just export thesecretFunction
symbol and import it in your test file. However, a private method actually is not supposed to need any testing. – Bergi Commented Feb 3, 2020 at 22:37
3 Answers
Reset to default 4As the article you linked to points out, some mon symbols allow you to override built-in Javascript behaviour in a way that functions alone can't.
Symbol.iterator
Consider this code:
const foo = {}
for (const item of foo) {
console.log(item)
}
It raises a TypeError
: 'foo is not iterable'. Using Symbol.iterator
you can change the behaviour of the for
loop:
const foo = {}
foo[Symbol.iterator] = function * () {
for (let i = 0; i < 10; i++) {
yield 'foo ' + i
}
}
for (const item of foo) {
console.log(item)
}
Which now outputs:
foo 0
foo 1
foo 2
foo 3
foo 4
foo 5
foo 6
foo 7
foo 8
foo 9
Symbol.toPrimitive
Similar to the above, you can change how the Javascript runtime will perform type coercion on objects. For instance, stringifying plain objects tends to return [object Object]
, but we can make it more descriptive:
const foo = {}
console.log(String(foo))
foo[Symbol.toPrimitive] = () => {
return 'Foo is a nice lad'
}
console.log(String(foo))
Which outputs:
[object Object]
Foo is a nice lad
FYI the above would make all type coercions of foo
into a string, but you could cover other cases too.
The specific purpose I had for this, was to enable a sort of duck-typing.
Basically, if an object is passed to a function, and it has a [mySymbol]
function, my system will handle it differently.
Effectively I used this as a type of interface. If I gave this function a name, it would probably have been something like handle()
, but due a large chance of collision, it felt safer to allow users to implement this with this specific symbol.
This is not unlike Javascript's built-in Symbol.iterator, which serves a similar purpose. This symbol allows any object to implement this interface-like function, which causes the Javascript engine to call it when a user throws it in a for...of
loop.
Symbol.iterator
is also not secret or meant to be private.
What do people use Symbol functions in Javascript for?
A Symbol in Javascript allows you to create a unique and token that can be used in a number of ways, most often as a property name on an object. There are several advantages to using a Symbol in this way:
It is totally unique in the system and cannot conflict with any other property name or symbol name. So, there can never be a name collision when using a Symbol as a property name. You can think of the Symbol as its own namespace that does not intersect with the typical strings used as property names in any way (it truly is a different data type from a string). With ES6 and the introduction of symbols, these new data types can be property names (before property names could only be strings).
The Javascript language itself can use various new symbols to define new properties of objects that cannot conflict with any user-code properties that were previously being used. For example, all iterable things like an Array in ES6+ have a
Symbol.iterator
property on them. The recent versions of Javascript have defined several new "known" property names in this way that can be used in service of new language features without any risk of conflicting with string property names being used in prior code.You can create your own Symbols as unique tokens for any purpose. So, rather than trying to make up a unique prefix such as "_somethingRTryingToBeUnique" and hoping that it never conflicts with something else, you can now just make a Symbol and know that it's unique when pared to any other string or symbol in this Javascript instance.
Some people use a newly created Symbol as an explicitly non-public means of accessing some property on an object. If you also make it non-enumerable, then it won't show in the usual ways that one iterates properties of any object such as
for prop in obj
or Object.keys(obj) or evenObject.getOwnPropertyNames(obj)
because that explicitly returns only string properties, not Symbol properties. It is not pletely private because it can be accessed viaObject.getOwnPropertySymbols(obj)
, but it has at least been separated from all the purposely enumerable properties and separate from the string properties. It won't accidentally get lumped in with any string property processing.
As for the code you show:
const secretFunction = Symbol('secretFunction');
class SecretController {
constructor(){
}
[secretFunction](){
console.log("I AM THE SECRET!");
}
}
let x = new SecretController();
x[secretFunction]();
This creates a class with a method that needs access to the secretFunction
Symbol in order to call that method.
You cannot create the same secretFunction
symbol by just calling this:
const secretFunction = Symbol('secretFunction');
again. The 'secretFunction'
string passed to the Symbol function is just a debugging tag, it does not affect the creation of the Symbol at all. So, when you call that again with the same string, it creates a new and different Symbol than the first time. So, you can't call it again to generate a symbol that can be used to access that original function.
Also, using a Symbol as a property name in a class
definition automatically makes it non-enumerable so it's not easy to find from the outside world. Neither of these:
console.log(Object.keys(SecretController.prototype))
console.log(Object.getOwnPropertyNames(SecretController.prototype));
will list or enumerate the private function.
What is the purpose of writing a function this way?
To make it non-public and to separate it from any string-based properties on the object.
How do you use functions like this?
They would be used internally where access to the original Symbol is available.
How do you test them?
They would not be tested from the outside world because they are not meant to be accessed from the outside world. So, they would likely be tested only by testing the other methods that use or rely on that non-public method or by internal test code within the module (not outside the module).
Just to be entirely clear here. A property with a Symbol as its property name is not entirely private. It can be retrieved with Object.getOwnPropertySymbols(obj)
. True privacy likely needs to use a weakMap
that is held in a private closure or module as described here or some other related method to get real privacy.
本文标签: What do people use Symbol functions in Javascript forStack Overflow
版权声明:本文标题:What do people use Symbol functions in Javascript for? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742405808a2468796.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论