JavaScript: Inheritance and Constant declaration

谁说胖子不能爱 提交于 2021-02-08 09:38:26

问题


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?


回答1:


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 );



回答2:


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.




回答3:


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() );


来源:https://stackoverflow.com/questions/744452/javascript-inheritance-and-constant-declaration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!