Implementing prototype method - javascript

If I implemented a method x on a String like :
String.prototype.x = function (a) {...}
And then the new version of javascript actually implements the x method, but on the another way, either returning something different than my implementation or function with more/less arguments than my implementation. Will this break my implementation and override it?

You'll overwrite the default implementation.
Any code that uses it will use yours instead.
There was a proposal for scoped extension methods and it was rejected because it was too expensive computationally to implement in JS engines. There is talk about a new proposal (protocols) to address the issue. ES6 symbols will also give you a way around that (but with ugly syntax).
However, that's not the punch - here's a fun fact no one is going to tell you.
No one is ever going to implement a method called x on String.prototype
You can implement it and get away with it. Seriously, prollyfilling and polyfilling is a viable, expressive and interesting solution to many use cases. If you're not writing a library I think it's acceptable.

No, you'll be overriding the default implementation of said function, from the point at which you've declared/defined it. The "new" implementation will function in its native behavior, until your implementation's defined.
var foo = 'some arbitrary string';
console.log(foo.indexOf('s')); // logs [0]
String.prototype.indexOf = function(foo, bar) { return 'foo'; };
console.log(foo.indexOf()); // logs [foo]
Illustration: http://jsfiddle.net/Z4Fq9/

Your code will be overriding the default implementation.
However if the interface of your method is not compatible with the standard one the libraries you may use could depend on the standard behavior so the program as a whole could break anyway with newer versions of the libraries.
In general is a bad idea doing something that could break if others do the same: what if another library thinks it's a good idea to add a method x to the standard string object prototype? Trying to avoid conflicts is a must for libraries but it's also good for applications (and if an application is written nicely then a lot of its code is probably quite similar to a library, and may evolve in a library later).
This kind of "patching" makes sense only to provide the a standard method for broken or old javascript implementations where that method is absent. Patching standard prototypes just because you can is a bad idea and will make your code a bad neighbor with which is difficult to share a page.

