Javascript 仍然对angularjs服务和工厂感到困惑

Javascript 仍然对angularjs服务和工厂感到困惑,javascript,angularjs,Javascript,Angularjs,我读过几篇关于angularjs服务和工厂的文章。我知道服务是单例的,工厂返回对象的实例。但我还是不知道如何使用它们。我的应用程序是一个简单的社交网络。使用该应用程序的用户需要登录,然后才能查看其他成员并向他们发送消息 我的理想设计是: 创建一个成员对象来表示我的服务的任意成员。每当“list”或“get”操作返回数据时,它都会被包装在这个成员中,这样我就可以对其调用实用程序方法。我会用工厂来做这个 当用户登录到应用程序时,创建一个代表他们的成员(包含他们的用户ID和身份验证令牌,用于将来的身份

我读过几篇关于angularjs服务和工厂的文章。我知道服务是单例的,工厂返回对象的实例。但我还是不知道如何使用它们。我的应用程序是一个简单的社交网络。使用该应用程序的用户需要登录,然后才能查看其他成员并向他们发送消息

我的理想设计是:

  • 创建一个成员对象来表示我的服务的任意成员。每当“list”或“get”操作返回数据时,它都会被包装在这个成员中,这样我就可以对其调用实用程序方法。我会用工厂来做这个
  • 当用户登录到应用程序时,创建一个代表他们的成员(包含他们的用户ID和身份验证令牌,用于将来的身份验证请求)。这必须对其他作用域可用,因此可以附加到$rootScope,也可以是返回为经过身份验证的用户定制的成员实例的MemberService
  • 我创建了以下内容:

    angular.module('myapp.models', [])
    .factory('Member', ['$log', 'DataService', '$http', 'Restangular',
        function($log, DataService, $http, Restangular) {
            return {
                user_id: null,
                first_name: null,
                last_name: null,
    
                authenticate: function(username, password, loginSuccessHandler, loginErrorHandler) {
                    $log.debug("inside Member.authenticate");
    
                    var authSuccessHandler = function(data, status, headers, config) {
                        $http.defaults.headers.common.Authorization = 'Basic ' + btoa(data._id + ':' + data.token);
                        var token = btoa(data._id + ':' + data.token);
                        user_id = data._id;       // attach this to the rootScope? Needs to be
                                                  // globally accessible (or even this whole object)
                        Restangular.setDefaultHeaders({'Authorization': 'Basic ' + token});
                        $log.debug("Auth successful, token stored " + token);
                        loginSuccessHandler();
                    };
    
                    DataService.authenticate(username, password, authSuccessHandler, authErrorHandler);
                },
          ...
    
    我如何实例化它并将其提供给其他作用域(例如,在其他作用域中我知道登录用户的ID)


    另外,在分析成员列表时,如何实例化此对象?例如,如果我有一个对象
    {名字:“John”,姓氏:“Smith”}
    我如何从这个工厂获得一个设置了这些属性的成员对象?

    工厂
    服务
    都是
    提供者
    的抽象

    这是angular用于实例化新提供程序的方法:

    function provider(name, provider_) {
        if (isFunction(provider_) || isArray(provider_)) {
            provider_ = providerInjector.instantiate(provider_);
        }
        if (!provider_.$get) {
            throw Error('Provider ' + name + ' must define $get factory method.');
        }
        return providerCache[name + providerSuffix] = provider_;
    }
    
    第一部分在angular应用程序加载时实例化一个新的(单例)对象。
    $get
    方法用作新对象的构造函数。这就是
    提供者的实例化可能的样子(来自angular的文档):

    以下是如何配置提供程序。在
    module.config()
    块中,与稍后将提供程序注入控制器/指令/服务时不同,我们得到的是单例,而不是
    $get
    方法的返回值

    myApp.config(["unicornLauncherProvider", function(unicornLauncherProvider) {
      unicornLauncherProvider.useTinfoilShielding(true);
    }]);
    
    然后,每当您注入并调用
    unicornLauncher
    时,
    $get
    方法中的内容都将被调用,并且您将获得一个新的
    unicornLauncher
    ,在这种情况下,它具有所提供的配置,
    useTinfoilShielding=true

    如您所见,提供者有两个部分。首先,它是一个单例,在angular加载时进行实例化和配置,并推送到
    providerCache
    ,因此您可以在整个应用程序中使用它。它还有一个用于实例化新对象的
    $get
    方法

    您可以这样看待它:singleton将其属性和方法作为您在加载应用程序时设置的设置和数据,然后您可以创建使用这些设置和数据的新对象

    如果您创建了一个供其他人使用的模块,则需要分别使用每个应用程序的选项对其进行修改,这就是您要做的。你可以将提供者注入到你的应用程序中,对其进行配置,然后让它按照我们在配置提供者时设置的预设,根据你的需要分发对象

    然后我们有服务工厂。这些实际上是
    提供者
    的抽象。以下是angular用于启动
    工厂的函数:

    function factory(name, factoryFn) {
        return provider(name, { $get: factoryFn });
    }
    
    它只是一个
    提供程序
    ,但它并没有返回一个包含我们看到的所有属性的对象,而是返回一个只包含
    $get
    方法的对象,并且没有任何其他可变部分,如
    提供程序

    以下是
    服务的功能:

    function service(name, constructor) {
        return factory(name, ['$injector', function($injector) {
            return $injector.instantiate(constructor);
        }]);
    }
    
    这里我们有一个工厂,它的
    $get
    方法使用提供的构造函数返回一个由angular实例化的单例。所以你有一个可以在整个应用程序中使用的单例,你可以在任何地方使用它的方法。你可以在一个地方设置它的属性,并在应用程序的其他地方看到你设置的相同值,因为无论你在哪里注入它,它都是相同的单例对象

    摘要

    主要区别在于
    服务
    是angular根据声明服务时提供的构造函数创建的对象,
    工厂
    只是一个可以用来创建新对象的函数,就像在本机JavaScript中一样

    希望有助于理解
    工厂
    服务


    回到你的问题上来

    在您的例子中,您有一个工厂,您希望使用它为每个成员创建一个新对象。在注入
    成员的控制器中,您只需执行以下操作:

    var data = {first_name: "John", last_name: "Smith"} 
    var member = new Member(data);
    
    对您的工厂进行一个小改动:

    .factory('Member', ['$log', 'DataService', '$http', 'Restangular',
        function($log, DataService, $http, Restangular) {
            return function(data) {
            //construct the object
            }
    ])
    

    对工厂的
    new
    调用(作为构造函数注入)将返回一个新的、唯一的对象,其构造方式与JS中的任何其他对象一样。你可以用它做任何你想做的事。您可以将其保留在控制器、
    $rootScope
    或保存成员和其他相关数据和函数的服务中。然后你可以在整个应用程序的任何地方注入该服务。

    我只想说服务和工厂以及提供商都是单身


    对于其他人,请检查以下答案:

    我总是说,如果理解某事物的原理如此困难,那么为什么还要尝试使用它呢?谢谢。你的答案加上现场的视频帮助很大。
    .factory('Member', ['$log', 'DataService', '$http', 'Restangular',
        function($log, DataService, $http, Restangular) {
            return function(data) {
            //construct the object
            }
    ])