Javascript and prototype inheritance issue - javascript

Is there any way to stop instances of a function from inheriting property's from each other? I was reading an article on Javascripts prototype object and read the following.
"It's important to note that the prototype is "live". Objects are passed by reference in JavaScript, and therefore the prototype is not copied with every new object instance. What does this mean in practice? It means that you can modify the prototype at any time and all objects (even those created before the modification) will inherit the changes."
Is there any way to prevent all objects from getting updated. I would like to keep the property's of each instance unique. If not are there any other methods from assigning property's to functions? Here's some code i'm working with. It allows me to display animated sprites in three.js but when I create new instances of the function the instances jump to the frame the new instance calls from. So there all displaying the same frame. i figured if I can turn of the inheritance It should be ok. Sorry if it's sloppy I removed a bunch of stuff that's not needed for the question.
function slowToStopFunc(texture, tilesHoriz, tilesVert, numTiles, tileDispDuration) {
this.tilesHorizontal = tilesHoriz;
this.tilesVertical = tilesVert;
this.numberOfTiles = numTiles;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1 / this.tilesHorizontal, 1 / this.tilesVertical );
this.tileDisplayDuration = tileDispDuration;
this.currentDisplayTime = 0;
this.currentTile = 3;
this.update3 = function( milliSec3 ) {
this.currentDisplayTime += milliSec3;
while (this.currentDisplayTime > this.tileDisplayDuration && adjustSpeed <= 2)
{
if (this.currentTile >= -1 && this.currentTile <= 14) {
this.currentTile++;
}
}
var currentColumn = this.currentTile % this.tilesHorizontal;
texture.offset.x = currentColumn / this.tilesHorizontal;
var currentRow = Math.floor( this.currentTile / this.tilesHorizontal );
texture.offset.y = currentRow / this.tilesVertical;
}
}

The nature of prototypal inheritance allows you to do this since the way property lookups are working.
When a property lookup occurs:
Does the object has someProperty? If yes return someProperty.
If the object doesn't have someProperty, check it's prototype chain and perform the same logic until it's prototype link is null.
Basically that means setting a property on an object will shadow it's inherited value naturally.
function A() {
}
A.prototype.test = 'test';
var a = new A();
a.test = 'test 2';
console.log(a.test); //not test anymore
However if you are asking if it's possible to modify a constructor's prototype without affecting the existing instances, it is possible but I do not know why you would like to do this.
Basically you just have to replace the whole prototype instance, so that newly created instances have a whole new prototype object.
function A() {}
A.prototype.test = 'test';
var a = new A();
A.prototype = {
constructor: A,
test: 'new value'
};
console.log(a.test); //test
console.log(new A().test); //new value

Did you try overriding inherited properties? Not sure how much you are familiar with object inheritance, but in general you can write over inherited properties by matching the name of properties.

Related

Instance property vs Prototype property [duplicate]

This question already has answers here:
Use of 'prototype' vs. 'this' in JavaScript?
(15 answers)
Closed last month.
In the below code,
function Person(first, last, age) {
this.firstName = first;
this.lastName = last;
this.age = age;
}
Person.prototype.planet = "Earth";
p1 = new Person("David", "Beckham", 39);
p2 = new Person("Lionel", "Messi", 30);
If multiple instances p1 p2 are created using constructor Person, then
How do I understand the difference about the property planet with property age? What difference it would make by adding property planet as this.planet in the constructor Person?
Note: Understanding prototype property
Consider situation when in the fututre we are going to change prototype property that is shared by all instances
function Person(first, last, age) {
this.firstName = first;
this.lastName = last;
this.age = age;
}
Person.prototype.planet = "Earth";
p1 = new Person("David", "Beckham", 39);
p2 = new Person("Lionel", "Messi", 30);
console.log(p1.planet) // Earth
Person.prototype.planet = "Mars"
console.log(p1.planet) // Mars
console.log(p1.planet === p2.planet) // true
Changing one property on prototype will change it in all instances
A prototype property will be part of any object created from the so-called prototype, and this includes prototype chain.
A instance property will be part of the whole instance, and in your case, it will part of any instance because you're adding it within the constructor function:
function A() {
this.x = 11;
}
var instance = new A();
instance.x = 11;
Both above cases are adding the property to the own object rather than in the prototype.
Furthermore, adding properties to the prototype has a side effect:
function A() {}
A.prototype.x = 11;
function B() {}
B.prototype = Object.create(A.prototype);
var instanceA = new A();
var instanceB = new B();
A.prototype.x = 12;
// Both "x" will hold 12
alert(instanceA.x);
alert(instanceB.x);
Learn more about prototype chain on MDN.
About some OP comment
So, In java terminology, age is an instance member and planet is a
static member. To define a static member, we use prototype property,
am I correct? –
This is a wrong statement.
Prototype properties aren't static, since prototypes are regular objects. It's just JavaScript uses prototype chain to implement inheritance and it relies in a standard property called prototype.
In JavaScript there're no statics. When you access any property, JavaScript's runtime will look for it through the prototype chain:
function A() {};
A.prototype.x = 11;
function B() {};
B.prototype = Object.create(A.prototype);
function C() {};
C.prototype = Object.create(B.prototype);
var instanceC = new C();
var x = instanceC.x;
// Once you request a property "x", the runtime will do the following process:
// 1) Is "x" in the own object? No, then 2)
// 2) Is "x" in current object's prototype? No, then 3)
// 3) Is "x" in the parent prototype? No, then 4)
// 4) And so on, until it reaches the top-level prototype, and if this has no
// "x" property, then runtime will return "undefined"
It's actually memory usage. Here are some images I have created depicting each problem.
In the image below, each instance of person is linked to the same prototype object. This saves memory if multiple instances are created pointing to the same object. However, if you change 'Earth' to 'Mars' every instance will have the same change.
In the image below each instance will point to a completely different property linked specifically to that instance. If you believe a specific planet can change names, you should do this.. otherwise use prototype because this will use more resources.

