整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

在 .NET 平台使用ReflectionDynamicObject优化反射调用代码

于封装的原则,API 的设计者会将部分成员(属性、字段、方法等)隐藏以保证健壮性。但总有需要直接访问这些私有成员的情况。

为了访问一个类型的私有成员,除了更改 API 还有就是使用反射技术:

public class MyApi
{
    public MyApi()
    {
        _createdAt = DateTime.Now;
    }
    private DateTime _createdAt;
    public int ShowTimes { get; private set; }
    public void ShowCreateTime()
    {
        Console.WriteLine(_createdAt);
        ShowTimes++;
    }
}

void Main()
{
    var api = new MyApi();
    var field = api.GetType().GetField("_createdAt", BindingFlags.NonPublic | BindingFlags.Instance);
    var value = field.GetValue(api);
    Console.WriteLine(value);
}

这种写法并不优雅:

  1. 代码冗长,编写麻烦。
  2. 实现比较绕,不太直观。

笔者基于“动态类型技术”探索出了一种相对来说比较优雅的方案用于美化上述代码,并为其命名为 ReflectionDynamicObject :

void Main()
{
    var api = new MyApi();
    dynamic wrapper = ReflectionDynamicObject.Wrap(api);
    Console.WriteLine(wrapper._createdAt);
}

除了支持获取值,ReflectionDynamicObject 还支持赋值:

void Main()
{
    var api = new MyApi();
    dynamic wrapper = ReflectionDynamicObject.Wrap(api);
    wrapper._createdAt = new DateTime(2022, 2, 2, 22, 22, 22);
    api.ShowCreateTime();
}

除了字段,当然也支持对属性的操作:

void Main()
{
    var api = new MyApi();
    dynamic wrapper = ReflectionDynamicObject.Wrap(api);
    wrapper.ShowTimes = 100;
    Console.WriteLine(wraper.ShowTimes);
}

在对属性的支持上,ReflectionDynamicObject 使用了“快速反射”技术,将取值和复制操作生成了委托以优化性能。

ReflectionDynamicObject 的实现原理

ReflectionDynamicObject 派生自 DynamicObject ,其内部通过反射技术获取到所有的属性和字段并对其 getter 和 setter 方法进行存储并通过 TryGetMember 和 TrySetMember 方法经运行时调用。

ReflectionDynamicObject 的源代码

