【发布时间】:2020-10-22 22:05:26
【问题描述】:
我目前正在学习 Javascript,发现我们可以在对象的原型中而不是在对象的构造函数中定义对象的成员,因为它使对象更轻,因为它们不会在每个实例中都携带方法代码。
如果这个构造函数的所有对象都指向同一个变量字段,我可以看到变量如何工作不好,但是方法不应该改变太多或根本不应该改变,所以共享它们不是问题。
是否有理由不在原型上而不是在对象的构造函数上定义方法?
【问题讨论】:
标签: javascript
我目前正在学习 Javascript,发现我们可以在对象的原型中而不是在对象的构造函数中定义对象的成员,因为它使对象更轻,因为它们不会在每个实例中都携带方法代码。
如果这个构造函数的所有对象都指向同一个变量字段,我可以看到变量如何工作不好,但是方法不应该改变太多或根本不应该改变,所以共享它们不是问题。
是否有理由不在原型上而不是在对象的构造函数上定义方法?
【问题讨论】:
标签: javascript
人们可能更喜欢将方法放在实例本身上的一个原因是在简洁地添加方法的同时确保正确的this 上下文。让this 正常工作是 JavaScript 中非常常见的问题。
例如:
class Foo {
i = 0;
clickHandler = () => console.log(this.i++);
}
const f = new Foo();
window.onclick = f.clickHandler;
这是 React 中类组件的常见模式。如果将方法放在原型上,有时会变得更丑:
class Foo {
i = 0;
clickHandler() {
console.log(this.i++);
}
}
const f = new Foo();
window.onclick = () => f.clickHandler();
另一种常见的处理方法是将绑定方法从原型移动到构造函数中的实例:
class Foo {
i = 0;
constructor() {
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler() {
console.log(this.i++);
}
}
const f = new Foo();
window.onclick = () => f.clickHandler();
这是更喜欢其中一个的原因吗?这取决于您,但要牢记这是一个有争议的优势。
【讨论】:
window.addEventListener("click", () => f.clickHandler())。
fn 时都需要一个() => obj.fn() (并且当需要传递其他参数时会变得更丑陋)。改用类字段(顺便将方法放在实例本身上)只是众多可用选项之一。
只是我的一个想法 - 有一种方法可以处理“正确”的执行上下文,例如单击原型级别的处理程序也是如此。考虑以下示例:
class AbstractClickHandler {
// the "proper" this is ensured via closure over the actual implementation
clickHandler() {
return (...args) => {
this.handleClick.apply(this, args)
}
}
// no-op in base class
handleClick() {
}
}
class ClickHandler extends AbstractClickHandler {
constructor(data) {
super()
this.data = data
}
// actual implementation of the handler logic
handleClick(arg1, arg2) {
console.log(`Click handled with data ${this.data} and arguments ${arg1}, ${arg2}`)
}
}
const instance = new ClickHandler(42)
const handler = instance.clickHandler()
handler.call(null, 'one', 'two')
这样,就不需要在每个相关的构造函数中定义绑定处理程序了。
【讨论】: