Области разработки и пространства имен библиотеки Javascript - PullRequest
1 голос
/ 09 апреля 2011

В настоящее время мы изучаем некоторые материалы по Javascript на курсе в университете.Для этого мы реализуем библиотеку для общих задач, таких как show (), hide (), write и тому подобное.

В настоящее время я работаю с реализацией, такой как:

var myLib_maker = function () {
/*
private scope
*/
var debuggingMode=true;
var currentElement=null;
/*
end private scope
*/
return {
    getElement: function (id) {
        var o;
        if (typeof id === 'string') { o = document.getElementById(id); }
        if (!!(o && o.nodeType !== 1)) { 
            throw {
                name: 'Type Error',
                message: 'Wrong node type at id: '+id
            } 
        }
      currentElement=o;
      return this;
    },
    getCurrentElement: function() {
        console.log(currentElement)
        return currentElement;
    },
    isVisible: function () {
        return this.getCurrentElement().style.display.toLowerCase() === "block"; 
    },
    show: function () {
        this.debug("show "+this.getCurrentElement())
        this.getCurrentElement().style.display = "block";
        return this;
    },
    hide: function () {
        this.debug("hide "+this.getCurrentElement())
        this.getCurrentElement().style.display = "none";
        return this;
    },
    toggle: function() {
        this.debug("toggle "+this.getCurrentElement())
        this.isVisible() ? this.hide(): this.show();
        return this;
    },
    write: function (content){
        this.debug("write to"+this.getCurrentElement().id);
        var tg = this.getCurrentElement().tagName.toLowerCase();
        if (tg === 'input' || tg === 'textarea') {
            currentElement.value = content; 
        } else { 
            currentElement.innerHTML = content;
        }
        return this
    },
    debug: function (what) {
        if (debuggingMode===true){
            console.log("[DEBUG] "+what);
        }
        return this;
    }

};
  }
  var myLib=myLib_maker();

Чем у меня естьвнешняя функция (для тестирования) для переключения содержимого 2 текстовых областей.

 function switchEditors(id1, id2){
      c1=myLib.getElement(id1).getCurrentElement().value;
      c2=myLib.getElement(id2).getCurrentElement().value;
      myLib.getElement(id1).write(c2)
      myLib.getElement(id2).write(c1)
 }

Сначала я попробовал следующий код, который, очевидно, не работает, потому что я перезаписываю свой приватный currentElement и поэтому всегда пишу в id2

function switchEditors(id1, id2){
      tmp=myLib.getElement(id1).getCurrentElement().value
      myLib.getElement(id1).write(myLib.getElement(id2).getCurrentElement().value)
      myLib.getElement(id2).write(tmp)
 } 

Но то, что я действительно хотел изначально, это не использование закрытой переменной currentElement.Первая реализация метода write расширила объект Element

Element.prototype.write= function (content){
    var tg = this.tagName.toLowerCase();
    if (tg === 'input' || tg === 'textarea') {
        this.value = content; 
    } else { 
         this.innerHTML = content;
    }
    return this;
}

, и такая функция getElement вернула

document.getElementById(id)

Я хочу каскадирование (надеюсь, это правильное слово -> я имею в видуmyLib.getElement ("myid"). show (). hide () вещь конкатенации) и получение прямого доступа ко всем атрибутам Element, но мы не должны использовать глобальную область видимости для нашей библиотеки, поэтому я должен каким-либо образом инкапсулировать свою библиотеку.

Так есть ли элегантный способ использовать каскадную вещь и иметь возможность получить прямой доступ ко всем атрибутам объекта-элемента без реализации каждого метода в глобальной области видимости элемента?

Илимоя работа написана совершенно неправильно и должна быть совершенно другой.Если так, просто скажи мне, я ценю любую помощь.(Я пытался выяснить, как jQuery на самом деле реализует эти вещи, но не понял, как это делается ... слишком много кода ... :))

Я надеюсь, что описал свои пожелания итребования.Если нет, пожалуйста, запросите более подробную информацию.

Ответы [ 2 ]

1 голос
/ 09 апреля 2011

Хотя решение Magnar будет работать с этим (одноэлементным) шаблоном, лучше избегать создания нового объекта каждый раз, когда вы вызываете getElement. Есть причина создавать "классы" вместо синглетонов.

Вы можете сделать это так:

var MyLib_Maker = (function () { // I capitalized the class as a helpful 
                                // convention recommended by Douglas Crockford

    // Private static vars
    var debuggingMode = true;
    var currentElement = null;

    // Private static methods
    function _myMethod (x, y) { // call below by _myMethod(3,4);
        return x * y;
    }

    // Private instance methods (but only if called properly: 
    // invoke below by _instMethod.call(this, 3, 4); )
    function _instMethod (x, y) {
        return this.anInstanceNumber * x * y;
    }

    // Private instance properties (quite cumbersome but doable if you 
    // absolutely must--e.g., for classes whose objects need to be clean when iterated)
    // See http://brettz9.blogspot.com/2009/02/true-private-instance-variables-in.html
    // and http://brettz9.blogspot.com/2009/02/further-relator-enhancements.html
    // (put the Relator inside the closure if you don't want it reusable (and public),
    // but then your extending classes must be inside the closure too)

    function MyLib_Maker (arg1, arg2) {
        // I recommend the following check to allow your class to be
        // instantiated without the 'new' keyword (as in jQuery/$):
        if (!(this instanceof MyLib_Maker)) {
            return new MyLib_Maker(arg1, arg2);
        }
        // Other constructor code here
        // ...
    }
    // Methods added on the prototype benefit from merely 
    // providing a low-memory reference across all instances; 
    // this will avoid adding a whole new object unnecessarily 
    // into memory
    MyLib_Maker.prototype.getElement = function () {
        // ....
        return this; // Keep the chain going (if not public
        // properties, you could add a method which also avoids 
        // extending the chain, like $(el).get() in jQuery
    };


    return MyLib_Maker;
}()); // We can invoke immediately to wrap up the closure

// Usage example:
var mlm = MyLib_Maker(2, 3).getElement().doSomething();

Кстати, то, что вы описываете, называется цепочкой; Каскадирование используется в подобных CSS, чтобы указать, что подобно различным волнам из водопада, один может писать поверх другого, как вы можете сделать, написав правила, которые переопределяют предыдущие в CSS.

И хорошо, что вы отошли от переопределения объекта Element, потому что, независимо от несовместимости браузера, это наихудший вид глобального загрязнения пространства имен, поскольку он затрагивает все элементы, увеличивая вероятность того, что другая библиотека зависит от этого метода (или который небрежно переопределяет встроенные прототипы) может привести к неожиданным результатам.

1 голос
/ 09 апреля 2011

Как вы уже поняли, currentElement распределяется между вызовами на getElement. Вместо этого вы можете создать новый экземпляр myLib-объекта с Object.create и связать currentElement с этим.

getElement: function (id) {
    var o, self = Object.create(this);
    /* ... */
    self.currentElement = o;
    return self;
}

И использовать this.currentElement, чтобы каждый вызов использовал свой текущий элемент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...