Extend, but for objects instead of classes - javascript

In software, we usually use the word 'extends' to refer to the subclassing of a superclass, but is there good terminology to use when 'extending' the properties of an object instead of a class in a systematic way?
for example, in JavaScript, if I have an object like so:
var foo = {
property1:'',
property2:''
}
then I have:
var bar = {
property3:''
}
if I add bar's properties to foo's properties, this is what I mean.

For whatever reason, the terminology extend has been adopted for adding the properties in one object to those in another. jQuery does this, but it probably wasn't the first. Underscore uses the same terminology:
_.extend(myObj, {newProp1: 1})
$.extend(myObj, {newProp1: 1})
Ember, on the other hand, uses extend in the subclassing sense, and the API for adding properties is Ember.merge.
The ES6 version is called assign:
Object.assign(myObj, {newProp1: 1})
There is no standard terminology and no standard way to differentiate the notions of extending an object with new properties and extending a class in the sense of subclassing it.

You may call that merging or extending. You can "extend" an object with another with a function like this :
function merge(obj1, obj2) {
for(var key in obj2) {
obj1[key] = obj2[key];
}
}
PS. Prototypal inheritance is your friend.

Related

How can I make a sub-function for a pre-existing data type? [duplicate]

I was working on an AJAX-enabled asp.net application.
I've just added some methods to Array.prototype like
Array.prototype.doSomething = function(){
...
}
This solution worked for me, being possible reuse code in a 'pretty' way.
But when I've tested it working with the entire page, I had problems..
We had some custom ajax extenders, and they started to behave as the unexpected: some controls displayed 'undefined' around its content or value.
What could be the cause for that? Am I missing something about modifing the prototype of standart objects?
Note: I'm pretty sure that the error begins when I modify the prototype for Array. It should be only compatible with IE.
While the potential for clashing with other bits o' code the override a function on a prototype is still a risk, if you want to do this with modern versions of JavaScript, you can use the Object.defineProperty method, e.g.
// functional sort
Object.defineProperty(Array.prototype, 'sortf', {
value: function(compare) { return [].concat(this).sort(compare); }
});
Modifying the built-in object prototypes is a bad idea in general, because it always has the potential to clash with code from other vendors or libraries that loads on the same page.
In the case of the Array object prototype, it is an especially bad idea, because it has the potential to interfere with any piece of code that iterates over the members of any array, for instance with for .. in.
To illustrate using an example (borrowed from here):
Array.prototype.foo = 1;
// somewhere deep in other javascript code...
var a = [1,2,3,4,5];
for (x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'
}
Unfortunately, the existence of questionable code that does this has made it necessary to also avoid using plain for..in for array iteration, at least if you want maximum portability, just to guard against cases where some other nuisance code has modified the Array prototype. So you really need to do both: you should avoid plain for..in in case some n00b has modified the Array prototype, and you should avoid modifying the Array prototype so you don't mess up any code that uses plain for..in to iterate over arrays.
It would be better for you to create your own type of object constructor complete with doSomething function, rather than extending the built-in Array.
What about Object.defineProperty?
There now exists Object.defineProperty as a general way of extending object prototypes without the new properties being enumerable, though this still doesn't justify extending the built-in types, because even besides for..in there is still the potential for conflicts with other scripts. Consider someone using two Javascript frameworks that both try to extend the Array in a similar way and pick the same method name. Or, consider someone forking your code and then putting both the original and forked versions on the same page. Will the custom enhancements to the Array object still work?
This is the reality with Javascript, and why you should avoid modifying the prototypes of built-in types, even with Object.defineProperty. Define your own types with your own constructors.
There is a caution! Maybe you did that: fiddle demo
Let us say an array and a method foo which return first element:
var myArray = ["apple","ball","cat"];
foo(myArray) // <- 'apple'
function foo(array){
return array[0]
}
The above is okay because the functions are uplifted to the top during interpretation time.
But, this DOES NOT work: (Because the prototype is not defined)
myArray.foo() // <- 'undefined function foo'
Array.prototype.foo = function(){
return this[0]
}
For this to work, simply define prototypes at the top:
Array.prototype.foo = function(){
return this[0]
}
myArray.foo() // <- 'apple'
And YES! You can override prototypes!!! It is ALLOWED. You can even define your own own add method for Arrays.
You augmented generic types so to speak. You've probably overwritten some other lib's functionality and that's why it stopped working.
Suppose that some lib you're using extends Array with function Array.remove(). After the lib has loaded, you also add remove() to Array's prototype but with your own functionality. When lib will call your function it will probably work in a different way as expected and break it's execution... That's what's happening here.
Using Recursion
function forEachWithBreak(someArray, fn){
let breakFlag = false
function breakFn(){
breakFlag = true
}
function loop(indexIntoSomeArray){
if(!breakFlag && indexIntoSomeArray<someArray.length){
fn(someArray[indexIntoSomeArray],breakFn)
loop(indexIntoSomeArray+1)
}
}
loop(0)
}
Test 1 ... break is not called
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
})
Produces
a
b
c
d
e
f
g
Test 2 ... break is called after element c
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
if(element =="c"){breakFn()}
})
Produces
a
b
c
There are 2 problems (as mentioned above)
It's enumerable (i.e. will be seen in for .. in)
Potential clashes (js, yourself, third party, etc.)
To solve these 2 problems we will:
Use Object.defineProperty
Give a unique id for our methods
const arrayMethods = {
doSomething: "uuid() - a real function"
}
Object.defineProperty(Array.prototype, arrayMethods.doSomething, {
value() {
// Your code, log as an example
this.forEach(v => console.log(v))
}
})
const arr = [1, 2, 3]
arr[arrayMethods.doSomething]() // 1, 2, 3
The syntax is a bit weird but it's nice if you want to chain methods (just don't forget to return this):
arr
.map(x=>x+1)
[arrayMethods.log]()
.map(x=>x+1)
[arrayMethods.log]()
In general messing with the core javascript objects is a bad idea. You never know what any third party libraries might be expecting and changing the core objects in javascript changes them for everything.
If you use Prototype it's especially bad because prototype messes with the global scope as well and it's hard to tell if you are going to collide or not. Actually modifying core parts of any language is usually a bad idea even in javascript.
(lisp might be the small exception there)