If the implementation of x is from a new version of Javascript, it's part of the core, therefore when you write String.prototype.x... it will be already there, and you will overwrite it.
Best practice in this kind of things is to write
if( !String.prototype.x ){
String.prototype.x = function ...
//your

Related

Javascript defaultdict without library

I'd like something like Python's defaultdict in Javascript, except without using any libraries. I realize this won't exist in pure Javascript. However, is there a way to define such a type in a reasonable amount of code (not just copying-and-pasting some large library into my source file) that won't hit undesirable corner cases later?
I want to be able to write the following code:
var m = defaultdict(function() { return [] });
m["asdf"].push(0);
m["qwer"].push("foo");
Object.keys(m).forEach(function(value, key) {
// Should give me "asdf" -> [0] and "qwer" -> ["foo"]
});
I need this to work on recent versions of Firefox, Chrome, Safari, and ideally Edge.
Again, I do not want to use a library if at all possible. I want a way to do this in a way that minimizes dependencies.
Reasons why previous answers don't work:
This answer uses a library, so it fails my initial criteria. Also, the defaultdict it provides doesn't actually behave like a Javascript object. I'm not looking to write Python in Javascript, I'm looking to make my Javascript code less painful.
This answer suggests defining get. But you can't use this to define a defaultdict over collection types (e.g. a map of lists). And I don't think the approach will work with Object.keys either.
This answer mentions Proxy, but it's not obvious to me how many methods you have to implement to avoid having holes that would lead to bad corner cases later. Writing all of the Proxy methods certainly seems like a pain, but if you skip any methods you might cause painful bugs for yourself down the road if you try to use something you didn't implement a handler for. (Bonus question: What is the minimal set of Proxy methods you'd need to implement to avoid any such holes?) On the other hand, the suggested getter approach doesn't follow standard object syntax, and you also can't do things like Object.keys.
You really seem to be looking for a proxy. It is available in the modern browsers you mention, is not a library, and is the only technology allowing you to keep the standard object syntax. Using a proxy is actually quite simple, all you need to overwrite is the get trap that should automatically create non-existing properties:
function defaultDict(createValue) {
return new Proxy(Object.create(null), {
get(storage, property) {
if (!(property in storage))
storage[property] = createValue(property);
return storage[property];
}
});
}
var m = defaultDict(function() { return [] });
m["asdf"].push(0);
m["qwer"].push("foo");
Object.keys(m).forEach(console.log);

Will Function.prototype.bind() always be slow?

I am writing an open source javascript library, and I use .bind() method heavily, because I have an idea that object-oriented code looks more clear then. (debatable, though)
Example
A1:
var that = this;
setTimeout(function () {
that.method();
}, 0);
vs
B1:
setTimeout(this.method.bind(this), 0);
Or, a more practical code portion
A2:
remoteDataSource.getData(function (a, b, c, d) {
obj.dataGetter(a, b, c, d);
})
vs B2:
remoteDataSource.getData(obj/* or prototype */.dataGetter.bind(obj));
I use a non-native bind for older browsers, and everything went perfect until I opened a jsperf benchmark for bind.
It looks like code using bind is 100 times slowlier. Now, before to rewrite all my library, I have a question for those who are familiar with javascript engines:
Is there a probability that, being a new feature, bind will get optimized
soon, or there is no chance because of JavaScript architecture limits?
First of all, fixed jsperf http://jsperf.com/bind-vs-emulate/13.
=You should not recreate static functions inside the benchmark. That is not realistic because in real code static functions are only created once.
You can see that var self = this pattern is still about 60% faster. But it requires the function definition to be inlined where as you can bind from anywhere and therefore have better maintainability.
Well no, the built-in bind semantics are ridiculously convoluted.
When I bind, I just want this:
function bind(fn, ctx) {
return function bound() {
return fn.apply(ctx, arguments);
};
}
If I wanted to pre-apply arguments or use some deep constructor black magic, I would want a totally different function for that. I have no idea why any of this was included in bind.
<rant>Btw, the same problem is with almost anything introduced in ES5, punishing the common case by forcing implementations to handle some theoretical edge case that is not plausibly relevant to anyone in practice. The next language version is continuing on the same path.</rant>
The emulated bind doesn't even try to emulate bind at all. And even if you try to emulate it, you will not be able
to do it completely so that's just not fair.
So with everything else equal* the built-in bind cannot be faster than common sense custom bind which just binds.
*In JITs user code has no significant disadvantage to built-in code. In fact both SM and V8 implement many built-ins
in Javascript.
Currently, late 2013, the best possible solution will be implementing handmade versions of Function.prototype.bind and either override the vendor's "native" (not being truly native) method with your own javascript code, or use your own myBind.
Function.prototype.apply is rather fast, and Array slicing, concating and shifting is slow, so you better use apply instead if bind, or minimize arguments manipulations in myBind function. That will leave you without the features of parameters pre-filling.
So I see no need in rewriting everything back to closures (ugly var that = this;). Let the functional nature of javascript win.
More details and working code examples here:
http://jsperf.com/function-bind-performance/4
http://jsperf.com/function-bind-performance/5
http://jsperf.com/bind-vs-emulate/4 .. 10.
Summarizing: workarounds found are not so bad. Use them bravely. If you use not fully featured bind, don't go too far from original conception as I have found no reasons it's not implemented in C yet. It's a question of time.

How can I prove that my JavaScript files are in the scope of a specific JS or ECMA version?

Let's say you would get a bunch of .js files and now it is your job to sort them into groups like:
requires at least JavaScript 1.85
requires at least E4X (ECMAScript 4 EX)
requires at least ECMAScript 5
or something like this.
I am interested in any solution, but especially in those which work using JavaScript or PHP. This is used for creation of automated specifications, but it shouldn't matter - this is a nice task which should be easy to solve - however, I have no idea how and it is not easy for me. So, if this is easy to you, please share any hints.
I would expect something like this - http://kangax.github.com/es5-compat-table/# - just not for browsers, rather for a given file to be checked against different implementations of JavaScript.
My guess is, that each version must have some specifics, which can be tested for. However, all I can find is stuff about "what version does this browser support".
PS: Don't take "now it is your job" literally, I used it to demonstrate the task, not to imply that I expect work done for me; while in the progress of solving this, it would be just nice to have some help or direction.
EDIT: I took the easy way out, by recquiring ECMAScript 5 to be supported at least as good as by the current FireFox for my projekt to work as intendet and expected.
However, I am still intereseted in any solution-attemps or at least an definite answer of "is possible(, with XY)" or "is not possible, because ..."; XY can be just some Keyword, like FrameworkXY or DesignPatternXY or whatever or a more detailed solution of course.
Essentially you are looking to find the minimum requirements for some javascript file. I'd say that isn't possible until run time. JavaScript is a dynamic language. As such you don't have compile time errors. As a result, you can't tell until you are within some closure that something doesn't work, and even then it would be misleading. Your dependencies could in fact fix many compatibility issues.
Example:
JS File A uses some ES5 feature
JS File B provides a shim for ES5 deficient browsers or at least mimics it in some way.
JS File A and B are always loaded together, but independently A looks like it won't work.
Example2:
Object.create is what you want to test
Some guy named Crockford adds create to Object.prototype
Object.create now works in less compatible browsers, and nothing is broken.
Solution 1:
Build or find a dependency map. You definitely already have a dependency map, either explicitly or you could generate it by iterating over you HTML files.
Run all relevant code paths in environments with decreasing functionality (eg: ES5, then E4X, then JS 1.x, and so forth).
Once a bundle of JS files fail for some code path you know their minimum requirement.
Perhaps you could iterate over the public functions in your objects and use dependency injection to fill in constructors and methods. This sounds really hard though.
Solution 2:
Use webdriver to visit your pages in various environments.
Map window.onerror to a function that tells you if your current page broke while performing some actions.
On error you will know that there is a problem with the bundle on the current page so save that data.
Both these solutions assume that you always write perfect JS that never has errors, which is something you should strive for but isn't realistic. This might; however, provide you with some basic "smoke testing" though.
This is not possible in an exact way, and it also is not a great way of looking at things for this type of issue.
Why its not possible
Javascript doesn't have static typing. But properties are determined by the prototype chain. This means that for any piece of code you would have to infer the type of an object and check along the prototype chain before determining what function would be called for a function call.
You would for instance, have to be able to tell that $(x).bind() o $(x).map are not making calls to the ecmascript5 map or bind functions, but the jQuery ones. This means that you would really have to parse out the whole code and make inferences on type. If you didn't have the whole code base this would be impossible. If you had a function that took an object and you called bind, you would have no idea if that was supposed to be Function.prototype.bind or jQuery.bind because thats not decided till runtime. In fact its possible (though not good coding practice) that it could be both, and that what is run depends on the input to a function, or even depends on user input. So you might be able to make a guess about this, but you couldn't do it exactly.
Making all of this even more impossible, the eval function combined with the ability to get user input or ajax data means that you don't even know what types some objects are or could be, even leaving aside the issue that eval could attempt to run code that meets any specification.
Here's an example of a piece of code that you couldn't parse
var userInput = $("#input").val();
var objectThatCouldBeAnything = eval(userInput);
object.map(function(x){
return !!x;
});
There's no way to tell if this code is parsing a jQuery object in the eval and running jQuery.map or producing an array and running Array.prototype.map. And thats the strength and weakness of a dynamically typed language like javascript. It provides tremendous flexibility, but limits what you can tell about the code before run time.
Why its not a good strategy
ECMAScript specifications are a standard, but in practice they are never implemented perfectly or consistently. Different environments implement different parts of the standard. Having a "ECMAScript5" piece of code does not guarantee that any particular browser will implement all of its properties perfectly. You really have to determine that on a property by property basis.
What you're much better off doing is finding a list of functions or properties that are used by the code. You can then compare that against the supported properties for a particular environment.
This is still a difficult to impossible problem for the reasons mentioned above, but its at least a useful one. And you could gain value doing this even using a loose approximation (assuming that bind actually is ecmascript5 unless its on a $() wrap. Thats not going to be perfect, but still might be useful).
Trying to figure out a standard thats implemented just isn't practical in terms of helping you decide whether to use it in a particular environment. Its much better to know what functions or properties its using so that you can compare that to the environment and add polyfills if necessary.

Implementing operator overloading in Javascript via a transpiler

One of the problems, for some of us, with Javascript is the lack of operator overloading. This makes writing numeric libraries awkward. For instance, we might want to write something like:
var a = new BigInteger(5);
var b = new BigInteger(10);
var c = a + b;
A possible solution is to transpile a language with operator overloading to Javascript. While feasible -- by replacing operators by function calls and type checks -- the consensus seems to be that this is impossible without killing performance. CoffeeScript has rejected the idea for this reason:
https://github.com/jashkenas/coffee-script/issues/846
But are there really no clever solutions?
For instance, it might be possible hoist type checks out of tight loops or to use some other pipeline where modern JS compilers can optimize away added cruft when the types are numeric.
Ideas?
Are you really sure you need your big numbers to be useable by old functions written with normal numbers in mind (that use the traditional operators)? If you only need the overloading for your own convenience on functions you cave control over you might be able to get by by using a different, custom operator for bignums.
For example, you could write a compiler to safely convert
var d = a <+> b <*> c;
into
var d = (a).add((b).multiply(c));
or perhaps, if you want automatic conversions...
var d = toBignum(a).add(toBignum(b).multiply(toBignum(c)));
I don't really see you being able to force overloading on an existing implementation without a big hassle. While you could teoretically replace all occurences of + with <+> and so on, current Javascript implementations are not optimized for this and I don't even want to start thinking what would happen if you tried to pass a bignum to one of the native C++ functions that are under the hood.
edit: Not needing to override the base integer class is the important point here (note how in the link you gave, overriding is the first thing the guy wants...). I don't think you will be able to find some kind "magic" optimization though as you have no control over which of the many JS implementations is being used by the client.
If you really don't like a custom operator like <+> the only way to distinguish a normal + operator (you shoudln't meddle with) from a fancy + operator (you want to do bignum stuff with) would be forcing some kind of ad-hoc typing system on top of Javascript, perhaps via comments, custom syntax or (as mentioned in a comment) hungarian notation. Just settling for a custom operator name you hate less would be less hackish, IMO.
Have a look how Scala implemented Operator Overloading:
They defined that every operator is a method call on an object, so your example would be:
var c = a["+"](b);
If you stop here, you could trivially implement method overload, the function would have to check the values passed by param. If you want to develop a better solution take Odersky's Programing in Scala book and some time to read all their ideas how they've solved the problem (which is a very nice solution!)

Extending native elements in JavaScript via prototype?

Would you consider extending the native elements via the prototype dangerous? I see some frameworks such as Prototype doing this so I have started to wonder if I dare to do that too.
I am worried about implementing things like addClassName and make it collide in the future in a way that I can't resolve any other way than rewriting the software and asking module authors to do the same.
I wouldn't because IMHO it might definitely make collisions soon or later and create a potential bug very difficult to be spot out.
I anyway do extend some basic simple native Javascript objects like String.trim, I'm anyway careful to always test to see if it already exists by using a simple if test:
if(!String.prototype.trim)
String.prototype.trim = function() { return this.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }
You could do the same with addClassName.
The difference is that doing it with simple function like String.trim, it's difficult that might lead to problems in future, because even if a browser engine has got String.trim (actually FF has it) well such a function is going exactly to do what my String.trim does, so you won't see differences in your web application workflow ever.
A more complex function like overriding querySelectorAll might lead to differences between how the browser implements it and your implementation. For example: the order of the returned elements might be different, the browser function returns a collection while your one an array, and other issues. So when you run your webapp on browser that does implement the querySelectorAll it might lead to having your webapp not working anymore as expected, and there try finding out the bug!!!
Maybe querySelectorAll is not the best example, but I hope I explained the concept.

Categories