Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
于封裝的原則,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);
}
這種寫法并不優雅:
筆者基于“動態類型技術”探索出了一種相對來說比較優雅的方案用于美化上述代碼,并為其命名為 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 派生自 DynamicObject ,其內部通過反射技術獲取到所有的屬性和字段并對其 getter 和 setter 方法進行存儲并通過 TryGetMember 和 TrySetMember 方法經運行時調用。
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 并未添加對“方法”的支持。這也就意味著對方法的調用是缺失的。雖然動態行為讓程序擺脫了對字符串的依賴,但是該實現對“重構”的支持仍然不友好。
Liquid 主題引擎 是筆者根據 Liquid 語言和 Shopify 主題機制并采用 Fluid 模板引擎實現的一套 HTML 主題引擎。該引擎允許最終用戶自由地修改自己的主題模板而不會對宿主造成影響。最終目標是做到多語言、多主題、高擴展性以及所見即所得。
在編寫 Liquid 主題引擎 時,筆者需要重寫 Fluid 模板引擎的 render 標簽讓子視圖從 snippets 文件夾加載。在實現該標簽時,需要訪問 TemplateContext 的 LocalScope 和 RootScope 字段,不幸的是上述字段被標記為了 internal ,無法在外部程序集中訪問到。于是便有了 ReflectionDynamicObject ,幫助筆者完成對 LocalScope 和 RootScope 的訪問。
們整理了一份主要的Angular面試問題清單,分為三部分:
特征 | AngularJS | Angular |
---|---|---|
建筑 | 支持MVC設計模型 | 使用組件和指令 |
語言 | 推薦語言:JavaScript | 推薦語言:TypeScript |
表達式語法 | 圖片/屬性和事件需要特定的ng指令 | 使用()綁定事件,使用[]進行屬性綁定 |
行動支援 | 不提供任何移動支持 | 提供移動支持 |
路由 | $ routeprovider.when()用于路由配置 | @RouteConfig {(…)}用于路由配置 |
依賴注入 | 不支持依賴注入的概念 | 支持基于樹的單向更改檢測的分層依賴注入 |
結構體 | 難以管理 | 簡化的結構,使大型應用程序的開發和維護更加容易 |
速度 | 通過雙向數據綁定,開發工作和時間得以減少 | 升級功能比AngularJS更快 |
支持 | 不再提供支持或新的更新 | 積極的支持和頻繁的新更新 |
Angular是一個開放源代碼的前端Web框架。它是最流行的JavaScript框架之一,主要由Google維護。它提供了一個輕松開發基于Web的應用程序的平臺,并使前端開發人員能夠管理跨平臺應用程序。它集成了強大的功能,例如聲明性模板,端到端工具,依賴項注入以及各種其他使開發路徑更流暢的最佳實踐。
下面列出了使用Angular框架的一些主要優點:
Angular通常用于表示單頁應用程序的SPA的開發。Angular提供了一組現成的模塊,可簡化單頁應用程序的開發。不僅如此,Angular還具有內置數據流,類型安全性和模塊化CLI的功能,被認為是成熟的Web框架。
角表達式是類似于JavaScript的代碼段,通常放在諸如{{expression}}之類的綁定中。這些表達式用于將應用程序數據綁定到HTML
語法:{{expression}}
Angular中的模板是使用包含特定于Angular的元素和屬性的HTML編寫的。這些模板與來自模型和控制器的信息結合在一起,進一步渲染這些信息以向用戶提供動態視圖。
Angular中的字符串插值是一種特殊的語法,它在雙花括號 {{}}中使用模板表達式來顯示組件數據。它也稱為小胡子語法。JavaScript表達式包含在花括號中,由Angular執行,然后將相對輸出嵌入HTML代碼中。這些表達式通常像表一樣進行更新和注冊,作為摘要循環的一部分。
使用Reflect Metadata庫,角度注釋是類的“唯一”元數據集。它們用于創建“注釋”數組。另一方面,裝飾器是用于分離裝飾或修改類的設計模式,而無需實際更改原始源代碼。
控制器是JavaScript函數,可為HTML UI提供數據和邏輯。顧名思義,它們控制數據如何從服務器流到HTML UI。
Angular中的范圍是一個引用應用程序模型的對象。它是表達式的執行上下文。范圍以模仿應用程序DOM結構的層次結構排列。范圍可以監視表達式并傳播事件。
Angular的核心功能是指令,這些屬性使您可以編寫 特定于應用程序的新HTML語法。它們本質上是在Angular編譯器在DOM中找到它們時執行的函數。Angular指令分為三部分:
在Angular中,數據綁定是最強大,最重要的功能之一,可讓您定義組件與DOM(文檔對象模型)之間的通信。它從根本上簡化了定義交互式應用程序的過程,而不必擔心在視圖或模板與組件之間推送和提取數據。在Angular中,數據綁定有四種形式:
Angular中的過濾器用于格式化表達式的值,以便將其顯示給用戶。這些過濾器可以添加到模板,指令,控制器或服務中。不僅如此,您還可以創建自己的自定義過濾器。使用它們,您可以輕松地組織數據,使數據僅在滿足特定條件時才顯示。通過使用豎線字符|,將過濾器添加到表達式中,然后是過濾器。
特征 | jQuery | Angular |
---|---|---|
DOM操作 | 是 | 是 |
RESTful API | 沒有 | 是 |
動畫支持 | 是 | 是 |
深層鏈接路由 | 沒有 | 是 |
表格驗證 | 沒有 | 是 |
雙向數據綁定 | 沒有 | 是 |
AJAX / JSONP | 是 | 是 |
提供程序是Angular中的可配置服務。這是對依賴關系注入系統的一條指令,它提供有關獲取依賴關系值的方式的信息。它是一個具有$ get()方法的對象,該方法被調用以創建服務的新實例。提供者還可以包含其他方法,并使用$ provide來注冊新的提供者。
是的,Angular確實支持嵌套控制器的概念。需要以層次方式定義嵌套控制器,以便在視圖中使用它。
Angular表達式 | JavaScript表達式 |
---|---|
1.它們可以包含文字,運算符和變量。 | 1.它們可以包含文字,運算符和變量。 |
2.它們可以寫在HTML標記內。 | 2.它們不能寫在HTML標記內。 |
3.它們不支持條件,循環和異常。 | 3.它們確實支持條件,循環和異常。 |
4.它們支持過濾器。 | 4.他們不支持過濾器。 |
以下是使用核心Angular功能在應用程序模塊之間進行通信的最通用方法:
Angular中的service()是用于應用程序業務層的函數。它作為構造函數運行,并在運行時使用'new'關鍵字調用一次。而factory()是一個類似于service()的函數,但功能更強大,更靈活。factory()是有助于創建對象的設計模式。
Angular中的$ scope對象被組織成一個層次結構,并且主要由視圖使用。它包含一個根范圍,該范圍可以進一步包含稱為子范圍的范圍。一個根作用域可以包含多個子作用域。在這里,每個視圖都有自己的$ scope,因此由其視圖控制器設置的變量將對其他控制器隱藏。范圍層次結構通常如下所示:
AOT代表Angular-Ahead-of-Time編譯器。它用于在構建過程中預編譯應用程序組件及其模板。用AOT編譯的Angular應用程序的啟動時間更短。同樣,這些應用程序的組件可以立即執行,而無需任何客戶端編譯。這些應用程序中的模板作為代碼嵌入其組件中。它減少了下載Angular編譯器的需要,從而使您免于繁瑣的任務。AOT編譯器可以丟棄未使用的指令,這些指令會使用搖樹工具進一步丟棄。
jQlite也稱為 jQuery lite是jQuery的子集,包含其所有功能。默認情況下,它打包在Angular中。它幫助Angular以兼容的跨瀏覽器方式操作DOM。jQLite基本上僅實現最常用的功能,因此占用空間小。
Angular中的摘要周期是監視監視列表的過程,以跟蹤監視變量的值的變化。在每個摘要循環中,Angular都會比較范圍模型值的先前版本和新版本。通常,此過程是隱式觸發的,但是您也可以使用$ apply()手動將其激活。
所有Angular應用程序都是模塊化的,并遵循稱為NgModules的模塊化系統。這些容器保存著專門用于應用程序域,工作流或一組緊密相關的功能的內聚代碼塊。這些模塊通常包含組件,服務提供商和其他代碼文件,其范圍由包含的NgModule定義。有了模塊,代碼變得更加可維護,可測試和易讀。同樣,應用程序的所有依賴關系通常僅在模塊中定義。
Angular支持創建以下內容的自定義指令:
以下是Angular支持的各種過濾器:
依賴注入(DI)是一種軟件設計模式,其中對象作為依賴關系傳遞,而不是在組件中對其進行硬編碼。當您嘗試將對象創建的邏輯與使用對象的邏輯分開時,依賴注入的概念會派上用場。“ config”操作使用DI,在加載模塊以檢索應用程序的元素時,必須預先配置DI。使用此功能,用戶可以根據自己的要求更改依賴關系。
在 單向數據綁定中,無論何時更改數據模型,“視圖”或“ UI”部分都不會自動更新。您需要手動編寫自定義代碼,以便在每次視圖更改時對其進行更新。
而在雙向數據綁定中,一旦更改數據模型,則隱式更新View或UI部分。與單向數據綁定不同,這是一個同步過程。
Angular組件具有離散的生命周期,其中包含從出生到死亡過渡的不同階段。為了更好地控制這些階段,我們可以使用以下方法將其連接:
在Angular中,摘要過程稱為臟檢查。之所以調用它,是因為它掃描整個范圍以進行更改。換句話說,它將所有新的作用域模型值與以前的作用域值進行比較。由于所有監視變量都包含在單個循環中,因此任何變量的任何更改/更新都將導致重新分配DOM中存在的其余監視變量。被監視的變量處于單個循環(摘要循環)中,任何變量的任何值更改都會在DOM中重新分配其他被監視變量的值
DOM | 物料清單 |
---|---|
1.代表文檔對象模型 | 1.代表瀏覽器對象模型 |
2.表示網頁的內容 | 2.在網頁上方工作,并包含瀏覽器屬性 |
3.所有對象都以樹狀結構排列,并且只能通過提供的API來操作和訪問文檔 | 3.所有全局JavaScript對象,變量和函數都隱式地成為window對象的成員 |
4.處理HTML文檔 | 4.訪問和操縱瀏覽器窗口 |
5. W3C推薦的標準規格 | 5.每個瀏覽器都有自己的實現 |
Angular中的編譯是指將源代碼從一種編程語言轉換為另一種編程語言的過程。通常,在Angular中,此轉換是從TypeScript到JavaScript的。這是一個隱式過程,在內部發生。
為了在Angular應用程序中執行動畫,您需要包括一個稱為Animate Library的特殊Angular庫,然后將ngAnimate模塊引用到您的應用程序中,或者將ngAnimate作為依賴項添加到您的應用程序模塊內部。
Angular中的包含可讓您將指令的原始子代轉移到新模板內的特定位置。ng指令指示正在使用包含的最近父指令的已包含DOM的插入點。諸如ng-transclude 或 ng-transclude-slot之類的屬性指令主要用于包含。
Angular中的事件是特定的指令,可幫助自定義各種DOM事件的行為。以下列出了Angular支持的事件:
在Angular中,服務是可替換對象,該對象使用依賴項注入連接在一起。通過將服務注冊到要在其中執行的模塊中來創建服務。基本上,您可以通過三種方式創建角度服務。基本上,它們是在Angular中創建服務的三種方式:
Angular中的Singleton模式是一種很棒的模式,它限制了一個類不能被多次使用。Angular中的Singleton模式主要在依賴項注入和服務中實現。因此,如果您不使用“ new Object()”而未將其設為單例,則將為同一對象分配兩個不同的存儲位置。而如果將該對象聲明為單例,則如果該對象已存在于內存中,則將簡單地將其重用。
REST表示RE表象小號大老牛逼轉讓(BOT)。REST是適用于HTTP請求的API(應用程序編程接口)樣式。在這種情況下,所請求的URL可以精確定位需要處理的數據。然后,HTTP方法將標識需要對請求的數據執行的特定操作。因此,遵循此方法的API被稱為RESTful API。
在Angular中進行引導只是初始化或啟動Angular應用程序。Angular支持自動和手動引導。
在Angular中,常量類似于用于定義全局數據的服務。常量使用關鍵字“ constant”聲明。它們是使用恒定依賴性創建的,可以注入控制器或服務中的任何位置。
提供者 | 服務 | 廠 |
---|---|---|
提供程序是一種可以將應用程序的一部分傳遞到app.config中的方法 | 服務是一種用于創建以'new'關鍵字實例化的服務的方法。 | 這是用于創建和配置服務的方法。在這里,您可以創建一個對象,向其中添加屬性,然后返回相同的對象,并將工廠方法傳遞到控制器中。 |
Angular Global API是用于執行各種常見任務的全局JavaScript函數的組合,例如:
有一些常見的Angular Global API函數,例如:
為了在Angular中使用cookie,您需要包含一個名為ngCookies angular-cookies.js的模塊。
設置Cookies –為了以鍵值格式設置Cookies,使用“ put”方法。
cookie.set("nameOfCookie","cookieValue");
獲取Cookie –為了獲取Cookie,使用了“ get”方法。
cookie.get("nameOfCookie");
清除Cookie –使用“刪除”方法刪除Cookie。
cookie.delete("nameOfCookie");
您可以使用以下任意一種來更新視圖:
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>
@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'});
}
}
可以使用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架構師必看 ,更多內容點擊查看!
基于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>
JavaScript對像繼承機制有三種
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作用域構造方法中提供了一個$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作用域對象的所有屬性)。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。