How to get object itself in custom Object.prototype.xxx function?

Object.prototype.getB = function() {
// how to get the current value a
return a.b;
};
const a = {b: 'c'};
a.getB();
As you can see, I want to make a function to all Object value. And I need to get the object value in this function then do something.
Monkey Patching
What you want to do is called monkey patching — you mutate a built-in prototype.
There are many wrong ways to do it, and it should be avoided entirely, because it has negative Web compatibility impacts.
I will, however, demonstrate how this can be done in a way that matches existing prototype features most closely.
In your case, the function body should return this.b.
In functions called as methods, you can get the object itself with the this keyword.
See How does the "this" keyword work? (section 4: “Entering function code”, subsection “Function properties”) for more details.
You correctly added the method to Object.prototype.
See Inheritance and the prototype chain for more details.
The tools
There is a number of tools involved when reasoning about monkey-patching:
Checking own property existence
Using property descriptors
Using the correct function kind
Getters and setters
Let’s assume you’re trying to implement theMethod on TheClass.
1. Checking own property existence
Depending on your use case you may want to check if the method you want to introduce already exists.
You can do that with Object.hasOwn; this is quite a new method, but in older environments it can simply be replaced by Object.prototype.hasOwnProperty.call.
Alternatively, use hasOwnProperty normally, but be aware that if you or someone else monkey-patched the hasOwnProperty method itself, this may lead to incorrect results.
Note that in does not check for own properties, exclusively, but for inherited properties as well, which isn’t (necessarily) what you want when you’re about to create an own property on an object.
Also, note that if(TheClass.prototype.theMethod) is not a property existence check; it’s a truthiness check.
Code samples
if(Object.hasOwn(TheClass.prototype, "theMethod")){
// Define the method.
}
if(Object.prototype.hasOwnProperty.call(TheClass.prototype, "theMethod")){
// Define the method.
}
if(TheClass.prototype.hasOwnProperty("theMethod")){
// Define the method.
}
2. Using property descriptors
You can choose the property descriptor however you like, but existing methods are writable, configurable, and non-enumerable (the last of which is the default when using defineProperty).
defineProperties can be used to define multiple properties in one go.
When simply assigning a property using =, the property becomes writable, configurable, and enumerable.
Code samples
// Define the method:
Object.defineProperty(TheClass.prototype, "theMethod", {
writable: true,
configurable: true,
value: function(){}
});
// Define the method:
Object.defineProperties(TheClass.prototype, {
theMethod: {
writable: true,
configurable: true,
value: function(){}
}
});
3. Using the correct function kind
JavaScript has four major kinds of functions which have different use cases.
“Is invokable” means that it can be called without new and “Is constructable” means that it can be called with new.
Function kind
Example
Is invokable
Is constructable
Has this binding
Arrow function
() => {}
Yes
No
No
Method
({ method(){} }).method
Yes
No
Yes
Class
(class{})
No
Yes
Yes
function function
(function(){})
Yes
Yes
Yes
What we’re looking for is a method that can be called (without new) and has its own this binding.
We could use functions, but, looking at existing methods, not only is new "HELLO".charAt(); strange, it also doesn’t work!
So the method should also not be constructable.
Therefore proper Methods are what we’re looking for.
Note that this obviously depends on your use case.
For example, if you want a constructable function, by all means, use a class instead.
Code sample
We go back to the previous code sample and instead of function(){} use a method definition.
// Define the method:
Object.defineProperty(TheClass.prototype, "theMethod", {
writable: true,
configurable: true,
value: {
theMethod(){
// Do the thing.
}
}.theMethod
});
Why bother with 2. and 3.?
The goal of the enumerability and constructability considerations is to create something that has the same “look and feel” as existing, built-in methods.
The difference between those and a naive implementation can be demonstrated using this snippet:
class TheClass{}
TheClass.prototype.theMethod = function(){};
Let’s compare this to a different, built-in method, like String.prototype.charAt:
Code snippet
Naive example
Built-in example
thePrototype
Is TheClass.prototype
Is String.prototype
theMethod
Is TheClass.prototype.theMethod
Is String.prototype.charAt
for(const p in thePrototype){ console.log(p); }
"theMethod" will be logged at some point.
"charAt" will never be logged.
new theMethod
Creates an instance of theMethod.
TypeError: theMethod is not a constructor.
Using the tools from subsections 2 and 3 make it possible to create methods that behave more like built-in methods.
4. Getters and setters
An alternative is to use a getter. Consider this:
const arr = [
"a",
"b",
"c",
];
console.log(arr.indexOfB); // 1
How would an indexOfB getter on the Array prototype look like?
We can’t use the above approach and replace value by get, or else we’ll get:
TypeError: property descriptors must not specify a value or be writable when a getter or setter has been specified
The property writable needs to be removed entirely from the descriptor.
Now value can be replaced by get:
Object.defineProperty(Array.prototype, "indexOfB", {
configurable: true,
get: {
indexOfB(){
return this.indexOf("b");
}
}.indexOfB
});
A setter can also be specified by adding a set property to the descriptor:
Object.defineProperty(Array.prototype, "indexOfB", {
configurable: true,
get: {
indexOfB(){
return this.indexOf("b");
}
}.indexOfB,
set: {
indexOfB(newValue){
// `newValue` is the assigned value.
// Use `this` for the current Array instance.
// No `return` necessary.
}
}.indexOfB
});
Web compatibility impact
There are a few reasons why anyone would want to extend built-in prototypes:
You got a brilliant idea yourself for a new feature to be added to all instances of whatever class you’re extending, or
You want to backport an existing, specified feature to older browsers.
If you extend the target object, there are two options to consider:
If the property doesn’t exist, supply it, otherwise, leave the existing property in place, or
Always replace the property with your own implementation, no matter if it exists or not.
All approaches mostly have disadvantages:
If you or someone else invented their own feature, but a standard method comes along which has the same name, then these features are almost guaranteed to be incompatible.
If you or someone else try to implement a standard feature in order to backport it to browsers that don’t support it, but don’t read the specification and “guess” how it works, then the polyfilled feature is almost guaranteed to be incompatible with the standard implementation.
Even if the spec is followed closely, who will make sure to keep up with spec changes?
Who will account for possible errors in the implementation?
If you or someone else choose to check if the feature exists before overriding it, then there’s a chance that as soon as someone with a browser which supports the feature visits your page, suddenly everything breaks because the implementations turn out to be incompatible.
If you or someone else choose to override the feature regardless, then at least the implementations are consistent, but then migration to the standard feature may be difficult.
If you write a library that is used a lot in other software, then the migration cost becomes so large that the standard itself has to change; this is why Array.prototype.contains had to be renamed to Array.prototype.includes[Reddit] [ESDiscuss] [Bugzilla] [MooTools], and Array.prototype.flatten could not be used and had to be named Array.prototype.flat instead[Pull request 1] [Pull request 2] [Bugzilla].
In other words, this is the reason we can’t have nice things.
Also, your library may not be interoperable with other libraries.
Alternatives
The simplest alternative is to define your own plain function:
const theMethod = (object) => object.theProperty; // Or whatever.
const theProperty = theMethod(theObject);
You could also consider a Proxy.
This way you can dynamically query the property and respond to it.
Let’s say you have an object with properties a through z and you want to implement methods getA through getZ:
const theProxiedObject = new Proxy(theObject, {
get(target, property, receiver){
const letter = property.match(/^get(?<letter>[A-Z])$/)?.groups?.letter.toLowerCase();
if(letter){
return () => target[letter];
}
return Reflect.get(target, property, receiver);
}
});
console.assert(theProxiedObject.getB() === theProxiedObject.b);
You could also extend your object’s prototype using another class, and use this instead:
class GetterOfB extends Object{
b;
constructor(init){
super();
Object.assign(this, init);
}
getB(){
return this.b;
}
}
const theObject = new GetterOfB({
b: "c"
});
const theB = theObject.getB();
All you have to keep in mind is to not modify things you didn’t define yourself.

