JavaScript类与返回对象的函数对比:Playwright PoM实现疑问
1. 为啥函数要返回内容,类实例不用?
这种写法属于工厂函数模式,外层函数一般用来接收Playwright的page或locator这类核心依赖,然后返回一个包含组件操作方法的对象(你说的返回函数可能是嵌套的高阶工厂,本质还是返回组件操作集合)。
类的话,是通过new关键字实例化的——new操作符会自动创建实例对象,把构造函数里的逻辑绑定到实例上,最后自动返回这个实例,所以不用你手动写return。而工厂函数就是普通函数,你不手动返回定义好的组件对象,调用后得到的就是undefined,完全没法用。
举个常见的函数式写法例子:
export const createHeader = (page: Page) => { const self = { logo: page.locator('#header-logo'), async clickLogo() { await self.logo.click() } } return self }
调用的时候就是const header = createHeader(page),拿到的就是包含logo和clickLogo的组件对象。
2. 这种写法比类有啥优势?
说几个实际开发里的好处:
- 彻底避开
this坑:类里的方法如果不用箭头函数绑定,很容易出现this指向混乱(比如把方法当回调传的时候),函数式写法用闭包捕获依赖,根本没this这回事,代码稳得一批。 - 代码更轻量简洁:不用处理类的继承、原型链这些概念,小组件写起来飞快,一眼就能看懂所有逻辑。
- TS类型推导更省心:工厂函数返回的对象类型是TS自动推导的,不用额外写接口或者类型声明;类的话有时候还要手动补类型,尤其是继承场景下。
- 依赖注入更直观:外层函数直接传
page或者父级locator,组件依赖一眼看明白,调用的时候直接传参,比类的构造函数注入更直白。
当然劣势也有:复杂组件要复用逻辑的话,类的继承比函数式的复用(比如拷贝对象、组合函数)更方便,所以一般小组件用函数式,复杂组件用类更合适。
3. ...expect(self)和self到底干啥用?
先讲self:它就是把组件的所有元素定位、操作方法都聚合到一个对象里,方便内部引用和后续维护。比如上面例子里,clickLogo方法直接用self.logo,不用重复写page.locator('#header-logo'),以后要改logo的定位器,只需要改self.logo这一处就行,所有用到的地方自动生效。
再讲...expect(self):这是把Playwright的断言方法“混入”到组件对象里,简化断言代码。假设self里有个根定位器(比如root: page.locator('#header')),expect(self.root)会返回Playwright的LocatorAssertions对象,把这个对象的方法展开到self里,你就可以直接写await header.toBeVisible(),而不用写await expect(header.root).toBeVisible(),本质是语法糖,让代码更简洁。
内容的提问来源于stack exchange,提问作者msmith1114

