整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          在 .NET 平臺(tái)使用ReflectionDynamicObject優(yōu)化反射調(diào)用代碼

          于封裝的原則,API 的設(shè)計(jì)者會(huì)將部分成員(屬性、字段、方法等)隱藏以保證健壯性。但總有需要直接訪問這些私有成員的情況。

          為了訪問一個(gè)類型的私有成員,除了更改 API 還有就是使用反射技術(shù):

          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);
          }

          這種寫法并不優(yōu)雅:

          1. 代碼冗長(zhǎng),編寫麻煩。
          2. 實(shí)現(xiàn)比較繞,不太直觀。

          筆者基于“動(dòng)態(tài)類型技術(shù)”探索出了一種相對(duì)來(lái)說比較優(yōu)雅的方案用于美化上述代碼,并為其命名為 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();
          }

          除了字段,當(dāng)然也支持對(duì)屬性的操作:

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

          在對(duì)屬性的支持上,ReflectionDynamicObject 使用了“快速反射”技術(shù),將取值和復(fù)制操作生成了委托以優(yōu)化性能。

          ReflectionDynamicObject 的實(shí)現(xiàn)原理

          ReflectionDynamicObject 派生自 DynamicObject ,其內(nèi)部通過反射技術(shù)獲取到所有的屬性和字段并對(duì)其 getter 和 setter 方法進(jìn)行存儲(chǔ)并通過 TryGetMember 和 TrySetMember 方法經(jīng)運(yùn)行時(shí)調(diào)用。

          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 的局限性

          基于復(fù)雜度的考慮,ReflectionDynamicObject 并未添加對(duì)“方法”的支持。這也就意味著對(duì)方法的調(diào)用是缺失的。雖然動(dòng)態(tài)行為讓程序擺脫了對(duì)字符串的依賴,但是該實(shí)現(xiàn)對(duì)“重構(gòu)”的支持仍然不友好。

          哪里用到了 ReflectionDynamicObject ?

          Liquid 主題引擎 是筆者根據(jù) Liquid 語(yǔ)言和 Shopify 主題機(jī)制并采用 Fluid 模板引擎實(shí)現(xiàn)的一套 HTML 主題引擎。該引擎允許最終用戶自由地修改自己的主題模板而不會(huì)對(duì)宿主造成影響。最終目標(biāo)是做到多語(yǔ)言、多主題、高擴(kuò)展性以及所見即所得。

          在編寫 Liquid 主題引擎 時(shí),筆者需要重寫 Fluid 模板引擎的 render 標(biāo)簽讓子視圖從 snippets 文件夾加載。在實(shí)現(xiàn)該標(biāo)簽時(shí),需要訪問 TemplateContext 的 LocalScope 和 RootScope 字段,不幸的是上述字段被標(biāo)記為了 internal ,無(wú)法在外部程序集中訪問到。于是便有了 ReflectionDynamicObject ,幫助筆者完成對(duì) LocalScope 和 RootScope 的訪問。

          參考鏈接

          • Liquid 模板語(yǔ)言: Liquid 模板語(yǔ)言中文文檔 | 碼農(nóng)很忙
          • Fluid 模板引擎:https://github.com/sebastienros/fluid
          • Liquid 主題引擎:智贏科技/Liquid主題引擎

          們整理了一份主要的Angular面試問題清單,分為三部分:

          • 角度面試問題–初學(xué)者水平
          • 角度面試問題–中級(jí)
          • 角度面試問題–高級(jí)

          初學(xué)者水平–面試問題

          1.區(qū)分Angular和AngularJS。

          特征AngularJSAngular
          建筑支持MVC設(shè)計(jì)模型使用組件和指令
          語(yǔ)言推薦語(yǔ)言:JavaScript推薦語(yǔ)言:TypeScript
          表達(dá)式語(yǔ)法圖片/屬性和事件需要特定的ng指令使用()綁定事件,使用[]進(jìn)行屬性綁定
          行動(dòng)支援不提供任何移動(dòng)支持提供移動(dòng)支持
          路由$ routeprovider.when()用于路由配置@RouteConfig {(…)}用于路由配置
          依賴注入不支持依賴注入的概念支持基于樹的單向更改檢測(cè)的分層依賴注入
          結(jié)構(gòu)體難以管理簡(jiǎn)化的結(jié)構(gòu),使大型應(yīng)用程序的開發(fā)和維護(hù)更加容易
          速度通過雙向數(shù)據(jù)綁定,開發(fā)工作和時(shí)間得以減少升級(jí)功能比AngularJS更快
          支持不再提供支持或新的更新積極的支持和頻繁的新更新

          2.什么是Angular?

          Angular是一個(gè)開放源代碼的前端Web框架。它是最流行的JavaScript框架之一,主要由Google維護(hù)。它提供了一個(gè)輕松開發(fā)基于Web的應(yīng)用程序的平臺(tái),并使前端開發(fā)人員能夠管理跨平臺(tái)應(yīng)用程序。它集成了強(qiáng)大的功能,例如聲明性模板,端到端工具,依賴項(xiàng)注入以及各種其他使開發(fā)路徑更流暢的最佳實(shí)踐。

          3.使用Angular有什么優(yōu)勢(shì)?

          下面列出了使用Angular框架的一些主要優(yōu)點(diǎn):

          • 支持雙向數(shù)據(jù)綁定
          • 它遵循MVC模式架構(gòu)
          • 它支持靜態(tài)模板和Angular模板
          • 您可以添加自定義指令
          • 它還支持RESTfull服務(wù)
          • 支持驗(yàn)證
          • 客戶端和服務(wù)器之間的通訊便利
          • 支持依賴注入
          • 具有強(qiáng)大的功能,例如事件處理程序,動(dòng)畫等。

          4. Angular主要用于什么?

          Angular通常用于表示單頁(yè)應(yīng)用程序的SPA的開發(fā)。Angular提供了一組現(xiàn)成的模塊,可簡(jiǎn)化單頁(yè)應(yīng)用程序的開發(fā)。不僅如此,Angular還具有內(nèi)置數(shù)據(jù)流,類型安全性和模塊化CLI的功能,被認(rèn)為是成熟的Web框架。

          5.什么是角度表達(dá)式?

          角表達(dá)式是類似于JavaScript的代碼段,通常放在諸如{{expression}}之類的綁定中。這些表達(dá)式用于將應(yīng)用程序數(shù)據(jù)綁定到HTML

          語(yǔ)法:{{expression}}

          6. Angular中的模板是什么?

          Angular中的模板是使用包含特定于Angular的元素和屬性的HTML編寫的。這些模板與來(lái)自模型和控制器的信息結(jié)合在一起,進(jìn)一步渲染這些信息以向用戶提供動(dòng)態(tài)視圖。

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

          Angular中的字符串插值是一種特殊的語(yǔ)法,它在雙花括號(hào) {{}}中使用模板表達(dá)式來(lái)顯示組件數(shù)據(jù)。它也稱為小胡子語(yǔ)法。JavaScript表達(dá)式包含在花括號(hào)中,由Angular執(zhí)行,然后將相對(duì)輸出嵌入HTML代碼中。這些表達(dá)式通常像表一樣進(jìn)行更新和注冊(cè),作為摘要循環(huán)的一部分。

          8. Angular中的Annotation和Decorator有什么區(qū)別?

          使用Reflect Metadata庫(kù),角度注釋是類的“唯一”元數(shù)據(jù)集。它們用于創(chuàng)建“注釋”數(shù)組。另一方面,裝飾器是用于分離裝飾或修改類的設(shè)計(jì)模式,而無(wú)需實(shí)際更改原始源代碼。

          9.您對(duì)Angular中的控制器了解多少?

          控制器是JavaScript函數(shù),可為HTML UI提供數(shù)據(jù)和邏輯。顧名思義,它們控制數(shù)據(jù)如何從服務(wù)器流到HTML UI。

          10. Angular的范圍是什么?

          Angular中的范圍是一個(gè)引用應(yīng)用程序模型的對(duì)象。它是表達(dá)式的執(zhí)行上下文。范圍以模仿應(yīng)用程序DOM結(jié)構(gòu)的層次結(jié)構(gòu)排列。范圍可以監(jiān)視表達(dá)式并傳播事件。

          11. Angular中的指令是什么?

          Angular的核心功能是指令,這些屬性使您可以編寫 特定于應(yīng)用程序的新HTML語(yǔ)法。它們本質(zhì)上是在Angular編譯器在DOM中找到它們時(shí)執(zhí)行的函數(shù)。Angular指令分為三部分:

          1. 組件指令
          2. 結(jié)構(gòu)指令
          3. 屬性指令

          12.什么是數(shù)據(jù)綁定?

          在Angular中,數(shù)據(jù)綁定是最強(qiáng)大,最重要的功能之一,可讓您定義組件與DOM(文檔對(duì)象模型)之間的通信。它從根本上簡(jiǎn)化了定義交互式應(yīng)用程序的過程,而不必?fù)?dān)心在視圖或模板與組件之間推送和提取數(shù)據(jù)。在Angular中,數(shù)據(jù)綁定有四種形式:

          1. 字符串插值
          2. 屬性綁定
          3. 事件綁定
          4. 雙向數(shù)據(jù)綁定

          13.在Angular中使用過濾器的目的是什么?

          Angular中的過濾器用于格式化表達(dá)式的值,以便將其顯示給用戶。這些過濾器可以添加到模板,指令,控制器或服務(wù)中。不僅如此,您還可以創(chuàng)建自己的自定義過濾器。使用它們,您可以輕松地組織數(shù)據(jù),使數(shù)據(jù)僅在滿足特定條件時(shí)才顯示。通過使用豎線字符|,將過濾器添加到表達(dá)式中,然后是過濾器。

          14. Angular和jQuery有什么區(qū)別?

          特征jQueryAngular
          DOM操作
          RESTful API沒有
          動(dòng)畫支持
          深層鏈接路由沒有
          表格驗(yàn)證沒有
          雙向數(shù)據(jù)綁定沒有
          AJAX / JSONP

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

          提供程序是Angular中的可配置服務(wù)。這是對(duì)依賴關(guān)系注入系統(tǒng)的一條指令,它提供有關(guān)獲取依賴關(guān)系值的方式的信息。它是一個(gè)具有$ get()方法的對(duì)象,該方法被調(diào)用以創(chuàng)建服務(wù)的新實(shí)例。提供者還可以包含其他方法,并使用$ provide來(lái)注冊(cè)新的提供者。

          中級(jí)–面試問題

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

          是的,Angular確實(shí)支持嵌套控制器的概念。需要以層次方式定義嵌套控制器,以便在視圖中使用它。

          17.如何區(qū)分Angular表達(dá)式和JavaScript表達(dá)式?

          Angular表達(dá)式JavaScript表達(dá)式
          1.它們可以包含文字,運(yùn)算符和變量。1.它們可以包含文字,運(yùn)算符和變量。
          2.它們可以寫在HTML標(biāo)記內(nèi)。2.它們不能寫在HTML標(biāo)記內(nèi)。
          3.它們不支持條件,循環(huán)和異常。3.它們確實(shí)支持條件,循環(huán)和異常。
          4.它們支持過濾器。4.他們不支持過濾器。

          18.列出使用核心Angular功能在應(yīng)用程序模塊之間進(jìn)行通信的方式。

          以下是使用核心Angular功能在應(yīng)用程序模塊之間進(jìn)行通信的最通用方法:

          • 使用事件
          • 使用服務(wù)
          • 通過在$ rootScope上分配模型
          • 直接在控制器之間[ $ parent$$ childHead$$ nextSibling等]
          • 直接在控制器之間[ ControllerAs或其他繼承形式]

          19. service()和factory()有什么區(qū)別?

          Angular中的service()是用于應(yīng)用程序業(yè)務(wù)層的函數(shù)。它作為構(gòu)造函數(shù)運(yùn)行,并在運(yùn)行時(shí)使用'new'關(guān)鍵字調(diào)用一次。而factory()是一個(gè)類似于service()的函數(shù),但功能更強(qiáng)大,更靈活。factory()是有助于創(chuàng)建對(duì)象的設(shè)計(jì)模式。

          20. $ scope和Angular中的scope有什么區(qū)別?

          • Angular中的$ scope用于實(shí)現(xiàn)依賴項(xiàng)注入(DI)的概念,另一方面,scope 用于指令鏈接。
          • $ scope是$ scopeProvider提供的服務(wù),可以注入到控制器,指令或其他服務(wù)中,而Scope可以是任何東西,例如函數(shù)參數(shù)名稱等。

          21.解釋范圍層次的概念嗎?

          Angular中的$ scope對(duì)象被組織成一個(gè)層次結(jié)構(gòu),并且主要由視圖使用。它包含一個(gè)根范圍,該范圍可以進(jìn)一步包含稱為子范圍的范圍。一個(gè)根作用域可以包含多個(gè)子作用域。在這里,每個(gè)視圖都有自己的$ scope,因此由其視圖控制器設(shè)置的變量將對(duì)其他控制器隱藏。范圍層次結(jié)構(gòu)通常如下所示:

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

          22.什么是AOT?

          AOT代表Angular-Ahead-of-Time編譯器。它用于在構(gòu)建過程中預(yù)編譯應(yīng)用程序組件及其模板。用AOT編譯的Angular應(yīng)用程序的啟動(dòng)時(shí)間更短。同樣,這些應(yīng)用程序的組件可以立即執(zhí)行,而無(wú)需任何客戶端編譯。這些應(yīng)用程序中的模板作為代碼嵌入其組件中。它減少了下載Angular編譯器的需要,從而使您免于繁瑣的任務(wù)。AOT編譯器可以丟棄未使用的指令,這些指令會(huì)使用搖樹工具進(jìn)一步丟棄。

          23.解釋jQLite。

          jQlite也稱為 jQuery litejQuery的子集,包含其所有功能。默認(rèn)情況下,它打包在Angular中。它幫助Angular以兼容的跨瀏覽器方式操作DOM。jQLite基本上僅實(shí)現(xiàn)最常用的功能,因此占用空間小。

          24.解釋Angular中的摘要循環(huán)過程?

          Angular中的摘要周期是監(jiān)視監(jiān)視列表的過程,以跟蹤監(jiān)視變量的值的變化。在每個(gè)摘要循環(huán)中,Angular都會(huì)比較范圍模型值的先前版本和新版本。通常,此過程是隱式觸發(fā)的,但是您也可以使用$ apply()手動(dòng)將其激活。

          25.什么是Angular模塊?

          所有Angular應(yīng)用程序都是模塊化的,并遵循稱為NgModules的模塊化系統(tǒng)。這些容器保存著專門用于應(yīng)用程序域,工作流或一組緊密相關(guān)的功能的內(nèi)聚代碼塊。這些模塊通常包含組件,服務(wù)提供商和其他代碼文件,其范圍由包含的NgModule定義。有了模塊,代碼變得更加可維護(hù),可測(cè)試和易讀。同樣,應(yīng)用程序的所有依賴關(guān)系通常僅在模塊中定義。

          26.我們可以在哪種類型的組件上創(chuàng)建自定義指令?

          Angular支持創(chuàng)建以下內(nèi)容的自定義指令:

          • 元素指令 -當(dāng)遇到匹配的元素時(shí),指令將激活。
          • 屬性 -當(dāng)遇到匹配的屬性時(shí),指令將激活。
          • CSS- 指令會(huì)在遇到匹配的CSS樣式時(shí)激活。
          • 注釋 -遇到匹配的注釋時(shí),指令將激活

          27. Angular中有哪些不同類型的過濾器?

          以下是Angular支持的各種過濾器:

          • 貨幣: 將數(shù)字格式化為貨幣格式。
          • 日期: 將日期格式化為指定的格式。
          • filter: 從數(shù)組中選擇項(xiàng)的子集。
          • json: 將對(duì)象格式化為JSON字符串。
          • limit:將數(shù)組/字符串限制為指定數(shù)量的元素/字符。
          • 小寫: 將字符串格式化為小寫
          • number: 將數(shù)字格式化為字符串。
          • orderBy: 按表達(dá)式對(duì)數(shù)組排序
          • 大寫: 將字符串格式化為大寫

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

          依賴注入(DI)是一種軟件設(shè)計(jì)模式,其中對(duì)象作為依賴關(guān)系傳遞,而不是在組件中對(duì)其進(jìn)行硬編碼。當(dāng)您嘗試將對(duì)象創(chuàng)建的邏輯與使用對(duì)象的邏輯分開時(shí),依賴注入的概念會(huì)派上用場(chǎng)。“ config”操作使用DI,在加載模塊以檢索應(yīng)用程序的元素時(shí),必須預(yù)先配置DI。使用此功能,用戶可以根據(jù)自己的要求更改依賴關(guān)系。

          29.區(qū)分單向綁定和雙向數(shù)據(jù)綁定。

          單向數(shù)據(jù)綁定中,無(wú)論何時(shí)更改數(shù)據(jù)模型,“視圖”或“ UI”部分都不會(huì)自動(dòng)更新。您需要手動(dòng)編寫自定義代碼,以便在每次視圖更改時(shí)對(duì)其進(jìn)行更新。

          而在雙向數(shù)據(jù)綁定中,一旦更改數(shù)據(jù)模型,則隱式更新View或UI部分。與單向數(shù)據(jù)綁定不同,這是一個(gè)同步過程。

          30.組件和指令的生命周期掛鉤是什么?

          Angular組件具有離散的生命周期,其中包含從出生到死亡過渡的不同階段。為了更好地控制這些階段,我們可以使用以下方法將其連接:

          • 構(gòu)造函數(shù): 通過在類上調(diào)用new創(chuàng)建組件或指令時(shí)將調(diào)用它。
          • ngOnChanges:每當(dāng)組件的任何輸入屬性發(fā)生更改或更新時(shí),都將調(diào)用它。
          • ngOnInit:每次初始化給定組件時(shí)都會(huì)調(diào)用它。在第一個(gè)ngOnChanges之后,該掛鉤在其生命周期中僅被調(diào)用一次。
          • ngDoCheck:每當(dāng)調(diào)用給定組件的更改檢測(cè)器時(shí),便會(huì)調(diào)用它。這使您可以為提供的組件實(shí)現(xiàn)自己的變更檢測(cè)算法。
          • ngOnDestroy: 在Angular銷毀組件之前立即調(diào)用它。您可以使用此鉤子來(lái)取消訂閱可觀察對(duì)象并分離事件處理程序,以避免發(fā)生任何類型的內(nèi)存泄漏。

          31.通過對(duì)Angular進(jìn)行臟檢查,您了解什么?

          在Angular中,摘要過程稱為臟檢查。之所以調(diào)用它,是因?yàn)樗鼟呙枵麄€(gè)范圍以進(jìn)行更改。換句話說,它將所有新的作用域模型值與以前的作用域值進(jìn)行比較。由于所有監(jiān)視變量都包含在單個(gè)循環(huán)中,因此任何變量的任何更改/更新都將導(dǎo)致重新分配DOM中存在的其余監(jiān)視變量。被監(jiān)視的變量處于單個(gè)循環(huán)(摘要循環(huán))中,任何變量的任何值更改都會(huì)在DOM中重新分配其他被監(jiān)視變量的值

          32.區(qū)分DOM和BOM。

          DOM物料清單
          1.代表文檔對(duì)象模型1.代表瀏覽器對(duì)象模型
          2.表示網(wǎng)頁(yè)的內(nèi)容2.在網(wǎng)頁(yè)上方工作,并包含瀏覽器屬性
          3.所有對(duì)象都以樹狀結(jié)構(gòu)排列,并且只能通過提供的API來(lái)操作和訪問文檔3.所有全局JavaScript對(duì)象,變量和函數(shù)都隱式地成為window對(duì)象的成員
          4.處理HTML文檔4.訪問和操縱瀏覽器窗口
          5. W3C推薦的標(biāo)準(zhǔn)規(guī)格5.每個(gè)瀏覽器都有自己的實(shí)現(xiàn)

          33.什么是Angular中的Transpiling?

          Angular中的編譯是指將源代碼從一種編程語(yǔ)言轉(zhuǎn)換為另一種編程語(yǔ)言的過程。通常,在Angular中,此轉(zhuǎn)換是從TypeScript到JavaScript的。這是一個(gè)隱式過程,在內(nèi)部發(fā)生。

          34. How to perform animation in Angular?

          為了在Angular應(yīng)用程序中執(zhí)行動(dòng)畫,您需要包括一個(gè)稱為Animate Library的特殊Angular庫(kù),然后將ngAnimate模塊引用到您的應(yīng)用程序中,或者將ngAnimate作為依賴項(xiàng)添加到您的應(yīng)用程序模塊內(nèi)部。

          35.什么是Angular中的包含?

          Angular中的包含可讓您將指令的原始子代轉(zhuǎn)移到新模板內(nèi)的特定位置。ng指令指示正在使用包含的最近父指令的已包含DOM的插入點(diǎn)。諸如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.列出一些用于測(cè)試角度應(yīng)用的工具嗎?

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

          38.如何在Angular中創(chuàng)建服務(wù)?

          在Angular中,服務(wù)是可替換對(duì)象,該對(duì)象使用依賴項(xiàng)注入連接在一起。通過將服務(wù)注冊(cè)到要在其中執(zhí)行的模塊中來(lái)創(chuàng)建服務(wù)。基本上,您可以通過三種方式創(chuàng)建角度服務(wù)。基本上,它們是在Angular中創(chuàng)建服務(wù)的三種方式:

          • Factory
          • Service
          • Provider

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

          Angular中的Singleton模式是一種很棒的模式,它限制了一個(gè)類不能被多次使用。Angular中的Singleton模式主要在依賴項(xiàng)注入和服務(wù)中實(shí)現(xiàn)。因此,如果您不使用“ new Object()”而未將其設(shè)為單例,則將為同一對(duì)象分配兩個(gè)不同的存儲(chǔ)位置。而如果將該對(duì)象聲明為單例,則如果該對(duì)象已存在于內(nèi)存中,則將簡(jiǎn)單地將其重用。

          40.您對(duì)Angular中的REST了解那些?

          REST表示RE表象小號(hào)大老牛逼轉(zhuǎn)讓(BOT)。REST是適用于HTTP請(qǐng)求的API(應(yīng)用程序編程接口)樣式。在這種情況下,所請(qǐng)求的URL可以精確定位需要處理的數(shù)據(jù)。然后,HTTP方法將標(biāo)識(shí)需要對(duì)請(qǐng)求的數(shù)據(jù)執(zhí)行的特定操作。因此,遵循此方法的API被稱為RESTful API。

          41. Angular中的自舉是什么?

          在Angular中進(jìn)行引導(dǎo)只是初始化或啟動(dòng)Angular應(yīng)用程序。Angular支持自動(dòng)和手動(dòng)引導(dǎo)。

          • 自動(dòng)引導(dǎo)程序:這是通過將ng-app指令添加到應(yīng)用程序的根目錄來(lái)完成的,通常是在標(biāo)記或標(biāo)記上(如果您希望angular自動(dòng)引導(dǎo)應(yīng)用程序)。當(dāng)Angular找到ng-app指令時(shí),它將加載與其關(guān)聯(lián)的模塊,然后編譯DOM。
          • 手動(dòng)引導(dǎo): 手動(dòng)引導(dǎo)為您提供了有關(guān)如何以及何時(shí)初始化Angular應(yīng)用程序的更多控制。如果您想在Angular喚醒并編譯頁(yè)面之前執(zhí)行任何其他操作,這將非常有用。

          42.在Angular中鏈接和編譯有什么區(qū)別?

          • 編譯功能用于模板DOM操縱并收集所有指令。
          • 鏈接功能用于注冊(cè)DOM偵聽器以及實(shí)例DOM操作,并在克隆模板后執(zhí)行。

          43. 您對(duì)Angular中的常數(shù)有什么了解?

          在Angular中,常量類似于用于定義全局?jǐn)?shù)據(jù)的服務(wù)。常量使用關(guān)鍵字“ constant”聲明。它們是使用恒定依賴性創(chuàng)建的,可以注入控制器或服務(wù)中的任何位置。

          44. Angular的提供者,服務(wù)和工廠之間有什么區(qū)別?

          提供者服務(wù)
          提供程序是一種可以將應(yīng)用程序的一部分傳遞到app.config中的方法服務(wù)是一種用于創(chuàng)建以'new'關(guān)鍵字實(shí)例化的服務(wù)的方法。這是用于創(chuàng)建和配置服務(wù)的方法。在這里,您可以創(chuàng)建一個(gè)對(duì)象,向其中添加屬性,然后返回相同的對(duì)象,并將工廠方法傳遞到控制器中。

          45. 什么是Angular Global API?

          Angular Global API是用于執(zhí)行各種常見任務(wù)的全局JavaScript函數(shù)的組合,例如:

          • 比較對(duì)象
          • 迭代對(duì)象
          • 轉(zhuǎn)換數(shù)據(jù)

          有一些常見的Angular Global API函數(shù),例如:

          • 有角的。小寫:將字符串轉(zhuǎn)換為小寫字符串。
          • 有角的。大寫: 將字符串轉(zhuǎn)換為大寫字符串。
          • 有角的。isString: 如果當(dāng)前引用是字符串,則返回true。
          • 有角的。isNumber:如果當(dāng)前引用為數(shù)字,則返回true。

          高級(jí)水平–面試問題

          46.在Angular中,描述如何設(shè)置,獲取和清除cookie?

          為了在Angular中使用cookie,您需要包含一個(gè)名為ngCookies angular-cookies.js的模塊。

          設(shè)置Cookies –為了以鍵值格式設(shè)置Cookies,使用“ put”方法。

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

          獲取Cookie –為了獲取Cookie,使用了“ get”方法。

          cookie.get("nameOfCookie");

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

          cookie.delete("nameOfCookie");

          47. 如果您的數(shù)據(jù)模型是在"區(qū)域"之外更新的,請(qǐng)說明該過程,您將如何查看視圖?

          您可以使用以下任意一種來(lái)更新視圖:

          1. ApplicationRef.prototype.tick():它將對(duì)整個(gè)組件樹執(zhí)行更改檢測(cè)。
          2. NgZone.prototype.run():它將對(duì)整個(gè)組件樹執(zhí)行更改檢測(cè)。在這里,引擎蓋下的run()將調(diào)用tick本身,然后參數(shù)將在tick之前獲取函數(shù)并執(zhí)行它。
          3. ChangeDetectorRef.prototype.detectChanges():它將在當(dāng)前組件及其子組件上啟動(dòng)更改檢測(cè)。

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

          ng-app指令用于定義Angular應(yīng)用程序,使我們可以在Angular應(yīng)用程序中使用自動(dòng)引導(dǎo)。它表示Angular應(yīng)用程序的根元素,通常在或標(biāo)簽附近聲明。在HTML文檔中可以定義任何數(shù)量的ng-app指令,但是只有一個(gè)Angular應(yīng)用程序可以被隱式地正式引導(dǎo)。其余應(yīng)用程序必須手動(dòng)引導(dǎo)。

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

          49.從準(zhǔn)備好的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元素,以在單擊按鈕時(shí)隱藏HTML元素。

          View

          <div ng-controller ="MyController">
            <button ng-click ="hide()">歡迎關(guān)注全棧程序員社區(qū)公眾號(hào)</ button>
            <p ng-hide ="isHide">歡迎關(guān)注Java架構(gòu)師社區(qū)公眾號(hào)!</ p>
          </ div>

          Controller

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

          歡迎關(guān)注 Java架構(gòu)師社區(qū)公眾號(hào).本文轉(zhuǎn)載自Java架構(gòu)師必看 ,更多內(nèi)容點(diǎn)擊查看!

          ngularJs作用域理解

          基于AngularJS入門與進(jìn)階(江榮波 著)這本書的筆記

          AngularJS 1.x的demo

          AngularJS1.x和Angular2,4,5是不一樣的兩個(gè)東西,構(gòu)建方式,語(yǔ)法,都很多不同


          每個(gè)AngularJS應(yīng)用至少會(huì)有一個(gè)名稱為$rootScope的作用域,它是AngularJS應(yīng)用的根作用域。框架中的ng-app指令,它可以出現(xiàn)在任何HTML標(biāo)簽中,用于啟動(dòng)AngularJS框架。當(dāng)AngularJS啟動(dòng)時(shí)會(huì)自動(dòng)創(chuàng)建一個(gè)根作用域?qū)ο?rootScope,當(dāng)使用ng-controller指令實(shí)例化控制器對(duì)象時(shí),AngularJS框架會(huì)創(chuàng)建一個(gè)子作用域$scope,默認(rèn)情況下,該子作用域會(huì)繼承$rootScope作用域的所有屬。

          如下代碼就是ng-init指令在$rootScope作用域?qū)ο笾行略隽藆serName屬性,然后在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對(duì)像繼承機(jī)制

          JavaScript對(duì)像繼承機(jī)制有三種

          1. 構(gòu)造方法原型鏈繼承
          2. 使用appley、call方法實(shí)現(xiàn)繼承
          3. 對(duì)像實(shí)例間繼承

          AngularJs是基于方法原型鏈繼承實(shí)現(xiàn)的,這里記錄下概念,書中原話:每個(gè)JavaScript構(gòu)造方法都有一個(gè)名稱為prototype的屬性,可以指向另一個(gè)對(duì)象。當(dāng)我們?cè)L問對(duì)象屬性時(shí)(例如obj.name),JavaScript引擎會(huì)從對(duì)象的所有屬性中查找該屬性,如果找到就返回屬性值,如果沒有找到就繼續(xù)從prototype屬性指向的對(duì)象屬性中查找,如果仍然沒有找到,則會(huì)沿著prototype鏈一直查找下去,直到prototype鏈結(jié)束或找到對(duì)象為止。

              <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);
                  // 本身如果沒有,會(huì)找指向的prototype 對(duì)像
                  man.eat();
              </script>
          

          控制臺(tái)輸出

          20
          pelple eat------------
          
          AngularJs作用域?qū)ο裨屠^承

          AngularJs繼承采用構(gòu)造方法原型繼承,在AngularJs作用域構(gòu)造方法中提供了一個(gè)$new()成員方法,用于創(chuàng)造子作用域,源碼這里就不重復(fù)了,書里面很詳細(xì),只記錄下過程

              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>
          

          控制臺(tái)成功輸出

          name:jock age:18 sex:男
          

          AngularJS框架查找到ng-app指令時(shí)啟動(dòng)應(yīng)用,創(chuàng)建$rootScope作用域。然后AngularJS框架查找到第一個(gè)ng-controller指令,指向名稱為fatherScope的控制器,并調(diào)用$rootScope.$new()方法,以原型繼承的方式創(chuàng)建$rootScope作用域的子作用域?qū)ο螅ㄓ洖?scope1)。當(dāng)fatherScope構(gòu)造方法接收一個(gè)名稱為$scope的參數(shù)時(shí),AngularJS實(shí)例化控制器對(duì)象時(shí)會(huì)把$scope1對(duì)象注入控制器對(duì)象中。接下來(lái)AngularJS繼續(xù)遍歷DOM元素,遇到第二個(gè)嵌套的ng-controller指令時(shí)調(diào)用$scope1.new()方法,以$scope1為原型創(chuàng)建子作用域(記為$scope2,$scope2作用域?qū)ο竽軌蛟L問$scope1作用域?qū)ο蟮乃袑傩裕?/p>


          主站蜘蛛池模板: 国产suv精品一区二区6| 亚洲片国产一区一级在线观看| 亚洲乱码一区二区三区国产精品| 亚洲一区中文字幕| 一区二区三区波多野结衣| 无码国产伦一区二区三区视频 | 一区二区无码免费视频网站| 成人午夜视频精品一区| ...91久久精品一区二区三区 | 在线观看视频一区二区| 国产午夜精品一区二区三区| 一区二区3区免费视频| 欧洲精品一区二区三区在线观看| 午夜AV内射一区二区三区红桃视 | 一区二区三区四区免费视频| 亚洲一区二区三区在线观看蜜桃 | 日韩免费一区二区三区在线| 色婷婷亚洲一区二区三区| 亚洲av片一区二区三区| 亚洲国产欧美一区二区三区| 一区二区三区观看免费中文视频在线播放 | 人妻无码第一区二区三区| jazzjazz国产精品一区二区| 亚洲日本久久一区二区va| 亚洲国产成人精品无码一区二区| 国产一区二区福利| 久久er99热精品一区二区| 亚洲av成人一区二区三区观看在线| jazzjazz国产精品一区二区| 国产一区二区好的精华液| 国产av成人一区二区三区| 天天爽夜夜爽人人爽一区二区| 国产一区二区中文字幕| 亚洲爆乳无码一区二区三区| 成人精品一区二区户外勾搭野战| 2021国产精品一区二区在线| 欧美日韩精品一区二区在线观看| 内射一区二区精品视频在线观看| 成人精品视频一区二区三区不卡 | 亚洲性色精品一区二区在线| 国产精品无码一区二区三区不卡|