You didn't quite elaborate enough in your question, but from a bit of inference and the comments, it seems like you are be misunderstanding how well-known symbols are used to interact with existing types. That is causing you to misunderstand how they improve over possible ES5 global overwriting solutions.
It's important to understand that the value of String.match
is a symbol, not a function for matching. It is almost as if someone had done
Symbol.match = Symbol("match");
at the top of your program to create a new Symbol, and set it as a global property so anyone can access it from anywhere.
This is in contrast with the value of String.prototype.match
which is the actual function that is used when developers call "foo".match(...)
.
You seem to be envisioning String.prototype.match
like
String.prototype.match = function(obj) {
return Symbol.match(obj);
};
which is not the case. Looking at a simplified example of the actual implementation may help you understand:
String.prototype.match = function(obj) {
// Any object that has a `Symbol.match` property
// will just call that property. This includes every
// existing RegExp object.
if (obj != null && obj[Symbol.match] !== undefined) {
return obj[Symbol.match](this);
}
// Otherwise create a new regex to match against
// match match using that. This is to handle strings, e.g
// "foo".match("f")
const reg = new RegExp(obj);
return reg[Symbol.match](this);
};
and remember, obj[Symbol.match](this);
is not calling Symbol.match()
, it is reading a property from obj
with the name Symbol.match
, and then calling the resulting function.
Why use a Symbol to override these functions?
Hopefully that example makes the reasoning behind this clearer.
var regexp = new RegExp("little");
var result = "a little pattern".match(regexp);
is essentially identical to doing
var regexp = new RegExp("little");
var result = regexp[Symbol.match]("a little pattern");
So why does this matter? Because now when you're designing an API to process text, you aren't limited to doing so with regular expressions. I could make my own whole library as
class MyOwnMatcher {
constructor(word) {
this.word = word;
}
[Symbol.match](haystack) {
return haystack.indexOf(this.word);
}
}
var index = "a little pattern".match(new MyOwnMatcher("little"));
// index === 2
and most importantly, I'm able to do this without having to change any globals. In JS code generally it's considered bad practice to modify globals unless you're polyfilling an officially specced and adopted API. You could implement the above like
var original = String.prototype.match;
String.prototype.match = function(arg) {
if (arg instanceof MyOwnMatcher) return this.indexOf(arg);
return original.apply(this, arguments);
};
but it's extremely ugly, easy to get wrong, and modifies a global object that isn't one that you've defined in your own code.
You can essentially think of well-known symbols as a way to implement an interface defined by a separate piece of code.