Mixin the target with the source

@inner
@param {Object} target the target
@param {Object} source the source
@param {string} k the key
@param {Object} opts the mixin options
function doMixin(target, source, k, opts) {
    let {
        mixinAttrName = MIXIN_ATTR_NAME,
        lifecycleHookMap,
        mixinStrategy
    } = opts;

    if (k === mixinAttrName) {
        return;
    }

    let mixinHandler = mixinStrategy && mixinStrategy[k];
    if (mixinHandler) {
        target[k] = mixinHandler(target[k], source[k]);
    }
    else if (lifecycleHookMap[k]) {
        let child = target[k];
        let parent = source[k];

        if (!Array.isArray(child)) {
            child = child ? [child] : [];
        }

        if (!Array.isArray(parent)) {
            parent = parent ? [parent] : [];
        }

        child.unshift.apply(child, parent);
        target[k] = child;
    }
    else if (!target.hasOwnProperty(k)) {
        target[k] = source[k];
    }
}