Method Added to JavaScript Object Class Appears when Traversing through Given Object

In my journey to become stronger in JavaScript, I have taken up a challenge to add a method, myMethod(), to the JavaScript Object class that can be called on a given Object, myObject, in order to manipulate its contents.
I have gotten as far as adding myMethod() to the Object prototype and traversing through myObject via myObject.myMethod(); however, I'm running into a curious problem: at the end of the given object, myMethod() is printed as an value of myObject even though, to my knowledge, it should not be.
Object.prototype.myMethod = function()
{
for (var key in this)
{
console.log(this[key]);
}
}
function processData(input)
{
//Enter your code here
var myObject = JSON.parse("{ \"myParam\": \"myValue\", \"anotherParam\": 123 }");
myObject.myMethod();
}
The following is the output of this code:
myValue
123
[Function]
Changing myObject[key] to myObject[key].toString() has the following output:
myValue
123
function ()
{
for (var key in this)
{
console.log(this[key].toString());
}
}
I am executing this script in WebStorm using a Node.js runtime.
The requirements of this challenge only calls for the contents of myObject, and I can't figure out how to stop myMethod() from showing up here. Is there something I'm missing?
In my journey to become stronger in JavaScript, I have taken up a challenge to add a method, myMethod(), to the JavaScript Object class that can be called on a given Object, myObject, in order to manipulate its contents.
Beware that this practice is seriously frowned-upon (here in 2017, possibly more than it strictly necessary*). Extending any built-in prototype is a bit fraught, but extending Object.prototype is particularly problematic since, of course, almost all objects inherit from it.
But if you're going to extend a prototype, it's important to add a non-enumerable property via Object.defineProperty or similar:
Object.defineProperty(Object.prototype, "myMethod", {
value: function() { /* ... */ }
});
The default for enumerable is false, so it won't show up in for-in loops, Object.keys arrays, etc.
* The "don't extend built-in prototypes" mantra started before ES5's introduction of a way of defining non-enumerable properties (e.g., defineProperty). Now that we can define non-enumerable properties, the chief concern is inter-script conflict, each trying to use the same name for something, or conflict with new features as they're added to JavaScript.
Use Object.defineProperty().
The Object class is used in a lot of libraries and frameworks and therefore is best left alone, but can be useful for things such as poly-fills for browser compatability.
if (!Object.prototype.myMethod) {
Object.defineProperty(Object.prototype, 'myMethod', {
value: function() { /* customer code here */ }
})
}

