ES6箭头函数的getter/setter

176

我正在使用Babel6,并为我的宠物项目创建一个XMLHttpRequest包装器,对于可以使用的方法:

open = (method, url, something) => {
  return this.xhr.open(method, url, something);
}

但对于属性,箭头函数不起作用。

这个是可行的:

get status() { return this.xhr.status; }

但是我无法使用

get status = () => this.xhr.status;

这是故意的吗?


你不需要花括号或return语句;你可以直接写成(method, url, something) => this.xhr.open(method. url, something) - user663031
get 是对象字面量或类定义的一部分,变量赋值不是。为什么您认为它们应该工作方式相同呢? - Bergi
5
"status => this.xhr.status" (C# 7 语法)或者 "get status() => this.xhr.status" 确实是一种很好的语法糖,可以提高可读性。但是 JavaScript 不支持这种语法(至少目前还不支持),而 TypeScript 可以支持。 - Charles HETIER
我在生活中非常需要这个!!! - Cristian E.
3个回答

185
根据ES2015语法,对象字面量上的属性 只能是以下三种之一:

PropertyDefinition:

  • IdentifierReference
  • PropertyName : AssignmentExpression
  • MethodDefinition
只有 MethodDefinition 允许前置 get

MethodDefinition

  • PropertyName StrictFormalParameters { FunctionBody }
  • GeneratorMethod
  • get PropertyName ( ) { FunctionBody }
  • set PropertyNamePropertySetParameterList { FunctionBody }

正如您所看到的,get形式遵循非常有限的语法,必须是以下形式:

get NAME () { BODY }

语法不允许形如 get NAME = ... 的函数。

谢谢你的帮助,我接受了你的答案。你知道在哪里定义了getter/setter不能与赋值一起使用吗?只是好奇。 - Gabor Dolla
@GaborDolla 编辑后引用ECMAScript规范中的对象字面量语法。 - apsillers

71

被接受的答案很棒。如果你愿意使用普通函数语法/对象初始化/方法定义语法,比如get NAME () { BODY },而不是紧凑的“箭头函数语法”。

但也许你真的喜欢箭头函数;也许你出于其他原因使用箭头函数而普通函数语法不能替代;你可能需要一个不同的解决方案。

例如,我注意到OP使用了this,你可能希望词法地绑定this,也称为“非绑定的this”),而箭头函数在这种词法绑定方面表现良好。

你仍然可以使用箭头函数与 getter 结合,通过 Object.defineProperty 技术来实现,具体使用 访问器描述符 方法:
{
  ...
  Object.defineProperty(your_obj, 'status', { 
     get : () => this.xhr.status 
  });
  ...
}

看到对象初始化技术(也称为get NAME() {...}defineProperty技术(也称为get : ()=>{}的提及。至少有一个重要的区别,使用defineProperty需要变量已经存在:

现有对象上定义getter

使用Object.defineProperty时,您必须确保your_obj(在我的示例中)存在并保存到一个变量中(而使用object-initialization则可以在对象初始化中返回一个对象字面量:{..., get(){ }, ... })。有关Object.defineProperty的更多信息,请点击此处Object.defineProperty(...)方法的一个优点是您可以在循环中运行代码(即定义多个属性)。
另一种方法的区别在于当您在上使用get与在类的实例上使用defineProperty时:

使用get时,属性将被定义在实例的原型上,而使用Object.defineProperty()时,属性将被定义在应用该方法的实例上

Object.defineProperty(...)似乎具有与get NAME(){...}语法相当的浏览器支持;现代浏览器,IE 9。

注意使用Object.defineProperty(...)时可用的其他选项:

  • enumerable:如果您希望使用Object.keys枚举/迭代新属性,请将其设置为true
  • configurable:如果您希望重新定义或删除属性,请将其设置为true

19
聪明,但它比只有 get status() { return this.xhr.status; } 更冗长。 - devuxer
8
我同意它太啰嗦了。但是为了明确,你的 this 必须是定义了 get status() { ... } 的对象。但是,由于词法绑定的差异,我的 this 可能是其他东西,对吗? - Nate Anderson
3
同意...尽管在实践中,我还没有碰到过在 get 访问器中 this 不是我想要的情况。(箭头函数的 this 绑定好像在传递函数时发挥作用,例如在事件处理程序和回调函数中。) - devuxer
4
我同意,我经常在传递给Promise的回调中使用 fat arrow + 词法绑定 ()=>{},比如 $http(...).then((promise_result)=> this...}))。如果我不使用fat-arrow,那么this将代表全局的Window对象,这样并没有什么用处。但是我很少(或者从来没有)将()=>{}作为“获取器”的函数,就像你所说的一样......至少get()内部的this将表示定义get()的对象(这已经比Window更有用了,所以没必要使用fat-arrow函数!)。 - Nate Anderson
2
defineProperty方法在循环中非常有用。目前我只是用它来从包含对象中公开子对象的某些属性。 - Edurne Pascual
显示剩余2条评论

0
是的,JavaScript 中不能使用箭头函数来定义属性是有意为之的。箭头函数没有自己的 this 绑定,因此不能用于访问所定义对象上的属性。
在你的示例中,status 属性是在 XMLHttpRequest 对象上定义的。如果尝试使用箭头函数来定义 status 属性,箭头函数将无法与 XMLHttpRequest 对象绑定,因此无法访问 status 属性。
要使用箭头函数定义属性,可以使用 Object.defineProperty() 方法。例如,以下代码使用箭头函数定义了一个 status 属性:
const xhr = new XMLHttpRequest();
Object.defineProperty(xhr, 'status', {
  get: () => this.xhr.status,
});

这段代码使用Object.defineProperty()方法在xhr对象上定义一个名为status的属性。status属性的get属性是一个箭头函数,返回XMLHttpRequest对象上status属性的值。

希望对你有所帮助!如果有其他问题,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接