public sealed class ReflectionDynamicObject : DynamicObject
{
    private readonly object _instance;
    private readonly Accessor _accessor;
    private ReflectionDynamicObject(object instance)
    {
        _instance = instance ?? throw new ArgumentNullException(nameof(instance));
        _accessor = GetAccessor(instance.GetType());
    }
    public static ReflectionDynamicObject Wrap(Object value)
    {
        if (value == null) throw new ArgumentNullException(nameof(value));
        return new ReflectionDynamicObject(value);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_accessor.TryFindGetter(binder.Name, out var getter))
        {
            result = getter.Get(_instance);
            return true;
        }
        return base.TryGetMember(binder, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_accessor.TryFindSetter(binder.Name, out var setter))
        {
            setter.Set(_instance, value);
            return true;
        }
        return base.TrySetMember(binder, value);
    }

    #region 快速反射
    private interface IGetter
    {
        object Get(object instance);
    }
    private interface ISetter
    {
        void Set(object instance, object value);
    }

    private class Getter : IGetter
    {
        private FieldInfo _field;
        public Getter(FieldInfo field)
        {
            _field = field ?? throw new ArgumentNullException(nameof(field));
        }
        public object Get(object instance)
        {
            return _field.GetValue(instance);
        }
    }

    private class Setter : ISetter
    {
        private FieldInfo _field;
        public Setter(FieldInfo field)
        {
            _field = field ?? throw new ArgumentNullException(nameof(field));
        }
        public void Set(object instance, object value)
        {
            _field.SetValue(instance, value);
        }
    }

    private class Getter<T1, T2> : IGetter
    {
        private readonly Func<T1, T2> _getter;
        public Getter(Func<T1, T2> getter)
        {
            _getter = getter ?? throw new ArgumentNullException(nameof(getter));
        }
        public object Get(object instance)
        {
            return _getter((T1)instance);
        }
    }

    private class Setter<T1, T2> : ISetter
    {
        private readonly Action<T1, T2> _setter;
        public Setter(Action<T1, T2> setter)
        {
            this._setter = setter ?? throw new ArgumentNullException(nameof(setter));
        }
        public void Set(object instance, object value)
        {
            this._setter.Invoke((T1)instance, (T2)value);
        }
    }

    private class Accessor
    {
        public Accessor(Type type)
        {
            this._type = type ?? throw new ArgumentNullException(nameof(_type));
            var getter = new SortedDictionary<string, IGetter>();
            var setter = new SortedDictionary<string, ISetter>();

            var fields = _type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            foreach (var field in fields)
            {
                getter[field.Name] = new Getter(field);
                setter[field.Name] = new Setter(field);
            }

            var props = _type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            foreach (var item in props)
            {
                if (item.CanRead)
                {
                    var method = item.GetMethod;
                    var funcType = typeof(Func<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var func = method.CreateDelegate(funcType);
                    var getterType = typeof(Getter<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var get = (IGetter)Activator.CreateInstance(getterType, func);
                    getter[item.Name] = get;
                }
                if (item.CanWrite)
                {
                    var method = item.SetMethod;
                    var actType = typeof(Action<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var act = method.CreateDelegate(actType);
                    var setterType = typeof(Setter<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var set = (ISetter)Activator.CreateInstance(setterType, act);
                    setter[item.Name] = set;
                }
            }

            _getters = getter;
            _setters = setter;
        }
        private readonly Type _type;
        private readonly IReadOnlyDictionary<string, IGetter> _getters;
        private readonly IReadOnlyDictionary<string, ISetter> _setters;

        public bool TryFindGetter(string name, out IGetter getter) => _getters.TryGetValue(name, out getter);
        public bool TryFindSetter(string name, out ISetter setter) => _setters.TryGetValue(name, out setter);
    }
    private static Dictionary<Type, Accessor> _accessors = new Dictionary<Type, Accessor>();
    private static object _accessorsLock = new object();
    private static Accessor GetAccessor(Type type)
    {
        if (_accessors.TryGetValue(type, out var accessor)) return accessor;
        lock (_accessorsLock)
        {
            if (_accessors.TryGetValue(type, out accessor)) return accessor;
            accessor = new Accessor(type);
            var temp = new Dictionary<Type, Accessor>(_accessors);
            temp[type] = new Accessor(type);
            _accessors = temp;
            return accessor;
        }
    }
    #endregion
}

ReflectionDynamicObject 的局限性

基于复杂度的考虑,ReflectionDynamicObject 并未添加对“方法”的支持。这也就意味着对方法的调用是缺失的。虽然动态行为让程序摆脱了对字符串的依赖,但是该实现对“重构”的支持仍然不友好。

哪里用到了 ReflectionDynamicObject ?

Liquid 主题引擎 是笔者根据 Liquid 语言和 Shopify 主题机制并采用 Fluid 模板引擎实现的一套 HTML 主题引擎。该引擎允许最终用户自由地修改自己的主题模板而不会对宿主造成影响。最终目标是做到多语言、多主题、高扩展性以及所见即所得。

在编写 Liquid 主题引擎 时,笔者需要重写 Fluid 模板引擎的 render 标签让子视图从 snippets 文件夹加载。在实现该标签时,需要访问 TemplateContext 的 LocalScope 和 RootScope 字段,不幸的是上述字段被标记为了 internal ,无法在外部程序集中访问到。于是便有了 ReflectionDynamicObject ,帮助笔者完成对 LocalScope 和 RootScope 的访问。

参考链接

  • Liquid 模板语言: Liquid 模板语言中文文档 | 码农很忙
  • Fluid 模板引擎:https://github.com/sebastienros/fluid
  • Liquid 主题引擎:智赢科技/Liquid主题引擎

们整理了一份主要的Angular面试问题清单,分为三部分:

  • 角度面试问题–初学者水平
  • 角度面试问题–中级
  • 角度面试问题–高级

初学者水平–面试问题

1.区分Angular和AngularJS。

特征AngularJSAngular
建筑支持MVC设计模型使用组件和指令
语言推荐语言:JavaScript推荐语言:TypeScript
表达式语法图片/属性和事件需要特定的ng指令使用()绑定事件,使用[]进行属性绑定
行动支援不提供任何移动支持提供移动支持
路由$ routeprovider.when()用于路由配置@RouteConfig {(…)}用于路由配置
依赖注入不支持依赖注入的概念支持基于树的单向更改检测的分层依赖注入
结构体难以管理简化的结构,使大型应用程序的开发和维护更加容易
速度通过双向数据绑定,开发工作和时间得以减少升级功能比AngularJS更快
支持不再提供支持或新的更新积极的支持和频繁的新更新

2.什么是Angular?

Angular是一个开放源代码的前端Web框架。它是最流行的JavaScript框架之一,主要由Google维护。它提供了一个轻松开发基于Web的应用程序的平台,并使前端开发人员能够管理跨平台应用程序。它集成了强大的功能,例如声明性模板,端到端工具,依赖项注入以及各种其他使开发路径更流畅的最佳实践。

3.使用Angular有什么优势?

下面列出了使用Angular框架的一些主要优点:

  • 支持双向数据绑定
  • 它遵循MVC模式架构
  • 它支持静态模板和Angular模板
  • 您可以添加自定义指令
  • 它还支持RESTfull服务
  • 支持验证
  • 客户端和服务器之间的通讯便利
  • 支持依赖注入
  • 具有强大的功能,例如事件处理程序,动画等。

4. Angular主要用于什么?

Angular通常用于表示单页应用程序的SPA的开发。Angular提供了一组现成的模块,可简化单页应用程序的开发。不仅如此,Angular还具有内置数据流,类型安全性和模块化CLI的功能,被认为是成熟的Web框架。

5.什么是角度表达式?

角表达式是类似于JavaScript的代码段,通常放在诸如{{expression}}之类的绑定中。这些表达式用于将应用程序数据绑定到HTML

语法:{{expression}}

6. Angular中的模板是什么?

Angular中的模板是使用包含特定于Angular的元素和属性的HTML编写的。这些模板与来自模型和控制器的信息结合在一起,进一步渲染这些信息以向用户提供动态视图。

7. 在Angular中,什么是字符串插值?

Angular中的字符串插值是一种特殊的语法,它在双花括号 {{}}中使用模板表达式来显示组件数据。它也称为小胡子语法。JavaScript表达式包含在花括号中,由Angular执行,然后将相对输出嵌入HTML代码中。这些表达式通常像表一样进行更新和注册,作为摘要循环的一部分。

8. Angular中的Annotation和Decorator有什么区别?

使用Reflect Metadata库,角度注释是类的“唯一”元数据集。它们用于创建“注释”数组。另一方面,装饰器是用于分离装饰或修改类的设计模式,而无需实际更改原始源代码。

9.您对Angular中的控制器了解多少?

控制器是JavaScript函数,可为HTML UI提供数据和逻辑。顾名思义,它们控制数据如何从服务器流到HTML UI。

10. Angular的范围是什么?

Angular中的范围是一个引用应用程序模型的对象。它是表达式的执行上下文。范围以模仿应用程序DOM结构的层次结构排列。范围可以监视表达式并传播事件。

11. Angular中的指令是什么?

Angular的核心功能是指令,这些属性使您可以编写 特定于应用程序的新HTML语法。它们本质上是在Angular编译器在DOM中找到它们时执行的函数。Angular指令分为三部分:

  1. 组件指令
  2. 结构指令
  3. 属性指令

12.什么是数据绑定?

在Angular中,数据绑定是最强大,最重要的功能之一,可让您定义组件与DOM(文档对象模型)之间的通信。它从根本上简化了定义交互式应用程序的过程,而不必担心在视图或模板与组件之间推送和提取数据。在Angular中,数据绑定有四种形式:

  1. 字符串插值
  2. 属性绑定
  3. 事件绑定
  4. 双向数据绑定

13.在Angular中使用过滤器的目的是什么?

Angular中的过滤器用于格式化表达式的值,以便将其显示给用户。这些过滤器可以添加到模板,指令,控制器或服务中。不仅如此,您还可以创建自己的自定义过滤器。使用它们,您可以轻松地组织数据,使数据仅在满足特定条件时才显示。通过使用竖线字符|,将过滤器添加到表达式中,然后是过滤器。

14. Angular和jQuery有什么区别?

特征jQueryAngular
DOM操作
RESTful API没有
动画支持
深层链接路由没有
表格验证没有
双向数据绑定没有
AJAX / JSONP

15. Angular中的提供程序是什么?

提供程序是Angular中的可配置服务。这是对依赖关系注入系统的一条指令,它提供有关获取依赖关系值的方式的信息。它是一个具有$ get()方法的对象,该方法被调用以创建服务的新实例。提供者还可以包含其他方法,并使用$ provide来注册新的提供者。

中级–面试问题

16. Angular是否支持嵌套控制器?

是的,Angular确实支持嵌套控制器的概念。需要以层次方式定义嵌套控制器,以便在视图中使用它。

17.如何区分Angular表达式和JavaScript表达式?

Angular表达式JavaScript表达式
1.它们可以包含文字,运算符和变量。1.它们可以包含文字,运算符和变量。
2.它们可以写在HTML标记内。2.它们不能写在HTML标记内。
3.它们不支持条件,循环和异常。3.它们确实支持条件,循环和异常。
4.它们支持过滤器。4.他们不支持过滤器。

18.列出使用核心Angular功能在应用程序模块之间进行通信的方式。

以下是使用核心Angular功能在应用程序模块之间进行通信的最通用方法:

  • 使用事件
  • 使用服务
  • 通过在$ rootScope上分配模型
  • 直接在控制器之间[ $ parent$$ childHead$$ nextSibling等]
  • 直接在控制器之间[ ControllerAs或其他继承形式]

19. service()和factory()有什么区别?

Angular中的service()是用于应用程序业务层的函数。它作为构造函数运行,并在运行时使用'new'关键字调用一次。而factory()是一个类似于service()的函数,但功能更强大,更灵活。factory()是有助于创建对象的设计模式。

20. $ scope和Angular中的scope有什么区别?

  • Angular中的$ scope用于实现依赖项注入(DI)的概念,另一方面,scope 用于指令链接。
  • $ scope是$ scopeProvider提供的服务,可以注入到控制器,指令或其他服务中,而Scope可以是任何东西,例如函数参数名称等。

21.解释范围层次的概念吗?

Angular中的$ scope对象被组织成一个层次结构,并且主要由视图使用。它包含一个根范围,该范围可以进一步包含称为子范围的范围。一个根作用域可以包含多个子作用域。在这里,每个视图都有自己的$ scope,因此由其视图控制器设置的变量将对其他控制器隐藏。范围层次结构通常如下所示:

  • 根$ scope
    • 控制器1的$ scope
    • 控制器2的$ scope
    • ..
    • 控制器'n'的$ scope

22.什么是AOT?

AOT代表Angular-Ahead-of-Time编译器。它用于在构建过程中预编译应用程序组件及其模板。用AOT编译的Angular应用程序的启动时间更短。同样,这些应用程序的组件可以立即执行,而无需任何客户端编译。这些应用程序中的模板作为代码嵌入其组件中。它减少了下载Angular编译器的需要,从而使您免于繁琐的任务。AOT编译器可以丢弃未使用的指令,这些指令会使用摇树工具进一步丢弃。

23.解释jQLite。

jQlite也称为 jQuery litejQuery的子集,包含其所有功能。默认情况下,它打包在Angular中。它帮助Angular以兼容的跨浏览器方式操作DOM。jQLite基本上仅实现最常用的功能,因此占用空间小。

24.解释Angular中的摘要循环过程?

Angular中的摘要周期是监视监视列表的过程,以跟踪监视变量的值的变化。在每个摘要循环中,Angular都会比较范围模型值的先前版本和新版本。通常,此过程是隐式触发的,但是您也可以使用$ apply()手动将其激活。

25.什么是Angular模块?

所有Angular应用程序都是模块化的,并遵循称为NgModules的模块化系统。这些容器保存着专门用于应用程序域,工作流或一组紧密相关的功能的内聚代码块。这些模块通常包含组件,服务提供商和其他代码文件,其范围由包含的NgModule定义。有了模块,代码变得更加可维护,可测试和易读。同样,应用程序的所有依赖关系通常仅在模块中定义。

26.我们可以在哪种类型的组件上创建自定义指令?

Angular支持创建以下内容的自定义指令:

  • 元素指令 -当遇到匹配的元素时,指令将激活。
  • 属性 -当遇到匹配的属性时,指令将激活。
  • CSS- 指令会在遇到匹配的CSS样式时激活。
  • 注释 -遇到匹配的注释时,指令将激活

27. Angular中有哪些不同类型的过滤器?

以下是Angular支持的各种过滤器:

  • 货币: 将数字格式化为货币格式。
  • 日期: 将日期格式化为指定的格式。
  • filter: 从数组中选择项的子集。
  • json: 将对象格式化为JSON字符串。
  • limit:将数组/字符串限制为指定数量的元素/字符。
  • 小写: 将字符串格式化为小写
  • number: 将数字格式化为字符串。
  • orderBy: 按表达式对数组排序
  • 大写: 将字符串格式化为大写

28.什么是Angular中的依赖注入?

依赖注入(DI)是一种软件设计模式,其中对象作为依赖关系传递,而不是在组件中对其进行硬编码。当您尝试将对象创建的逻辑与使用对象的逻辑分开时,依赖注入的概念会派上用场。“ config”操作使用DI,在加载模块以检索应用程序的元素时,必须预先配置DI。使用此功能,用户可以根据自己的要求更改依赖关系。

29.区分单向绑定和双向数据绑定。

单向数据绑定中,无论何时更改数据模型,“视图”或“ UI”部分都不会自动更新。您需要手动编写自定义代码,以便在每次视图更改时对其进行更新。

而在双向数据绑定中,一旦更改数据模型,则隐式更新View或UI部分。与单向数据绑定不同,这是一个同步过程。

30.组件和指令的生命周期挂钩是什么?

Angular组件具有离散的生命周期,其中包含从出生到死亡过渡的不同阶段。为了更好地控制这些阶段,我们可以使用以下方法将其连接:

  • 构造函数: 通过在类上调用new创建组件或指令时将调用它。
  • ngOnChanges:每当组件的任何输入属性发生更改或更新时,都将调用它。
  • ngOnInit:每次初始化给定组件时都会调用它。在第一个ngOnChanges之后,该挂钩在其生命周期中仅被调用一次。
  • ngDoCheck:每当调用给定组件的更改检测器时,便会调用它。这使您可以为提供的组件实现自己的变更检测算法。
  • ngOnDestroy: 在Angular销毁组件之前立即调用它。您可以使用此钩子来取消订阅可观察对象并分离事件处理程序,以避免发生任何类型的内存泄漏。

31.通过对Angular进行脏检查,您了解什么?

在Angular中,摘要过程称为脏检查。之所以调用它,是因为它扫描整个范围以进行更改。换句话说,它将所有新的作用域模型值与以前的作用域值进行比较。由于所有监视变量都包含在单个循环中,因此任何变量的任何更改/更新都将导致重新分配DOM中存在的其余监视变量。被监视的变量处于单个循环(摘要循环)中,任何变量的任何值更改都会在DOM中重新分配其他被监视变量的值

32.区分DOM和BOM。

DOM物料清单
1.代表文档对象模型1.代表浏览器对象模型
2.表示网页的内容2.在网页上方工作,并包含浏览器属性
3.所有对象都以树状结构排列,并且只能通过提供的API来操作和访问文档3.所有全局JavaScript对象,变量和函数都隐式地成为window对象的成员
4.处理HTML文档4.访问和操纵浏览器窗口
5. W3C推荐的标准规格5.每个浏览器都有自己的实现

33.什么是Angular中的Transpiling?

Angular中的编译是指将源代码从一种编程语言转换为另一种编程语言的过程。通常,在Angular中,此转换是从TypeScript到JavaScript的。这是一个隐式过程,在内部发生。

34. How to perform animation in Angular?

为了在Angular应用程序中执行动画,您需要包括一个称为Animate Library的特殊Angular库,然后将ngAnimate模块引用到您的应用程序中,或者将ngAnimate作为依赖项添加到您的应用程序模块内部。

35.什么是Angular中的包含?

Angular中的包含可让您将指令的原始子代转移到新模板内的特定位置。ng指令指示正在使用包含的最近父指令的已包含DOM的插入点。诸如ng-transcludeng-transclude-slot之类的属性指令主要用于包含。

36. Angular中的事件是什么?

Angular中的事件是特定的指令,可帮助自定义各种DOM事件的行为。以下列出了Angular支持的事件:

  • ng-click
  • ng-copy
  • ng-cut
  • ng-dblclick
  • ng-keydown
  • ng-keypress
  • ng-keyup
  • ng-mousedown
  • ng-mouseenter
  • ng-mouseleave
  • ng-mousemove
  • ng-mouseover
  • ng-mouseup
  • ng-blur

37.列出一些用于测试角度应用的工具吗?

  1. Karma
  2. Angular Mocks
  3. Mocha
  4. Browserify
  5. Sion

38.如何在Angular中创建服务?

在Angular中,服务是可替换对象,该对象使用依赖项注入连接在一起。通过将服务注册到要在其中执行的模块中来创建服务。基本上,您可以通过三种方式创建角度服务。基本上,它们是在Angular中创建服务的三种方式:

  • Factory
  • Service
  • Provider

39.什么是单例模式,在Angular中可以找到它?

Angular中的Singleton模式是一种很棒的模式,它限制了一个类不能被多次使用。Angular中的Singleton模式主要在依赖项注入和服务中实现。因此,如果您不使用“ new Object()”而未将其设为单例,则将为同一对象分配两个不同的存储位置。而如果将该对象声明为单例,则如果该对象已存在于内存中,则将简单地将其重用。

40.您对Angular中的REST了解那些?

REST表示RE表象小号大老牛逼转让(BOT)。REST是适用于HTTP请求的API(应用程序编程接口)样式。在这种情况下,所请求的URL可以精确定位需要处理的数据。然后,HTTP方法将标识需要对请求的数据执行的特定操作。因此,遵循此方法的API被称为RESTful API。

41. Angular中的自举是什么?

在Angular中进行引导只是初始化或启动Angular应用程序。Angular支持自动和手动引导。

  • 自动引导程序:这是通过将ng-app指令添加到应用程序的根目录来完成的,通常是在标记或标记上(如果您希望angular自动引导应用程序)。当Angular找到ng-app指令时,它将加载与其关联的模块,然后编译DOM。
  • 手动引导: 手动引导为您提供了有关如何以及何时初始化Angular应用程序的更多控制。如果您想在Angular唤醒并编译页面之前执行任何其他操作,这将非常有用。

42.在Angular中链接和编译有什么区别?

  • 编译功能用于模板DOM操纵并收集所有指令。
  • 链接功能用于注册DOM侦听器以及实例DOM操作,并在克隆模板后执行。

43. 您对Angular中的常数有什么了解?

在Angular中,常量类似于用于定义全局数据的服务。常量使用关键字“ constant”声明。它们是使用恒定依赖性创建的,可以注入控制器或服务中的任何位置。

44. Angular的提供者,服务和工厂之间有什么区别?

提供者服务
提供程序是一种可以将应用程序的一部分传递到app.config中的方法服务是一种用于创建以'new'关键字实例化的服务的方法。这是用于创建和配置服务的方法。在这里,您可以创建一个对象,向其中添加属性,然后返回相同的对象,并将工厂方法传递到控制器中。

45. 什么是Angular Global API?

Angular Global API是用于执行各种常见任务的全局JavaScript函数的组合,例如:

  • 比较对象
  • 迭代对象
  • 转换数据

有一些常见的Angular Global API函数,例如:

  • 有角的。小写:将字符串转换为小写字符串。
  • 有角的。大写: 将字符串转换为大写字符串。
  • 有角的。isString: 如果当前引用是字符串,则返回true。
  • 有角的。isNumber:如果当前引用为数字,则返回true。

高级水平–面试问题

46.在Angular中,描述如何设置,获取和清除cookie?

为了在Angular中使用cookie,您需要包含一个名为ngCookies angular-cookies.js的模块。

设置Cookies –为了以键值格式设置Cookies,使用“ put”方法。

cookie.set("nameOfCookie","cookieValue");

获取Cookie –为了获取Cookie,使用了“ get”方法。

cookie.get("nameOfCookie");

清除Cookie –使用“删除”方法删除Cookie。

cookie.delete("nameOfCookie");

47. 如果您的数据模型是在"区域"之外更新的,请说明该过程,您将如何查看视图?

您可以使用以下任意一种来更新视图:

  1. ApplicationRef.prototype.tick():它将对整个组件树执行更改检测。
  2. NgZone.prototype.run():它将对整个组件树执行更改检测。在这里,引擎盖下的run()将调用tick本身,然后参数将在tick之前获取函数并执行它。
  3. ChangeDetectorRef.prototype.detectChanges():它将在当前组件及其子组件上启动更改检测。

48.在Angular中解释ng-app指令。

ng-app指令用于定义Angular应用程序,使我们可以在Angular应用程序中使用自动引导。它表示Angular应用程序的根元素,通常在或标签附近声明。在HTML文档中可以定义任何数量的ng-app指令,但是只有一个Angular应用程序可以被隐式地正式引导。其余应用程序必须手动引导。

<div ng-app=“myApp” ng-controller=“myCtrl”>
First Name :
<input type=“text” ng-model=“firstName”>
<br />
Last Name :
<input type=“text” ng-model=“lastName”>
<br>
Full Name: {{firstName + ” ” + lastName }}
</div>  

49.从准备好的TemplateRef插入嵌入视图的过程是什么?

@Component({
    selector: 'app-root',
    template: `
        <ng-template #template let-name='fromContext'><div>{{name}}</ng-template>
    `
})
export class AppComponent implements AfterViewChecked {
    @ViewChild('template', { read: TemplateRef }) _template: TemplateRef<any>;
    constructor() { }

    ngAfterViewChecked() {
        this.vc.createEmbeddedView(this._template, {fromContext: 'John'});
    }
}

50.如何仅通过单击角形按钮即可隐藏HTML元素?

可以使用ng-hide指令与控制器一起轻松隐藏HTML元素,以在单击按钮时隐藏HTML元素。

View

<div ng-controller ="MyController">
  <button ng-click ="hide()">欢迎关注全栈程序员社区公众号</ button>
  <p ng-hide ="isHide">欢迎关注Java架构师社区公众号!</ p>
</ div>

Controller

controller: function() {
    this.isHide = false;
    this.hide = function(){
        this.isHide = true; 
    }; 
}

欢迎关注 Java架构师社区公众号.本文转载自Java架构师必看 ,更多内容点击查看!

ngularJs作用域理解

基于AngularJS入门与进阶(江荣波 著)这本书的笔记

AngularJS 1.x的demo

AngularJS1.x和Angular2,4,5是不一样的两个东西,构建方式,语法,都很多不同


每个AngularJS应用至少会有一个名称为$rootScope的作用域,它是AngularJS应用的根作用域。框架中的ng-app指令,它可以出现在任何HTML标签中,用于启动AngularJS框架。当AngularJS启动时会自动创建一个根作用域对象$rootScope,当使用ng-controller指令实例化控制器对象时,AngularJS框架会创建一个子作用域$scope,默认情况下,该子作用域会继承$rootScope作用域的所有属。

如下代码就是ng-init指令在$rootScope作用域对象中新增了userName属性,然后在scopeController控制器的子作用域中取到成功输出name:jock

<!DOCTYPE html>
<html lang="en" ng-app="scopeApp">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script  src="/lib/angular/angular.js"></script>
    <script type="text/javascript">
        var scopeApp = angular.module("scopeApp",[]);
        scopeApp.controller("scopeController",function ($scope,$log) {
            $log.log("name:" + $scope.userName)
        });
    </script>
</head>
<body ng-init="userName='jock'">
    <div ng-controller="scopeController"></div>
</body>
</html>

AngularJs作用域继承

JavaScript对像继承机制

JavaScript对像继承机制有三种

  1. 构造方法原型链继承
  2. 使用appley、call方法实现继承
  3. 对像实例间继承

AngularJs是基于方法原型链继承实现的,这里记录下概念,书中原话:每个JavaScript构造方法都有一个名称为prototype的属性,可以指向另一个对象。当我们访问对象属性时(例如obj.name),JavaScript引擎会从对象的所有属性中查找该属性,如果找到就返回属性值,如果没有找到就继续从prototype属性指向的对象属性中查找,如果仍然没有找到,则会沿着prototype链一直查找下去,直到prototype链结束或找到对象为止。

    <script type="text/javascript">
        function People() {
            this.eat = function () {
                console.log("pelple eat------------")
            }
        }
        
        function Man(age) {
            this.age = age;
        }
        // Man 的prototype属性指向People
        Man.prototype = new People();
        var man =  new Man("20");
        console.log(man.age);
        // 本身如果没有,会找指向的prototype 对像
        man.eat();
    </script>

控制台输出

20
pelple eat------------
AngularJs作用域对像原型继承

AngularJs继承采用构造方法原型继承,在AngularJs作用域构造方法中提供了一个$new()成员方法,用于创造子作用域,源码这里就不重复了,书里面很详细,只记录下过程

    var parent = $rootScope;
    var child = parent.$new();

示例代码


<!DOCTYPE html>
<html lang="en" ng-app="scopeApp">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script  src="/lib/angular/angular.js"></script>
    <script type="text/javascript">
        var scopeApp = angular.module("scopeApp",[]);
        scopeApp.controller("fatherScope",function ($scope,$log) {
            $scope.age = "18";
        });
        scopeApp.controller("childScope",function ($scope,$log) {
            $scope.sex = "男";
            console.log("name:" + $scope.userName + " "+ "age:" + $scope.age + " " + "sex:" + $scope.sex );
        });

    </script>
</head>
<body ng-init="userName='jock'">
    <div ng-controller="fatherScope">
        <div ng-controller="childScope"></div>
    </div>
</body>
</html>

控制台成功输出

name:jock age:18 sex:男

AngularJS框架查找到ng-app指令时启动应用,创建$rootScope作用域。然后AngularJS框架查找到第一个ng-controller指令,指向名称为fatherScope的控制器,并调用$rootScope.$new()方法,以原型继承的方式创建$rootScope作用域的子作用域对象(记为$scope1)。当fatherScope构造方法接收一个名称为$scope的参数时,AngularJS实例化控制器对象时会把$scope1对象注入控制器对象中。接下来AngularJS继续遍历DOM元素,遇到第二个嵌套的ng-controller指令时调用$scope1.new()方法,以$scope1为原型创建子作用域(记为$scope2,$scope2作用域对象能够访问$scope1作用域对象的所有属性)。