Показать сообщение отдельно
  #20 (permalink)  
Старый 21.07.2015, 21:21
Аватар для nohuhu
Профессор
Отправить личное сообщение для nohuhu Посмотреть профиль Найти все сообщения от nohuhu
 
Регистрация: 21.05.2015
Сообщений: 321

Сообщение от khusamov Посмотреть сообщение
Как так? А для чего тогда создаются методы setParam() для каждого param из раздела config? Для чего создаются методы applyParam, updateParam?

Я все этим методы активню пользуюсь, а теперь выясняется что нельзя? Они только для чтения???
Перечитал своё сообщение, понял что мысль выразил не доходчиво. Попытка №2:

Система конфигурации в Ext JS 5 имеет основной целью конфигурирование экземпляров объектов. Конфигурация каждого экземпляра может динамически меняться, при этом конфигурация других объектов того же класса изменяться не должна. Отсюда логически следует, что конфигурационные свойства классов должны быть доступны только для чтения, в отличие от объектов.

В теории это всё звучит хорошо, но на практике у нас есть JavaScript и только одна схема наследования, прототипная. Это означает, что наследование конфигов можно сделать двумя способами: либо связывая конфиги-объекты по прототипной цепочке с соответствующими конфигами классов, либо тупо копируя все свойства для каждого нового экземпляра. Второй способ отпал по причине низкой производительности, поэтому остаётся первый.

Если конфигурационные объекты по прототипу не связывать, то для каждого экземпляра объекта будут доступны только те свойства, которые содержатся в конфиге самого экземпляра - наследованные свойства доступны не будут. Именно так это работало в Ext JS 4:

Ext.define('Bar', {
    blerg: {
        frobbe: 'throbbe'
    }
});

var beer = new Bar({
    blerg: {
        qux: 'dux'
    }
});

console.log(beer.blerg);
// {
//     qux: 'dux'
// }


Как видите, никакого наследования быть не может, т.к содержимое переменной beer это объект, прототипом которого является объект Bar. У каждого из этих объектов есть свойство blerg, и использоваться будет "верхнее" значение в прототипной цепочке.

Блок config в Ext JS 5 работает по-другому и свойства-объекты связываются по прототипу, чтобы обеспечить наследование конфигов. Заметьте, что все эти пространные рассуждения никак не относятся к тривиальным значениям конфигов: строкам, числам, etc. С ними всё просто. Но объекты наследуются:

Ext.define('Foo', {
    config: {
        blerg: {
            zilch: 42
        }
    },

    // Это нужно только в данном примере;
    // в обычном случае initConfig уже вызывается
    // родительским классом (Ext.Component, etc)
    constructor: function(config) {
        this.initConfig(config);
    }
});

var foo = new Foo({
    blerg: {
        bar: 'qux',
        zilch: 43
    }
});

console.log(foo.getBlerg());
// {
//     bar: 'qux',
//     zilch: 43
// }


В этом примере объект в переменной foo имеет прототипом объект Foo, оба имеют конфиг blerg. Этот конфиг, в свою очередь, это тоже объект, прототипом которого является объект конфига blerg в объекте Foo. Свойство zilch имеется в обоих конфигах, но "верхнее" в цепочке принадлежит конфигу foo, поэтому оно и используется; свойство bar в конфиге Foo отсутствует и есть только в конфиге foo.

Поскольку конфиги динамические, то их можно менять, но только для экземпляра объекта:

foo.setBlerg({ zilch: 44 });

foo.getBlerg();
// {
//     zilch: 44
// }


Если вы проинспектируете конфиг объекта Foo, то увидите, что он не изменился. Конфигурация происходит только на уровне экземпляра, но не класса.

Что касается массивов, то с ними связывание по прототипу не работает, поэтому тоже будет использоваться "верхнее" значение в цепочке, так же как и с тривиальными типами данных:

Ext.define('Baz', {
    config: {
        qux: [42]
    },

    constructor: function(cfg) {
        this.initConfig(cfg);
    }
});

var bazz = new Baz();

bazz.getQux();
// [42]

var brazz = new Baz({ qux: [-1] });

brazz.getQux();
// [-1]


Специальная магия нужна в случае, если вы хотите, чтобы массив был объединением элементов из наследованных конфигов с элементами из массива на экземпляре:

Ext.define('MagicParent', {
    config: {
        qux: {
            $value: [42],
            merge: function(newValue, oldValue) {
                // Пристёгиваем новые элементы к старым
                return (oldValue || []).concat(newValue);
        }
    },

    constructor: function(cfg) {
        this.initConfig(cfg);
    }
});

Ext.define('MagicChild', {
    extend: 'MagicParent',

    config: {
        qux: [43]
    }
});

var magic = new MagicChild({ qux: [44] });

magic.getQux();
// [42, 43, 44]

// Значения, переданные в setter, считаются полными
// и через цепочку связываний не проходят:
magic.setQux([-1]);

magic.getQux();
// [-1]


Надеюсь, теперь будет понятнее. В целом система конфигов не безобразно сложна к пониманию, но имеет некоторые особенности, поэтому и остаётся большей частью приватной. Если разобраться, можно творить чудесатые чудеса. :)
Ответить с цитированием