inheritance using underscore

I've been given a class -
Zoo.Controller = (function() {
function Controller() {}
Controller.prototype.params = {};
Controller.prototype.set_params = function(params) {
this.params = params;
return this;
};
return Controller;
})();
and I want to inherit from that class using _.extend
Zoo.Controllers.WhaleController = _.extend({
new: function () {
// do something
}
}, Zoo.Controller);
When I try to instantiate that class like so...
this.whale_controller = new Zoo.Controllers.WhaleController();
I get -
Uncaught TypeError: object is not a function
Is it possible to do what I'm trying? I've read multiple articles on inheritance in JS, but had assumed that the Underscore library had it solved for me.
As Bergi pointed out; it isn't hard to inherit in JavaScript. You should know what a constructor function does and what prototype is used for. This answer may help with that, I tried to demonstrate prototype through simple and hopefully easy to understand examples. You can copy and paste the code in your browsers JS commandline (in the console) and change it to see if you understand how prototype behaves in JavaScript.
To inherit from ZooController you can:
Zoo.Controllers.WhaleController = function(args){
Zoo.Controller.apply(this,arguments);//re use Zoo.Controller constructor
//and initialize instance variables
//instance specific members of Whale using an args object
this.weitht=args.weight||4;
this.wu=args.weightUnit||wu.metricTon;
//Zoo.Controller.call(this,arg1,arg2); can be used too but I usually use
// an args object so every function can pick out and mutate whatever they want
// for example: var w = new WhaleController({weight:3,weightUnit:wu.metricTon});
// now it looks more like pythons optional arguments: fn(spacing=15, object=o)
};
//set Zoo.controller.prototype to a shallow copy of WhaleController.prototype
//may have to polyfill the Object.create method if you want to support older browsers
Zoo.Controllers.WhaleController.prototype=Object.create(Zoo.Controller.prototype);
//repair constructor
Zoo.Controllers.WhaleController.prototype.constructor=Zoo.Controllers.WhaleController;
//extend Zoo.controller.prototype.set_params
Zoo.Controllers.WhaleController.prototype.set_params=function(){
//re use parent set_params
Zoo.Controller.prototype.set_params.apply(this,arguments);
//and do something extra
console.log("extra in set_params from WhaleController");
};
//WhaleController own function
Zoo.Controllers.WhaleController.prototype.whaleSpecific=function(){
//funciton specific to WhaleController
};
Polyfill for Object.create here.
I was wondering this myself, and this is what I came up with.
Define the parent
var parentObj = function(parentMemo) {
console.log(parentMemo);
};
parentObj.prototype = {
parentCall : function() {
console.log('parentCall');
}
}
Define the child
var childObj = function(childMemo, parentMemo) {
parentObj.call(this, parentMemo);
console.log(childMemo);
};
_.extend(childObj.prototype, parentObj.prototype, {
childCall : function() {
console.log('childCall');
}
});
Construct a new a child to see the results
var newChild = new childObj("Constructing Child", "Constructing Parent");
newChild.childCall();
newChild.parentCall();
Console Results:
Constructing Child
Constructing Parent
childCall
parentCall
I've read multiple articles on inheritance in JS, but had assumed that the Underscore library had it solved for me.
No, Underscore does have no helper functions for prototypical inheritance. Read the docs on what extend does:
_.extend(destination, *sources): Copy all of the properties in the source objects over to the destination object, and return the destination object. It's in-order, so the last source will override properties of the same name in previous arguments.
Most interestingly, it does not return a function, but its first argument (which is a plain object).
So get back to the articles you've read, and choose a framework that does actually have an inherit function or implement the inheritance yourself - it's not hard.
John Resig has a good blog post on implementing Javascript inheritance that may be useful to you as it contains a solution for prototype inheritance, whereas Underscore extend is designed to extend simple Javascript objects.
As others have explained, underscore's extend method creates (very) shallow copies of object instances and doesn't preserve prototype chains. However I recently came up against a small library — Compose.js — whose wider remit is to provide a more flexible API for JS's OO properties.
The second example in the readme seems to deal with your use case almost exactly — I believe in your situation it would be invoked as follows:
Zoo.Controllers.WhaleController = Compose( Zoo.Controller, { new: function () {
// do something
} );
You could reuse the extend() function used by backboneJs. Its a quite simple function that uses _.extend() too
http://backbonejs.org/docs/backbone.html#section-208
Then attach it to your Controller prototype so you could do something like:
var MyController = Controller.extend({ /* your attributes, methods */ });
hope this helps

Extending core types without modifying prototype

How does one extend core JavaScript types (String, Date, etc.) without modifying their prototypes? For example, suppose I wanted to make a derived string class with some convenience methods:
function MyString() { }
MyString.prototype = new String();
MyString.prototype.reverse = function() {
return this.split('').reverse().join('');
};
var s = new MyString("Foobar"); // Hmm, where do we use the argument?
s.reverse();
// Chrome - TypeError: String.prototype.toString is not generic
// Firefox - TypeError: String.prototype.toString called on incompatible Object
The error seems to originate from String base methods, probably "split" in this case, since its methods are being applied to some non-string object. But if we can't apply the to non-string objects then can we really reuse them automatically?
[Edit]
Obviously my attempt is flawed in many ways but I think it demonstrates my intent. After some thinking, it seems that we can't reuse any of the String prototype object's functions without explicitly calling them on a String.
Is it possible to extend core types as such?
2 years later: mutating anything in global scope is a terrible idea
Original:
There being something "wrong" with extending native prototypes is FUD in ES5 browsers.
Object.defineProperty(String.prototype, "my_method", {
value: function _my_method() { ... },
configurable: true,
enumerable: false,
writeable: true
});
However if you have to support ES3 browsers then there are problems with people using for ... in loops on strings.
My opinion is that you can change native prototypes and should stop using any poorly written code that breaks
Update: Even this code does not fully extend the native String type (the length property does not work).
Imo it's probably not worth it to follow this approach. There are too many things to consider and you have to invest too much time to ensure that it fully works (if it does at all). #Raynos provides another interesting approach.
Nevertheless here is the idea:
It seems that you cannot call String.prototype.toString on anything else than a real string. You could override this method:
// constructor
function MyString(s) {
String.call(this, s); // call the "parent" constructor
this.s_ = s;
}
// create a new empty prototype to *not* override the original one
tmp = function(){};
tmp.prototype = String.prototype;
MyString.prototype = new tmp();
MyString.prototype.constructor = MyString;
// new method
MyString.prototype.reverse = function() {
return this.split('').reverse().join('');
};
// override
MyString.prototype.toString = function() {
return this.s_;
};
MyString.prototype.valueOf = function() {
return this.s_;
};
var s = new MyString("Foobar");
alert(s.reverse());
As you see, I also had to override valueOf to make it work.
But: I don't know whether these are the only methods you have to override and for other built-in types you might have to override other methods. A good start would be to take the ECMAScript specification and have a look at the specification of the methods.
E.g. the second step in the String.prototype.split algorithm is:
Let S be the result of calling ToString, giving it the this value as its argument.
If an object is passed to ToString, then it basically calls the toString method of this object. And that is why it works when we override toString.
Update: What does not work is s.length. So although you might be able to make the methods work, other properties seem to be more tricky.
First of all, in this code:
MyString.prototype = String.prototype;
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
the variables MyString.prototype and String.prototype are both referencing the same object! Assigning to one is assigning to the other. When you dropped a reverse method into MyString.prototype you were also writing it to String.prototype. So try this:
MyString.prototype = String.prototype;
MyString.prototype.charAt = function () {alert("Haha");}
var s = new MyString();
s.charAt(4);
"dog".charAt(3);
The last two lines both alert because their prototypes are the same object. You really did extend String.prototype.
Now about your error. You called reverse on your MyString object. Where is this method defined? In the prototype, which is the same as String.prototype. You overwrote reverse. What is the first thing it does? It calls split on the target object. Now the thing is, in order for String.prototype.split to work it has to call String.prototype.toString. For example:
var s = new MyString();
if (s.split("")) {alert("Hi");}
This code generates an error:
TypeError: String.prototype.toString is not generic
What this means is that String.prototype.toString uses the internal representation of a string to do its thing (namely returning its internal primitive string), and cannot be applied to arbitrary target objects that share the string prototype. So when you called split, the implementation of split said "oh my target is not a string, let me call toString," but then toString said "my target is not a string and I'm not generic" so it threw the TypeError.
If you want to learn more about generics in JavaScript, you can see this MDN section on Array and String generics.
As for getting this to work without the error, see Alxandr's answer.
As for extending the exact built-in types like String and Date and so on without changing their prototypes, you really don't, without creating wrappers or delegates or subclasses. But then this won't allow the syntax like
d1.itervalTo(d2)
where d1 and d2 are instances of the built-in Date class whose prototype you did not extend. :-) JavaScript uses prototype chains for this kind of method call syntax. It just does. Excellent question though... but is this what you had in mind?
You got only one part wrong here. MyString.prototype shouldn't be String.prototype, it should be like this:
function MyString(s) { }
MyString.prototype = new String();
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
var s = new MyString("Foobar");
s.reverse();
[Edit]
To answer your question in a better way, no it should not be possible.
If you take a look at this: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor it explains that you can't change the type on bools, ints and strings, thus they cannot be "subclassed".
I think the basic answer is you probably can't. What you can do is what Sugar.js does - create an object-like object and extend from that:
http://sugarjs.com/
Sugar.js is all about native object extensions, and they do not extend Object.prototype.

Categories