Javascript 符号:用于更改内置行为的众所周知的符号
据我所知,JavaScript ES6中的Javascript 符号:用于更改内置行为的众所周知的符号,javascript,ecmascript-6,Javascript,Ecmascript 6,据我所知,JavaScript ES6中的符号原语在以下两方面特别有用: 为对象属性创建唯一键 重写标准内置JavaScript对象方法、属性和运算符 例如:Symbol.hasInstance在(之前)instanceof运行时调用 因此,如果我们创建一个自定义版本的Symbol.hasInstance,我们就可以覆盖instanceof 我的基本问题是:为什么要使用符号来覆盖这些函数?我们不能直接覆盖它们吗 例如:覆盖String.prototype.match()而不是Symbol.m
符号
原语在以下两方面特别有用:
对象
属性创建唯一键对象
方法、属性和运算符
- 例如:
在(之前)Symbol.hasInstance
运行时调用instanceof
- 因此,如果我们创建一个自定义版本的
,我们就可以覆盖Symbol.hasInstance
instanceof
符号
来覆盖这些函数?我们不能直接覆盖它们吗
例如:覆盖String.prototype.match()
而不是Symbol.match
编辑:同意评论者的观点,即直接重写instanceof不起作用,因此使用match()作为示例。您在问题中的阐述不够详细,但从一些推论和评论来看,您似乎误解了知名符号是如何与现有类型交互的。这导致您误解了它们是如何改进可能的ES5全局覆盖解决方案的 重要的是要理解
String.match
的值是一个符号,而不是用于匹配的函数。这几乎就像是有人做了一样
Symbol.match = Symbol("match");
在程序顶部创建新符号,并将其设置为全局属性,以便任何人都可以从任何位置访问它
这与String.prototype.match
的值形成对比,后者是开发人员调用“foo.match(…)
时使用的实际函数
您似乎正在设想类似的String.prototype.match
String.prototype.match = function(obj) {
return Symbol.match(obj);
};
事实并非如此。查看实际实现的简化示例可能有助于您理解:
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);
};
记住,obj[Symbol.match](这个)
没有调用Symbol.match()
,它正在从obj
读取名为Symbol.match
的属性,然后调用结果函数
为什么要使用符号覆盖这些功能
希望这个例子能让这背后的道理更清楚
var regexp = new RegExp("little");
var result = "a little pattern".match(regexp);
从本质上讲,这与
var regexp = new RegExp("little");
var result = regexp[Symbol.match]("a little pattern");
那么,这有什么关系呢?因为现在,当您设计一个API来处理文本时,您不仅限于使用正则表达式。我可以把我自己的整个图书馆当作
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
最重要的是,我能够做到这一点,而无需更改任何全局变量。在JS代码中,通常认为修改globals是不好的做法,除非您正在填充官方指定和采用的API。您可以像这样实现上述功能
var original = String.prototype.match;
String.prototype.match = function(arg) {
if (arg instanceof MyOwnMatcher) return this.indexOf(arg);
return original.apply(this, arguments);
};
但它非常丑陋,容易出错,并且修改了一个全局对象,而这个对象不是您在自己的代码中定义的对象
基本上,您可以将已知符号视为实现由一段单独代码定义的接口的一种方式。如何直接重写instanceof?同意,instanceof不能直接重写。因此,我使用match()作为示例。fwiw无法在
元素.files
属性处实现aribtraryFile
对象的设置,而不使用符号。迭代器FileList
对象的属性,即使那个特定的实现并没有完全满足需求,为什么要覆盖现有的原型方法呢?如果目标是提供通用重写机制,则要求每个库重写全局函数将极易出错。为特定全局定义函数提供不同功能的另一种方法是使用类
,这将不会重写具有相同名称的全局本机函数。具体的方法取决于你想要达到的目标,这是非常有帮助的,谢谢。因此,总而言之,众所周知的符号允许您为一个特定对象创建自定义函数,全局内置对象将使用该函数(代替其自身的方法)。关键点是:只有使用符号的一个对象的行为才会发生变化。say.match()的所有其他用法将不受影响。这是对其目的的正确理解吗?(附言:很抱歉回复晚了,我一直在旅行)