Using "Object.create" instead of "new"

Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
With only one level of inheritance, your example may not let you see the real benefits of Object.create.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB example, I don't think that your init method should be public or even exist, if you call again this method on an existing object instance, the id and name properties will change.
Object.create lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create, with an object literal using a syntax similar to the used by the Object.defineProperties and Object.defineProperty methods.
It lets you set the property attributes (enumerable, writable, or configurable), which can be really useful.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.

Generating a class from an object (JavaScript)

I'm trying to generate a class from an object in JavaScript. For example:
var Test = {
constructor: function() { document.writeln('test 1'); },
method: function() { document.writeln('test 2'); }
};
var TestImpl = function() { };
TestImpl.prototype.constructor = Test.constructor;
TestImpl.prototype.method = Test.method;
var x = new TestImpl();
x.method();
But this doesn't work: it'll only write 'test 2' (for whatever reason, constructor isn't being defined properly). Why?
I think you're doing it wrong.
Remember, JavaScript doesn't actually have classes at all. It has prototypes instead. So what you're really trying to do is create a prototype object that works like a collection of functions that you've built on another object. I can't imagine any useful purpose for this -- could you elaborate as to what you're trying to do?
Although I think you could make it work by using something like:
var TestImpl = function() {
Test.constructor.apply(this);
};
TestImpl.prototype.method = Test.method;
Your TestImpl function is the constructor. Usually you would do something like this:
var Test1 = function () {
document.writeln('in constructor');
};
Test1.prototype = {
x: 3,
method1: function() { document.writeln('x='+this.x); }
}
var y1 = new Test1();
y1.method1();
y1.x = 37;
y1.method1();
var y2 = new Test1();
y2.method1();
y2.x = 64;
y2.method1();
I think you have things a little backwards. Usually you will assign a prototype to a constructor, rather than assigning a constructor to a prototype.
The reason for assigning a method to the constructor's prototype, rather than to the "this" object inside the constructor, is that the former method creates only 1 shared function, whereas the latter method creates separate instances of a function. This is important (to keep memory allocation to a reasonable amount) if you create lots of objects each with lots of methods.
var Test = function () {
document.writeln('test 1');
this.method = function() { document.writeln('test 2'); }
};
var x = new Test();
x.method();
Javascript doesn't have a "Class" concept, It's all about prototype and the way you use them [ and you can simulate any kind of inheritance with this little neat feature. ]
In javascript "Function" plays the role of [ Class, Method and Constructor ].
so inorder to create "Class" behaviour in Javascript all you need to do is to use the power of "Function".
var A = function(){
alert('A.Constructor');
}
A.prototype = {
method : function(){
alert('A.Method');
}
}
var b = new A(); // alert('A.Constructor');
b.method(); // alert('A.Method');
now the neat thing about JS is that you can easily create "Inheritance" behaviour by using the same method. All you need to do is to connect the second class "Prototype Chain" to the first one, How?
B = function(){
this.prototype = new A(); // Connect "B"'s protoype to A's
}
B.prototype.newMethod = function() { alert('testing'); }
var b = new B();
b.method(); // Doesn't find it in B's prototype,
// goes up the chain to A's prototype
b.newMethod(); // Cool already in B's prototype
// Now when you change A, B's class would automatically change too
A.prototype.method = function(){ alert('bleh'); }
b.method(); // alert('bleh')
If you need any more references I suggest to take a look at Douglas Crockford's Site
Happy JS ing.

JavaScript: Inheritance and Constant declaration

Help,
I have this class
var jMath = {
pi2: Math.PI,
foo: function() {
return this.pi2;
}
}
I want to make the pi2 constant and i want jMath to inherit from Math object. How do I do that?
Oh amusing, scratch all that, this is the correct version:
function JMath() {
this.foo = function() {
return this.PI;
}
}
JMath.prototype = Math;
var jMath = new JMath();
alert(jMath.foo());
(which matches what the other answer is here)
(I originally tried to set the prototype using "JMath.prototype = new Math()" which is how I've seen it other places, but the above works)
Edit
Here's one way to do it as a singleton
// Execute an inline anon function to keep
// symbols out of global scope
var jMath = (function()
{
// Define the JMath "class"
function JMath() {
this.foo = function() {
return this.PI;
}
}
JMath.prototype = Math;
// return singleton
return new JMath();
})();
// test it
alert( jMath.PI );
// prove that JMath no longer exists
alert( JMath );
Consider using prototype:
function JMath() {};
JMath.prototype = {
pi2: Math.PI,
foo: function() {
return this.pi2;
}
}
var j = new JMath();
j.pi2=44; j.foo(); // returns 44
delete j.pi2; j.foo(); // now returns Math.PI
The difference between this and #altCognito's answer is that here the fields of the object are shared and all point to the same things. If you don't use prototypes, you create new and unlinked instances in the constructor. You can override the prototype's value on a per-instance basis, and if you override it and then decide you don't like the override value and want to restore the original, use delete to remove the override which merely "shadows" the prototype's value.
Edit: if you want to inherit all the methods and fields of the Math object itself, but override some things without affecting the Math object, do something like this (change the name "Constructor1" to your liking):
function Constructor1() {};
Constructor1.prototype = Math;
function JMath() {};
JMath.prototype = new Constructor1();
JMath.prototype.pi2 = JMath.prototype.PI;
JMath.prototype.foo = function() { return this.pi2; }
var j = new JMath();
j.cos(j.foo()); // returns -1
edit 3: explanation for the Constructor1 function: This creates the following prototype chain:
j -> JMath.prototype -> Math
j is an instance of JMath. JMath's prototype is an instance of Constructor1. Constructor1's prototype is Math. JMath.prototype is where the overridden stuff "lives". If you're only implementing a few instances of JMath, you could make the overridden stuff be instance variables that are setup by the constructor JMath, and point directly to Math, like #altCognito's answer does. (j is an instance of JMath and JMath's prototype is Math)
There are 2 downsides of augmenting-an-object-in-the-constructor. (Not actually downsides necessarily) One is that declaring instance fields/methods in the constructor creates separate values for each instance. If you create a lot of instances of JMath, each instance's JMath.foo function will be a separate object taking up additional memory. If the JMath.foo function comes from its prototype, then all the instances share one object.
In addition, you can change JMath.prototype.foo after the fact and the instances will update accordingly. If you make the foo function in the constructor as a per-instance method, then once JMath objects are created, they are independent and the only way to change the foo function is by changing each one.
edit 2: as far as read-only properties go, you can't really implement them from within Javascript itself, you need to muck around under the surface. However you can declare so-called "getters" which effectively act as constants:
JMath.prototype.__defineGetter__("pi2", function() { return Math.PI; });
JMath.prototype.__defineSetter__("pi2", function(){}); // NOP
var j = new JMath();
j.pi2 = 77; // gee, that's nice
// (if the setter is not defined, you'll get an exception)
j.pi2; // evaluates as Math.PI by calling the getter function
Warning: The syntax for defining getters/setters apparently is not something that IE doesn't implement nicely.
User-defined object properties can't be constant. Math (and a few other objects) is a special built-in - it has read-only properties and functions. But it's not a constructor - it's just a static object (Math.constructor === Object).
And because JavaScript has prototypal inheritance, and not classical, you can't inherit from Math. (Read more here)
What you can do, however, is define a prototype. When a property isn't found locally, the JS parser looks for that property on the current object's prototype. altCognito's current solutions shows this very well.
I'm curious about exactly what it is you're trying to achieve. Perhaps something like this is what you want?
var jMath = function()
{
const pi2 = Math.PI;
this.getPi2 = function()
{
return pi2;
}
}
var j = new jMath;
alert( j.getPi2() );

prototype and constructor object properties

I've:
function Obj1(param)
{
this.test1 = param || 1;
}
function Obj2(param, par)
{
this.test2 = param;
}
now when I do:
Obj2.prototype = new Obj1(44);
var obj = new Obj2(55);
alert(obj.constructor)
I have:
function Obj1(param) {
this.test1 = param || 1;
}
but the constructor function has been Obj2... why that?
Obj1 has become the Obj2 prototype...
Can someone explain me, in detail, the prototype chain and the constructor property
Thanks
constructor is a regular property of the prototype object (with the DontEnum flag set so it doesn't show up in for..in loops). If you replace the prototype object, the constructor property will be replaced as well - see this explanation for further details.
You can work around the issue by manually setting Obj2.prototype.constructor = Obj2, but this way, the DontEnum flag won't be set.
Because of these issues, it isn't a good idea to rely on constructor for type checking: use instanceof or isPrototypeOf() instead.
Andrey Fedorov raised the question why new doesn't assign the constructor property to the instance object instead. I guess the reason for this is along the following lines:
All objects created from the same constructor function share the constructor property, and shared properties reside in the prototype.
The real problem is that JavaScript has no built-in support for inheritance hierarchies. There are several ways around the issue (yours is one of these), another one more 'in the spirit' of JavaScript would be the following:
function addOwnProperties(obj /*, ...*/) {
for(var i = 1; i < arguments.length; ++i) {
var current = arguments[i];
for(var prop in current) {
if(current.hasOwnProperty(prop))
obj[prop] = current[prop];
}
}
}
function Obj1(arg1) {
this.prop1 = arg1 || 1;
}
Obj1.prototype.method1 = function() {};
function Obj2(arg1, arg2) {
Obj1.call(this, arg1);
this.test2 = arg2 || 2;
}
addOwnProperties(Obj2.prototype, Obj1.prototype);
Obj2.prototype.method2 = function() {};
This makes multiple-inheritance trivial as well.
Check out Tom Trenka's OOP woth ECMAscript, the "Inheritance" page. Everything from the prototype is inherited, including the constructor property. Thus, we have to unbreak it ourselves:
Obj2.prototype = new Obj1(42);
Obj2.prototype.constructor = Obj2;
Short version: ‘constructor’ doesn't do what you think, and isn't cross-browser compatible. Never use it.
Long version: Convention for prototype inheritance in JavaScript
Generally: you're getting confused due to (a) the impedence mismatch between class-based and prototype-based OO, and (b) the strangeness of JavaScript's particular rather poor interpretation of prototype-based OO.
You'll probably be happier if you find one classes-in-prototypes implementation you like and stick with that. Many libraries have one. Here's an arbitrary one I use:
Function.prototype.subclass= function() {
var c= new Function(
'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+
'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); '
);
if (this!==Object)
c.prototype= new this(Function.prototype.subclass.FLAG);
return c;
}
Function.prototype.subclass.FLAG= new Object();
And here's an example of how one might use it:
// make a new class
var Employee= Object.subclass();
// add members to it
Employee.prototype._LEGS= 2;
Employee.prototype.getLegs= function() {
return this._LEGS;
};
// optional initialiser, takes arguments from constructor
Employee.prototype._init= function(name) {
this.name= name;
};
// make a subclass
Manager= Employee.subclass();
// extend subclass method
Manager.prototype._init= function(name, importance) {
// call base class's method
Employee.prototype._init.call(this, name);
this.importance= importance;
}
// all managers are well-known to have three legs
Manager.prototype._LEGS= 3;
// create one
var jake= new Manager('Jake the Peg', 100);
Well, the constructor property is a property like any other, on the prototype (property) of Obj1. If you understand how prototypes work, this might help:
>>> obj.hasOwnProperty("constructor")
false
// obj's [[Prototype]] is Obj2.prototype
>>> Obj2.prototype.hasOwnProperty("constructor")
false
// Obj2.prototype's [[Prototype]] is Obj1.prototype
>>> Obj1.prototype.hasOwnProperty("constructor")
true
// Oh?
>>> Obj1.prototype.constructor
Obj1()
Aha! So obj has no constructor, JS goes to get it up the [[Prototype]] chain, all the way from Obj1.prototype.constructor
I'm not sure why the constructor property isn't just set on an object when you use `new'. There might be a reason, or it might just be an oversight. Either way, I tend to avoid it.

Categories

Resources