这是JavaScript。随着它变得更好,您会发现通常有一条中间道路可以帮助消除这种困境。另外,当有人尝试使用某个不受支持的“类型”时,它是否被某些东西捕获或中断,也没有关系,因为没有编译与运行时的关系。如果使用不当,它将损坏。试图隐藏它已损坏或使其在崩溃时中途工作不会改变事实。
因此,也要吃蛋糕,也要吃蛋糕,并学会通过使所有事物真正,非常明显地保留,如在命名正确的地方以及所有正确的地方保留所有正确的细节,来避免类型混乱和不必要的损坏。
首先,我强烈建议养成养成在需要检查类型之前先放鸭的习惯。最精简和最有效的方法(但就本机构造函数而言并非总是最好的)是先打原型,这样您的方法甚至不必关心所支持的类型在起作用。
String.prototype.pullRabbit = function(){
//do something string-relevant
}
HTMLElement.prototype.pullRabbit = function(){
//do something HTMLElement-relevant
}
Magician.pullRabbitFrom = function(someThingy){
return someThingy.pullRabbit();
}
注意:由于一切都从Object继承,因此对Object进行此操作被广泛认为是一种不好的形式。我个人也避免使用Function。有些人可能会对接触任何本机构造函数的原型感到不安,这可能不是一个坏策略,但是在使用自己的对象构造函数时,该示例仍然可以使用。
我不会为这种特定用途的方法担心这种方法,这种方法不太可能破坏不太复杂的应用程序中另一个库中的内容,但是如果您不这样做的话,最好避免在JavaScript的本机方法中过分断言任何东西除非您要在过时的浏览器中标准化较新的方法,否则必须这样做。
幸运的是,您始终可以将类型或构造函数名称预先映射到方法中(请注意IE <= 8,它没有<object> .constructor.name要求您将其从构造函数属性的toString结果中解析出来)。您仍在检查构造函数名称(在比较对象时,typeof在JS中是无用的),但至少它比巨型switch语句或方法的每次调用中的if / else链读取的内容都好得多,这可能范围很广。各种对象。
var rabbitPullMap = {
String: ( function pullRabbitFromString(){
//do stuff here
} ),
//parens so we can assign named functions if we want for helpful debug
//yes, I've been inconsistent. It's just a nice unrelated trick
//when you want a named inline function assignment
HTMLElement: ( function pullRabitFromHTMLElement(){
//do stuff here
} )
}
Magician.pullRabbitFrom = function(someThingy){
return rabbitPullMap[someThingy.constructor.name]();
}
或使用相同的映射方法,如果您想访问不同对象类型的'this'组件以像使用方法一样使用它们而不接触其继承的原型:
var rabbitPullMap = {
String: ( function(obj){
//yes the anon wrapping funcs would make more sense in one spot elsewhere.
return ( function pullRabbitFromString(obj){
var rabbitReach = this.match(/rabbit/g);
return rabbitReach.length;
} ).call(obj);
} ),
HTMLElement: ( function(obj){
return ( function pullRabitFromHTMLElement(obj){
return this.querySelectorAll('.rabbit').length;
} ).call(obj);
} )
}
Magician.pullRabbitFrom = function(someThingy){
var
constructorName = someThingy.constructor.name,
rabbitCnt = rabbitPullMap[constructorName](someThingy);
console.log(
[
'The magician pulls ' + rabbitCnt,
rabbitCnt === 1 ? 'rabbit' : 'rabbits',
'out of her ' + constructorName + '.',
rabbitCnt === 0 ? 'Boo!' : 'Yay!'
].join(' ');
);
}
在任何语言IMO中,一个良好的通用原则是,在获得真正能够触发触发器的代码之前,尝试整理出这样的分支细节。这样一来,很容易就能看到涉及该顶级API级别的所有参与者的概况,而且也很容易找出可能会发现某人可能关心的细节的地方。
注意:这都是未经测试的,因为我假设没有人实际使用RL。我确定有错别字/错误。