为什么 Angular $resource return 是 Resource 对象而不是 class 对象?

Why does Angular $resource return a Resource object instead of the class object?

使用 CoffeeScript、Angular 和 $resource,我创建了以下工厂:

angular.module('myapp', ['ngResource']).factory 'MyObject', ['$resource', ($resource) ->
    MyObjectResource = $resource '/api/my_object/:id', {
      id: '@id'
    }, {
      update:
        method: 'PUT'
    }

    class MyObject extends MyObjectResource

      someMethod: ->
        dosomething
 ]

问题是当我从我的 API 加载一个对象时,我得到一个 Resource 对象而不是 MyObject 对象,这是一个问题,因为我不知道无法访问我的其他方法。

这是我获取对象的代码:

result = MyObject.get({id: 1})

如果我打印 result,我可以看到:

Resource {id: 1, details: 'somestuff'}

相比之下,我希望有:

MyObject {id: 1, details: 'somestuff'}

这将使我能够访问 someMethod 以及我为此 class 定义的所有其他方法。

我是不是做错了什么?

提前致谢。

快速查看源代码后,我看到以下关系:

  1. 在工厂内部创建了一个 Resource 函数(它是 $resource 提供者)并且在调用 $resource 时被 return 编辑。

资源具有以下结构(假设我们只想了解它具有什么方法而不是每个方法的作用)

function Resource(value) { ... }
Resource.prototype.toJSON = function () { ... }
Resource.prototype.bind = function () { ... }
  1. 我还看到 $resource 函数在第三个参数中接收要在 Resource 函数上设置的附加操作(与一些默认操作合并),我看到你是发送额外的 update 方法,因此对象具有以下结构

合并 update 与默认操作:

{
  'get': {method: 'GET'},
  'save': {method: 'POST'},
  'query': {method: 'GET', isArray: true},
  'remove': {method: 'DELETE'},
  'delete': {method: 'DELETE'},
  // added by the user
  update: { method: 'PUT' }
}

$resourceResource 函数上为这个散列的每个 属性 设置一个方法,也在 Resource 的原型上附加一个 $方法名称,即

Resource.get = function () { ... }
Resource.save = function () { ... }
Resource.update = function () { ... }
...

Resource.prototype.$get = function () { ... }
Resource.prototype.$save = function () { ... }
Resource.prototype.$update = function () { ... }
...

现在 return 正在对您的代码进行扩展 MyObject 来自 MyObjectResource 的新函数,其中 MyObjectResource 是调用 $resource 的结果,即上面看到的 Resource 函数,coffeescript 的 extend 实际上会将 MyObjectResource 上定义的所有属性复制到 MyObject 并且还会使隐藏的 [[Prototype]] 属性 MyObject.prototype 指向 MyObjectResource.prototype:

MyObjectResource                
  prototype     ------->  MyObjectResource.prototype
                            $get
  get                       $save
  save                      toJSON
  ...                       ...
                             ^
                             |
MyObject                     |
  prototype     ------->  MyObject.prototype
  get (reference)           someMethod
  set (reference)
  ...

所以这就是为什么你可以做 MyObject.get 因为它现在有一个对 MyObjectResource.get 的引用,即 MyObject.get === MyObjectResource.get

这是有趣的部分,调用 MyObject.get 将 return MyObjectResrouce 的一个实例(这实际上是硬编码的,但只有在 MyObject.get this 内部时才会发生不是 MyObjectResource Source 的实例),如果我们这样做 new MyObjectResource() 就没有办法访问 someMethod 因为它实际上是在 "subclass".[=52 中定义的=]

但是我们可以创建 MyObject 的实例,并且由于 coffeescript extend 创建的链接,该实例可以通过 MyObjectResource.prototype.$get 访问相同的 get,所以:

var instance = new MyObject()
instance.$get({id: 1});     // works because of the link created between the prototypes
instance.someMethod();      // also works