向puppeteer.Page对象添加自定义方法

时间:2019-07-11 02:19:15

标签: javascript typescript methods puppeteer extending

我想向puppeteer.Page对象添加自定义方法,因此可以这样调用它们:

let page = await browser.newPage();
page.myNewCustomMethod();

这里是我创建的许多自定义方法中的一种。它使用表达式数组通过XPath表达式找到第一个可用元素:

const findAnyByXPath = async function (page: puppeteer.Page, expressions: string[]) {
    for (const exp of expressions) {
        const elements = await page.$x(exp);

        if (elements.length) {
            return elements[0];
        }
    }

    return null;
}

我必须像这样调用它...

let element = await findAnyByXPath(page, arrayOfExpressions);

对我来说,这在编辑器中看起来很奇怪,尤其是在正在调用许多自定义方法的区域中。在我看来,有点“脱离上下文”。所以我宁愿这样调用它:

page.findAnyByXPath(arrayOfExpressions);

我知道有一个page.exposeFunction方法,但这不是我想要的。

有什么方法可以实现这一目标?

1 个答案:

答案 0 :(得分:1)

可以这样做吗?是的。

您可以通过修改JavaScript的原型来扩展JavaScript中的任何对象。为了向Page对象添加功能,您可以使用__proto__属性访问Page对象的原型。

下面是一个简单的示例,将功能customMethod添加到所有Page对象:

const page = await browser.newPage();
page.__proto__.customMethod = async function () {
    // ...
    return 123;
}
console.log(await page.customMethod()); // 123

const anotherPage = await browser.newPage();
console.log(await anotherPage.customMethod()); // 123

请注意,由于构造函数(或类)本身并未公开,因此您首先需要一个Page对象才能访问原型。

您要这样做吗?否。

您可能已经注意到上面链接的MDN文档上的红色警告。仔细阅读它们。通常,不建议更改您正在使用且尚未创建的对象的原型。有人创造了原型,他没想到有人会修改它。有关更多信息,请查看以下stackoverflow问题:

如何代替?

相反,您应该只使用自己的函数。拥有自己的函数并以page作为参数来调用它们是没有错的:

// simple function
findAnyByXPath(page);

// your own "namespace" with more functionality
myLibrary.findAnyByXPath(page);
myLibrary.anotherCustomFunction(page);

通常,您也可以扩展类Page,但是在这种情况下,库不会导出class本身。因此,您只能创建一个包装器类,该包装器类在内部执行相同的功能,但在顶部提供更多功能。但这将是一种非常复杂的方法,在这种情况下确实值得付出努力。