The source code

    /**
     * @ignore
     *  attribute management
     * @author yiminghe@gmail.com, lifesinger@gmail.com
     */
    KISSY.add('base/attribute', function (S, undefined) {

        // atomic flag
        Attribute.INVALID = {};

        var INVALID = Attribute.INVALID;

        function normalFn(host, method) {
            if (typeof method == 'string') {
                return host[method];
            }
            return method;
        }

        // fire attribute value change
        function __fireAttrChange(self, when, name, prevVal, newVal, subAttrName, attrName) {
            attrName = attrName || name;
            return self.fire(when + S.ucfirst(name) + 'Change', {
                attrName: attrName,
                subAttrName: subAttrName,
                prevVal: prevVal,
                newVal: newVal
            });
        }

        function ensureNonEmpty(obj, name, create) {
            var ret = obj[name] || {};
            if (create) {
                obj[name] = ret;
            }
            return ret;
        }

        function getAttrs(self) {
            /*
             attribute meta information
             {
             attrName: {
             getter: function,
             setter: function,
             // 注意：只能是普通对象以及系统内置类型，而不能是 new Xx()，否则用 valueFn 替代
             value: v, // default value
             valueFn: function
             }
             }
             */
            return ensureNonEmpty(self, '__attrs', true);
        }

        function getAttrVals(self) {
            /*
             attribute value
             {
             attrName: attrVal
             }
             */
            return ensureNonEmpty(self, '__attrVals', true);
        }

        /*
         o, [x,y,z] => o[x][y][z]
         */
        function getValueByPath(o, path) {
            for (var i = 0, len = path.length;
                 o != undefined && i < len;
                 i++) {
                o = o[path[i]];
            }
            return o;
        }

        /*
         o, [x,y,z], val => o[x][y][z]=val
         */
        function setValueByPath(o, path, val) {
            var len = path.length - 1,
                s = o;
            if (len >= 0) {
                for (var i = 0; i < len; i++) {
                    o = o[path[i]];
                }
                if (o != undefined) {
                    o[path[i]] = val;
                } else {
                    s = undefined;
                }
            }
            return s;
        }

        function getPathNamePair(self, name) {
            var declared = self.hasAttr(name), path;

            if (
            // 声明过，那么 xx.yy 当做普通属性
                !declared &&
                    name.indexOf('.') !== -1) {
                path = name.split('.');
                name = path.shift();
            }

            return {
                path: path,
                name: name
            };
        }

        function getValueBySubValue(prevVal, path, value) {
            var tmp = value;
            if (path) {
                if (prevVal === undefined) {
                    tmp = {};
                } else {
                    tmp = S.clone(prevVal);
                }
                setValueByPath(tmp, path, value);
            }
            return tmp;
        }

        function setInternal(self, name, value, opts, attrs) {
            opts = opts || {};

            var ret,
                path,
                subVal,
                prevVal,
                pathNamePair = getPathNamePair(self, name),
                fullName = name;

            name = pathNamePair.name;
            path = pathNamePair.path;
            prevVal = self.get(name);

            if (path) {
                subVal = getValueByPath(prevVal, path);
            }

            // if no change, just return
            if (!path && prevVal === value) {
                return undefined;
            } else if (path && subVal === value) {
                return undefined;
            }

            value = getValueBySubValue(prevVal, path, value);

            // check before event
            if (!opts['silent']) {
                if (false === __fireAttrChange(self, 'before', name, prevVal, value, fullName)) {
                    return false;
                }
            }
            // set it
            ret = self.setInternal(name, value, opts);

            if (ret === false) {
                return ret;
            }

            // fire after event
            if (!opts['silent']) {
                value = getAttrVals(self)[name];
                __fireAttrChange(self, 'after', name, prevVal, value, fullName);
                if (!attrs) {
                    __fireAttrChange(self,
                        '', '*',
                        [prevVal], [value],
                        [fullName], [name]);
                } else {
                    attrs.push({
                        prevVal: prevVal,
                        newVal: value,
                        attrName: name,
                        subAttrName: fullName
                    });
                }
            }
            return self;
        }

        /**
         * @class KISSY.Base.Attribute
         * @private
         * Attribute provides configurable attribute support along with attribute change events.
         * It is designed to be augmented on to a host class,
         * and provides the host with the ability to configure attributes to store and retrieve state,
         * along with attribute change events.
         *
         * For example, attributes added to the host can be configured:
         *
         *  - With a setter function, which can be used to manipulate
         *  values passed to attribute 's {@link #set} method, before they are stored.
         *  - With a getter function, which can be used to manipulate stored values,
         *  before they are returned by attribute 's {@link #get} method.
         *  - With a validator function, to validate values before they are stored.
         *
         * See the {@link #addAttr} method, for the complete set of configuration
         * options available for attributes.
         *
         * NOTE: Most implementations will be better off extending the {@link KISSY.Base} class,
         * instead of augmenting Attribute directly.
         * Base augments Attribute and will handle the initial configuration
         * of attributes for derived classes, accounting for values passed into the constructor.
         */
        function Attribute() {
        }

        Attribute.prototype = {

            /**
             * get un-cloned attr config collections
             * @return {Object}
             * @private
             */
            getAttrs: function () {
                return getAttrs(this);
            },

            /**
             * get un-cloned attr value collections
             * @return {Object}
             */
            getAttrVals: function () {
                var self = this,
                    o = {},
                    a,
                    attrs = getAttrs(self);
                for (a in attrs) {
                    o[a] = self.get(a);
                }
                return o;
            },

            /**
             * Adds an attribute with the provided configuration to the host object.
             * @param {String} name attrName
             * @param {Object} attrConfig The config supports the following properties
             * @param [attrConfig.value] simple object or system native object
             * @param [attrConfig.valueFn] a function which can return current attribute 's default value
             * @param {Function} [attrConfig.setter] call when set attribute 's value
             * pass current attribute 's value as parameter
             * if return value is not undefined,set returned value as real value
             * @param {Function} [attrConfig.getter] call when get attribute 's value
             * pass current attribute 's value as parameter
             * return getter's returned value to invoker
             * @param {Function} [attrConfig.validator]  call before set attribute 's value
             * if return false,cancel this set action
             * @param {Boolean} [override] whether override existing attribute config ,default true
             * @chainable
             */
            addAttr: function (name, attrConfig, override) {
                var self = this,
                    attrs = getAttrs(self),
                    cfg = S.clone(attrConfig);
                if (!attrs[name]) {
                    attrs[name] = cfg;
                } else {
                    S.mix(attrs[name], cfg, override);
                }
                return self;
            },

            /**
             * Configures a group of attributes, and sets initial values.
             * @param {Object} attrConfigs  An object with attribute name/configuration pairs.
             * @param {Object} initialValues user defined initial values
             * @chainable
             */
            addAttrs: function (attrConfigs, initialValues) {
                var self = this;
                S.each(attrConfigs, function (attrConfig, name) {
                    self.addAttr(name, attrConfig);
                });
                if (initialValues) {
                    self.set(initialValues);
                }
                return self;
            },

            /**
             * Checks if the given attribute has been added to the host.
             * @param {String} name attribute name
             * @return {Boolean}
             */
            hasAttr: function (name) {
                return getAttrs(this).hasOwnProperty(name);
            },

            /**
             * Removes an attribute from the host object.
             * @chainable
             */
            removeAttr: function (name) {
                var self = this;

                if (self.hasAttr(name)) {
                    delete getAttrs(self)[name];
                    delete getAttrVals(self)[name];
                }

                return self;
            },

            /**
             * Sets the value of an attribute.
             * @param {String|Object} name attribute 's name or attribute name and value map
             * @param [value] attribute 's value
             * @param {Object} [opts] some options
             * @param {Boolean} [opts.silent] whether fire change event
             * @return {Boolean} whether pass validator
             */
            set: function (name, value, opts) {
                var self = this;
                if (S.isPlainObject(name)) {
                    opts = value;
                    var all = Object(name),
                        attrs = [],
                        e,
                        errors = [];
                    for (name in all) {
                        // bulk validation
                        // if any one failed,all values are not set
                        if ((e = validate(self, name, all[name], all)) !== undefined) {
                            errors.push(e);
                        }
                    }
                    if (errors.length) {
                        if (opts && opts.error) {
                            opts.error(errors);
                        }
                        return false;
                    }
                    for (name in all) {
                        setInternal(self, name, all[name], opts, attrs);
                    }
                    var attrNames = [],
                        prevVals = [],
                        newVals = [],
                        subAttrNames = [];
                    S.each(attrs, function (attr) {
                        prevVals.push(attr.prevVal);
                        newVals.push(attr.newVal);
                        attrNames.push(attr.attrName);
                        subAttrNames.push(attr.subAttrName);
                    });
                    if (attrNames.length) {
                        __fireAttrChange(self,
                            '',
                            '*',
                            prevVals,
                            newVals,
                            subAttrNames,
                            attrNames);
                    }
                    return self;
                }
                return setInternal(self, name, value, opts);
            },

            /**
             * internal use, no event involved, just set.
             * @protected
             */
            setInternal: function (name, value, opts) {
                var self = this,
                    setValue,
                // if host does not have meta info corresponding to (name,value)
                // then register on demand in order to collect all data meta info
                // 一定要注册属性元数据，否则其他模块通过 _attrs 不能枚举到所有有效属性
                // 因为属性在声明注册前可以直接设置值
                    e,
                    attrConfig = ensureNonEmpty(getAttrs(self), name, true),
                    setter = attrConfig['setter'];

                // validator check
                e = validate(self, name, value);

                if (e !== undefined) {
                    if (opts.error) {
                        opts.error(e);
                    }
                    return false;
                }

                // if setter has effect
                if (setter && (setter = normalFn(self, setter))) {
                    setValue = setter.call(self, value, name);
                }

                if (setValue === INVALID) {
                    return false;
                }

                if (setValue !== undefined) {
                    value = setValue;
                }

                // finally set
                getAttrVals(self)[name] = value;
            },

            /**
             * Gets the current value of the attribute.
             * @param {String} name attribute 's name
             * @return {*}
             */
            get: function (name) {
                var self = this,
                    dot = '.',
                    path,
                    declared = self.hasAttr(name),
                    attrVals = getAttrVals(self),
                    attrConfig,
                    getter, ret;

                if (!declared && name.indexOf(dot) !== -1) {
                    path = name.split(dot);
                    name = path.shift();
                }

                attrConfig = ensureNonEmpty(getAttrs(self), name);
                getter = attrConfig['getter'];

                // get user-set value or default value
                //user-set value takes privilege
                ret = name in attrVals ?
                    attrVals[name] :
                    getDefAttrVal(self, name);

                // invoke getter for this attribute
                if (getter && (getter = normalFn(self, getter))) {
                    ret = getter.call(self, ret, name);
                }

                if (!(name in attrVals) && ret !== undefined) {
                    attrVals[name] = ret;
                }

                if (path) {
                    ret = getValueByPath(ret, path);
                }

                return ret;
            },

            /**
             * Resets the value of an attribute.just reset what addAttr set
             * (not what invoker set when call new Xx(cfg))
             * @param {String} name name of attribute
             * @param {Object} [opts] some options
             * @param {Boolean} [opts.silent] whether fire change event
             * @chainable
             */
            reset: function (name, opts) {
                var self = this;

                if (typeof name == 'string') {
                    if (self.hasAttr(name)) {
                        // if attribute does not have default value, then set to undefined
                        return self.set(name, getDefAttrVal(self, name), opts);
                    }
                    else {
                        return self;
                    }
                }

                opts = name;

                var attrs = getAttrs(self),
                    values = {};

                // reset all
                for (name in attrs) {
                    values[name] = getDefAttrVal(self, name);
                }

                self.set(values, opts);
                return self;
            }
        };

        // get default attribute value from valueFn/value
        function getDefAttrVal(self, name) {
            var attrs = getAttrs(self),
                attrConfig = ensureNonEmpty(attrs, name),
                valFn = attrConfig.valueFn,
                val;

            if (valFn && (valFn = normalFn(self, valFn))) {
                val = valFn.call(self);
                if (val !== undefined) {
                    attrConfig.value = val;
                }
                delete attrConfig.valueFn;
                attrs[name] = attrConfig;
            }

            return attrConfig.value;
        }

        function validate(self, name, value, all) {
            var path, prevVal, pathNamePair;

            pathNamePair = getPathNamePair(self, name);

            name = pathNamePair.name;
            path = pathNamePair.path;

            if (path) {
                prevVal = self.get(name);
                value = getValueBySubValue(prevVal, path, value);
            }
            var attrConfig = ensureNonEmpty(getAttrs(self), name, true),
                e,
                validator = attrConfig['validator'];
            if (validator && (validator = normalFn(self, validator))) {
                e = validator.call(self, value, name, all);
                // undefined and true validate successfully
                if (e !== undefined && e !== true) {
                    return e;
                }
            }
            return undefined;
        }

        return Attribute;
    });

    /*
     2011-10-18
     get/set sub attribute value ,set('x.y',val) x 最好为 {} ，不要是 new Clz() 出来的
     add validator
     */