JavaScript: наследование и объявление констант - PullRequest
1 голос
/ 13 апреля 2009

Помощь, У меня есть этот класс

var jMath = {

    pi2: Math.PI,

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

Я хочу сделать константу pi2 и хочу, чтобы jMath наследовал от объекта Math. Как мне это сделать?

Ответы [ 3 ]

3 голосов
/ 13 апреля 2009

Рассмотрите возможность использования 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

edit 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 - это изменить каждый из них.


edit 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

Предупреждение: синтаксис для определения методов получения / установки , по-видимому, не является чем-то, что IE не реализует красиво .

3 голосов
/ 13 апреля 2009

О, забавно, поцарапайте все это, это правильная версия:

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 голос
/ 13 апреля 2009

Пользовательские свойства объекта не могут быть постоянными. Math (и несколько других объектов) - это специальная встроенная функция - она ​​имеет свойства и функции только для чтения. Но это не конструктор - это просто статический объект (Math.constructor === Object).

А поскольку JavaScript имеет прототипное наследование, а не классическое, вы не можете наследовать от Math. ( Подробнее здесь )

Однако вы можете определить прототип. Когда свойство не найдено локально, анализатор JS ищет это свойство в прототипе текущего объекта. Текущие решения altCognito хорошо это показывают.

Мне интересно, что именно вы пытаетесь достичь. Возможно, что-то вроде этого - то, что вы хотите?

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

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

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