What are the performance repercussions of adding functions to the String class in JavaScript and Node.js?
What are the repercussions of adding functions to the String class in JavaScript? Is this a bad idea? E.g.,
// String functions
String.prototype.startsWith = function(string) {
return (this.indexOf(string) === 0);
}
String.proto开发者_开发技巧type.empty = function() {
//console.log($.trim(this.valueOf()));
if($.trim(this.valueOf()) == '') {
return true;
}
else {
return false;
}
}
Performance-wise, there is zero effect.
But it's still not a great idea, imo. You're now depending on globally altered state. What happens if some other module does the same thing? Or worse, does a slightly different thing, but using the same name? Ouch.
Better to just define functions that take String arguments, and then use the functions.
Well first off prototype is slower than functions on objects. Creating a function has a cost as does look up. Look up is more expensive on the prototype than on just a normal object
Check out this JSPerf: http://jsperf.com/prototype-methods-vs-object-methods
Here is the setup:
<script>
Benchmark.prototype.setup = function() {
function Bob() {
}
var b = new Bob();
Bob.prototype.testproto = function() {};
b.testobj = function() {};
};
</script>
That being said, adding things onto the string prototype is no different than adding it to any other prototype.
It has no performance penalties. It does not affect any String object directly, the function is only bound to the String.prototype
-object.
The only reason not to do it is because somewhere someone might be using a for-in construct without checking for hasOwnProperty
and accidentally iterating over your new function.
If that's not likely, you should go ahead.
I'd suggest writing your own native object prototype expansion library, which is much simpler and quicker than the first phrase of this sentence might suggest. Prototype.js does something similar, as do I in a proprietary library I use on various systems I maintain. One advantage of this route is interlibrary compatibility, another is reducing the overhead of creating new native objects when your expansion methods aren't needed. Some libraries like this use a single object for expansion methods, I prefer to have objects relating to specific native objects.
(function(){
//native object specific factory objects for expansion
var Arrays = function(o) { this.value = o; },
, Objects = function(o) { this.value = o; },
, Strings = function(o) { this.value = o; },
, Functions = function(o) { this.value = o; },
, Dates = function(o) { this.value = o; },
, Numbers = function(o) { this.value = o; };
, Booleans = function(o) { this.value = o; };
//route object to correct expansion pack
var Shell = function(o) {
var type = Object.prototype.toString.call(o);
switch( type ) {
case '[object Array]' : return new Arrays(o);
case '[object Boolean]' : return new Booleans(o);
case '[object Date]' : return new Dates(o);
case '[object Function]': return new Functions(o);
case '[object Number]' : return new Numbers(o);
case '[object Object]' : return new Objects(o);
case '[object String]' : return new Strings(o);
default : throw { name : "Unsupported Object", message: "Unsupported Object type: "+type};
}
}
//easy access for prototyping
Shell.Array = Arrays.prototype;
Shell.Boolean = Booleans.prototype;
Shell.String = Strings.prototype;
Shell.Function = Functions.prototype;
Shell.Date = Dates.prototype;
Shell.Number = Numbers.prototype;
Shell.Object = Objects.prototype;
//global access
this._nativeWrapper = Shell;
})(window);
A few things you'd want to add to this are probably methods for chaining and for applying a prototype extension to all of the factory objects at once. You'll also want to make sure that if you write an extender for copying properties onto the Shell's prototype or any of the factory object that you do so in a manner that accounts for getters and setters.
Performance-wise, adding a method to the String prototype is no different than adding a method to any other object. I also ran some tests and having a custom method on there did not appear to slow down the execution of any native String methods -- i.e., adding 'someOtherFunc' to String.prototype did not cause 'indexOf' to run any slower.
Of course, your JavaScript functions will be slower than those native versions, so if you add a "trim" function to older browsers those with a native trim function will run it many times faster than those without. That goes without saying.
As other people have pointed out, you can run into collision problems when you add too many functions to the core JavaScript object's prototypes; over time, other frameworks might want to add the same function and a native function with the same name might even come out. For that reason, I only like to use this to add support for modern web standards to older browsers, such as adding 'trim' to String.prototype if String.prototype.trim doesn't already natively exist. And if you do this, make sure your function behaves identically to the modern standard, so other libraries that use it don't get choked up.
If you want to add entirely new features that aren't actually part of a new standard like ECMAScript 5, it's usually better to add them to a utility object or make them normal functions. That doesn't make them run any faster; it just makes your code easier to maintain years later.
精彩评论