odoo前端js对象的扩展方法

odoo前端js对象的扩展方法

在 Odoo 中,你可以使用两种方法来扩展 JavaScript 对象:extendspatch。这两种方法在功能上有一些区别。

  1. extends 方法:

    • 使用 extends 方法可以创建一个新的 JavaScript 对象,并继承自现有的对象。这意味着你可以在新对象中添加、修改或覆盖现有对象的属性和方法。
    • extends 方法适用于对现有对象进行全面的扩展和修改,以满足特定的需求。你可以通过创建一个新的对象,并在其中添加自定义的属性和方法来实现扩展。
    • 使用 extends 方法时,你需要确保新对象的原型链正确设置,以便正确继承和覆盖现有对象的属性和方法。
  2. patch 方法:

    • 使用 patch 方法可以直接修改现有的 JavaScript 对象,而无需创建新的对象。你可以通过 patch 方法来修改对象的属性和方法,添加新的属性和方法,或者删除现有的属性和方法。
    • patch 方法适用于对现有对象进行局部的修改和调整,以满足特定的需求。你可以直接在现有对象上进行修改,而无需创建新的对象。
    • 使用 patch 方法时,你需要确保正确地定位到要修改的对象,并进行相应的修改操作。

总的来说,extends 方法适用于全面的扩展和修改,而 patch 方法适用于局部的修改和调整。选择使用哪种方法取决于你的具体需求和场景。

1、patch的实现

patch 一个简单的例子

/** @odoo-module **/

import { _t } from "@web/core/l10n/translation";
import { patch } from "@web/core/utils/patch";
import { SearchBar } from "@web/search/search_bar/search_bar";

patch(SearchBar.prototype, {
    getPreposition(searchItem) {
        let preposition = super.getPreposition(searchItem);
        if (this.fields[searchItem.fieldName].name == 'payment_date') {
            preposition = _t("until");
        }
        return preposition
    }
});

2、patch.js

先学习一下object对象,再来学习patch.js

patch对象的原型,调用了很多Object的静态方法,原则上就是在原型对象上动态增加或者替换新的属性。

        // Replace the old property by the new one.
        Object.defineProperty(objToPatch, key, newProperty);

附录: patch.js 源文件

/** @odoo-module **/

/**
 *  @typedef {{
 *      originalProperties: Map;
 *      skeleton: object;
 *      extensions: Set;
 *  }} PatchDescription
 */

/** @type {WeakMap} */
const patchDescriptions = new WeakMap();

/**
 * Create or get the patch description for the given `objToPatch`.
 * @param {object} objToPatch
 * @returns {PatchDescription}
 */
function getPatchDescription(objToPatch) {
    if (!patchDescriptions.has(objToPatch)) {
        patchDescriptions.set(objToPatch, {
            originalProperties: new Map(),
            skeleton: Object.create(Object.getPrototypeOf(objToPatch)),
            extensions: new Set(),
        });
    }
    return patchDescriptions.get(objToPatch);
}

/**
 * @param {object} objToPatch
 * @returns {boolean}
 */
function isClassPrototype(objToPatch) {
    // class A {}
    // isClassPrototype(A) === false
    // isClassPrototype(A.prototype) === true
    // isClassPrototype(new A()) === false
    // isClassPrototype({}) === false
    return Object.hasOwn(objToPatch, "constructor") && objToPatch.constructor?.prototype === objToPatch;
}

/**
 * Traverse the prototype chain to find a potential property.
 * @param {object} objToPatch
 * @param {string} key
 * @returns {object}
 */
function findAncestorPropertyDescriptor(objToPatch, key) {
    let descriptor = null;
    let prototype = objToPatch;
    do {
        descriptor = Object.getOwnPropertyDescriptor(prototype, key);
        prototype = Object.getPrototypeOf(prototype);
    } while (!descriptor && prototype);
    return descriptor;
}

/**
 * Patch an object
 *
 * If the intent is to patch a class, don't forget to patch the prototype, unless
 * you want to patch static properties/methods.
 *
 * @template T
 * @template {T} U
 * @param {T} objToPatch The object to patch
 * @param {U} extension The object containing the patched properties
 * @returns {() => void} Returns an unpatch function
 */
export function patch(objToPatch, extension) {
    if (typeof extension === "string") {
        throw new Error(`Patch "${extension}": Second argument is not the patch name anymore, it should be the object containing the patched properties`);
    }

    const description = getPatchDescription(objToPatch);
    description.extensions.add(extension);

    const properties = Object.getOwnPropertyDescriptors(extension);
    for (const [key, newProperty] of Object.entries(properties)) {
        const oldProperty = Object.getOwnPropertyDescriptor(objToPatch, key);
        if (oldProperty) {
            // Store the old property on the skeleton.
            Object.defineProperty(description.skeleton, key, oldProperty);
        }

        if (!description.originalProperties.has(key)) {
            // Keep a trace of original property (prop before first patch), useful for unpatching.
            description.originalProperties.set(key, oldProperty);
        }

        if (isClassPrototype(objToPatch)) {
            // A property is enumerable on POJO ({ prop: 1 }) but not on classes (class A {}).
            // Here, we only check if we patch a class prototype.
            newProperty.enumerable = false;
        }

        if ((newProperty.get && 1) ^ (newProperty.set && 1)) {
            // get and set are defined together. If they are both defined
            // in the previous descriptor but only one in the new descriptor
            // then the other will be undefined so we need to apply the
            // previous descriptor in the new one.
            const ancestorProperty = findAncestorPropertyDescriptor(objToPatch, key);
            newProperty.get = newProperty.get ?? ancestorProperty?.get;
            newProperty.set = newProperty.set ?? ancestorProperty?.set;
        }

        // Replace the old property by the new one.
        Object.defineProperty(objToPatch, key, newProperty);
    }

    // Sets the current skeleton as the extension's prototype to make
    // `super` keyword working and then set extension as the new skeleton.
    description.skeleton = Object.setPrototypeOf(extension, description.skeleton);

    return () => {
        // Remove the description to start with a fresh base.
        patchDescriptions.delete(objToPatch);

        for (const [key, property] of description.originalProperties) {
            if (property) {
                // Restore the original property on the `objToPatch` object.
                Object.defineProperty(objToPatch, key, property);
            } else {
                // Or remove the property if it did not exist at first.
                delete objToPatch[key];
            }
        }

        // Re-apply the patches without the current one.
        description.extensions.delete(extension);
        for (const extension of description.extensions) {
            patch(objToPatch, extension);
        }
    };
}

 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(odoo16前端框架分析,前端,javascript,odoo)