JavaScript:继承和常量声明

时间:2009-04-13 16:27:08

标签: javascript inheritance constants

帮助, 我有这个班级

var jMath = {

    pi2: Math.PI,

    foo: function() {
        return this.pi2;
    }
}

我想让pi2保持不变,我希望jMath继承Math对象。我该怎么做?

3 个答案:

答案 0 :(得分:3)

哦,很有趣,抓一切,这是正确的版本:

function JMath() {
   this.foo = function() {
        return this.PI;
    }
}

JMath.prototype = Math;

var jMath = new JMath();
alert(jMath.foo());

(这与其他答案相符)

(我最初尝试使用“JMath.prototype = new Math()”设置原型,这是我在其他地方看到的,但上面的工作)

修改

这是将其作为单身人士的一种方式

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

答案 1 :(得分:3)

考虑使用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

这和@ altCognito的答案之间的区别在于,这里对象的字段是共享的,并且都指向相同的东西。如果不使用原型,则在构造函数中创建新的和未链接的实例。您可以基于每个实例覆盖原型的值,如果您覆盖它,然后决定不喜欢覆盖值并想要恢复原始值,请使用delete删除仅仅“阴影”的覆盖“原型的价值。

编辑:如果你想继承Math对象本身的所有方法和字段,但是在不影响Math对象的情况下覆盖一些东西,可以这样做(根据自己的喜好更改名称“Constructor1”):

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

编辑3:对Constructor1函数的解释:这将创建以下原型链:

j -> JMath.prototype -> Math

j是JMath的一个实例。 JMath的原型是Constructor1的一个实例。 Constructor1的原型是Math。 JMath.prototype是被覆盖的东西“活着”的地方。如果你只实现了几个JMath实例,你可以让被覆盖的东西是由构造函数JMath设置的实例变量,并直接指向Math,就像@ altCognito的答案那样。 (j是JMath的一个实例,JMath的原型是Math)

在构造函数中增加一个对象有两个缺点。 (实际上不一定是缺点)一个是在构造函数中声明实例字段/方法为每个实例创建单独的值。如果您创建了大量JMath实例,则每个实例的JMath.foo函数将是一个占用额外内存的单独对象。如果JMath.foo函数来自其原型,则所有实例共享一个对象。

此外,您可以在事实之后更改JMath.prototype.foo,并且实例将相应地更新。如果在构造函数中将foo函数作为每个实例的方法创建,那么一旦创建了JMath对象,它们就是独立的,更改foo函数的唯一方法就是更改每个函数。


编辑2:就只读属性而言,你无法在Javascript本身内实现它们,你需要在表面下捣乱。但是,您可以声明所谓的“getters”,它有效地充当常量:

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

警告:定义getter / setters apparently is not something that IE doesn't implement nicely的语法。

答案 2 :(得分:1)

用户定义的对象属性不能是常量。 Math(以及一些其他对象)是一种特殊的内置函数 - 它具有只读属性和函数。但它不是构造函数 - 它只是一个静态对象(Math.constructor === Object)。

因为JavaScript具有原型继承,而不是经典,所以不能继承自Math。 (Read more here

然而,您可以做的是定义原型。当在本地找不到属性时,JS解析器在当前对象的原型上查找该属性。 altCognito目前的解决方案非常清楚。

我很好奇你正在努力实现的目标。也许这样的事情就是你想要的?

var jMath = function()
{
    const pi2 = Math.PI;

    this.getPi2 = function()
    {
        return pi2;
    }
}

var j = new jMath;
alert( j.getPi2() );