欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解Angular.JS中的Scope繼承

 更新時間:2017年06月04日 14:39:30   作者:CraftsCoder  
這篇文章主要給大家深入的介紹了關(guān)于Angular.JS中Scope繼承的相關(guān)資料,Angular。JS中scope之間的繼承關(guān)系使用JavaScript的原型繼承方式實現(xiàn),文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。

前言

AngularJS中scope之間的繼承關(guān)系使用JavaScript的原型繼承方式實現(xiàn)。本文結(jié)合AngularJS Scope的實現(xiàn)以及相關(guān)資料談?wù)勗屠^承機(jī)制。下面來看看詳細(xì)的介紹:

基本原理

在JavaScript中,每創(chuàng)建一個構(gòu)造函數(shù)(constructor),就會同時給該函數(shù)生成一個指向原型對象的屬性prototype。每個原型對象又獲得一個constructor屬性指向相應(yīng)的構(gòu)造函數(shù),原型對象的其他屬性和方法從Object繼承而來。每個通過構(gòu)造函數(shù)創(chuàng)建的實例,都包含一個指向構(gòu)造函數(shù)原型對象的內(nèi)部屬性[[Prototype]](在瀏覽器中通常實現(xiàn)為__proto__)。構(gòu)造函數(shù)、原型對象和實例三者的關(guān)系如下 (圖片來源:《JavaScript高級程序設(shè)計(第3版)》):


person1和person2為構(gòu)造函數(shù)Person創(chuàng)建的兩個實例,可以通過[[Prototype]]屬性訪問原型對象Person Prototype,獲得原型中定義的所有方法和屬性。Person構(gòu)造函數(shù)的prototype屬性同樣指向Person Prototype原型對象。以上這些概念是理解原型繼承的基礎(chǔ),下面我們來看原型鏈的概念。如果把一個類型的實例賦值給一個原型對象會發(fā)生什么?根據(jù)上圖中的關(guān)系,此時的原型對象包含指向另一個原型的屬性,而另一個原型中也包含著指向另一個構(gòu)造函數(shù)的屬性。

效果如下圖:

SuperType為一個父類型,在原型中定義了屬性property和方法getSuperValue;SubType是一個子類型,定義了屬性subproperty和方法getSubValue。instance為SubType的一個實例。這里通過下面的關(guān)鍵代碼,將SubType的原型對象變?yōu)镾uperType對象的實例:

SubType.prototype = new SuperType(); 
SubType.prototype.getSubValue = function(){ 
 return this.subproperty; 
}; 

我們看到,SubType的原型對象中有來自SuperType實例對象的property屬性,以及自己在原型上定義的getSubValue方法,通過[[Prototype]]屬性,又可以進(jìn)一步訪問SuperType原型對象中的成員。假如SuperType的原型也被賦值成某個類型的實例,依次類推,那么可以通過[[Prototype]]屬性一直向上回溯,形成一條直通Object原型對象的原型鏈。上面的例子只展示了鏈條的前兩環(huán)。

通過原型鏈的實現(xiàn),SubType的實例繼承了SuperType實例的的所有實例成員和原型成員。例如,若要訪問instance.getSuperValue,首先在instance實例內(nèi)部搜索,沒有該方法;然后通過原型鏈向上回溯,找到SubType原型對象,也沒有該方法;再通過[[Prototype]]屬性繼續(xù)回溯,來到SuperType的原型對象,找到該方法。

以上描述的這種繼承方式就是原型繼承。在ES5以后,可以使用Object提供的create方法規(guī)范化上述過程,詳細(xì)請參考這里。AngularJS的Scope繼承關(guān)系的實現(xiàn)類似上述過程。

Scope繼承實現(xiàn)

在Angular中,想要定義一個Scope的child Scope可以通過scope.$new方法實現(xiàn),而$new方法本身的實現(xiàn)就體現(xiàn)了上述原型繼承的思想。首先,$new方法接受兩個參數(shù):isolated和parent。第一個參數(shù)表示創(chuàng)建的child scope是否是一個隔離的(isolated)。隔離的scope不繼承parent scope的原型,只是在層次結(jié)構(gòu)(hierachy)上屬于其child scope,這種結(jié)構(gòu)是Digest過程的基礎(chǔ)。isolated scope的一個好處是避免parent scope的成員被更改,在directive的實現(xiàn)里很有用。第二個參數(shù)指定創(chuàng)建的child scope的parent scope,如果不指定,默認(rèn)為當(dāng)前調(diào)用$new方法的scope。Angular中$new的實現(xiàn)類似:

$new : function(isolate, parent) { 
  var child; 
  parent = parent || this; 
  if (isolate) { 
   child = new Scope(); 
   child.$root = this.$root; 
  } else { 
   if (!this.$$ChildScope) { 
   this.$$ChildScope = createChildScopeClass(this); 
   } 
   child = new this.$$ChildScope(); 
  } 
  child.$parent = parent; 
  //... 
  return child; 
},//... 

可以看出,如果是isolate為true,則使用Scope類型構(gòu)造函數(shù)創(chuàng)建一個child對象。如果isolate為false或者未指定,則創(chuàng)建一個child scope原型繼承于當(dāng)前scope,這個過程由createChildScopeClass提供的構(gòu)造函數(shù)實現(xiàn):

function createChildScopeClass(parent) { 
 function ChildScope() { 
  this.$$watchers = null; 
  this.$$listeners = {};//... 
 } 
 ChildScope.prototype = parent; 
 return ChildScope; 
 } 

這里定義了ChildScope類型,包括其需要的屬性。然后將該類型的prototye屬性設(shè)置為傳入的scope實例(即前面的this),這就是前面闡述的原型繼承。之后通過ChildScope創(chuàng)建的scope對象都是原型繼承于parent的,即可以訪問parent scope的所有成員。結(jié)合$new的代碼,如果child非隔離,則child可以訪問當(dāng)前scope對象中的所有成員(例如$digest,$apply等方法以及自定義成員)。這就解釋了在我們自己創(chuàng)建的controller對應(yīng)的scope里,可以訪問$rootScope提供的成員,因為我們的scope最終原型繼承自root scope,因而可以通過原型鏈向上回溯到root scope的實例。

在前面一篇文章中,談到了Angular中Digest過程。當(dāng)調(diào)用scope.$apply方法時,實際上是從root scope開始,按照scope的層次結(jié)構(gòu),調(diào)用每個scope的$digest方法。這就是為什么在Scope的構(gòu)造函數(shù)中會設(shè)置$root屬性:

function Scope() { 
  this.$parent = null;//... 
  this.$root = this; 
  this.$$destroyed = false; 
  this.$$listeners = {}; 
  //... 
} 

對于一般child scope,$root會通過原型繼承得到,在root scope構(gòu)造以后,后續(xù)的scope都可以訪問$root對象,即是root scope對象。對于isolated scope,由于是通過Scope構(gòu)造函數(shù)創(chuàng)建(非原型繼承),$root被child scope覆蓋,需要將$root屬性設(shè)置為parent的$root屬性,如前面$new的實現(xiàn)。這就保證了在任何一個scope中始終能拿到root scope的實例,也就可以完成自上而下的Digest過程,在$apply等方法的實現(xiàn)中,使用$rootScope代替$root,二者相同:

$apply: function(expr) { 
  beginPhase('$apply'); 
  try { 
   return this.$eval(expr); 
  } finally { 
   clearPhase(); 
  } 
  finally { 
   $rootScope.$digest(); 
  } 
},//... 

$rootScope是$RootScopeProvider提供的Scope類型實例,是最先初始化的scope對象。在開發(fā)中,我們可以這樣使用child scope:

.controller('smallCatCtrl', [ 
 '$scope', function($scope){ 
    
  var child = $scope.$new(); 
  child.text = 'cat'; 
   
  var child1 = $scope.$new(true); 
  child1.value = 0; 
   
   var child2 = $scope.$new(true, child); 
   child2.value = 1; 
   
  child2.$watch('value', function(oldValue, newValue){ 
   console.log('child2.value changed'); 
  }); 
  child1.$watch('value', function(oldValue, newValue){ 
   console.log('child1.value changed'); 
  }) 
  child.$watch('text', function(oldValue, newValue){ 
   console.log('child.text changed'); 
  }); 
  console.log(child2.text); 
 
 }]); 

在這段代碼中,首先創(chuàng)建$scope的一個子scope----child,沒有給$new指定參數(shù),意味著child原型繼承于$scope。同時定義了child的屬性text。接下來創(chuàng)建$scope的第二個子scope----child1,傳入$new的參數(shù)要求child1是isolated scope,并且在層次結(jié)構(gòu)上是$scope的后代。同時定義了其value屬性。最后創(chuàng)建scope child2,它也是一個isolated scope,不同的是它以child為層次結(jié)構(gòu)上的parent scope。

這段代碼的輸出如下:

首先,child2只是在層次結(jié)構(gòu)上繼承于child,因此沒有把child實例作為原型,也就沒有text屬性,第一行輸出undefined。
由于Digest過程按scope層次結(jié)構(gòu)自上而下進(jìn)行,類似于樹的深度遍歷過程。在該例中scope的順序為$scope->child->child2->child1,因此三個watch listener函數(shù)的輸出也按照上面的順序。

本文參考資料:

1. AngularJS 官方文檔

2. AngularJS 源代碼

3. JavaScript 高級程序設(shè)計(第3版)

4. Build Your Own AngularJS

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Angular封裝搜索框組件操作示例

    Angular封裝搜索框組件操作示例

    這篇文章主要介紹了Angular封裝搜索框組件操作,結(jié)合實例形式分析了基于Angular組件庫實現(xiàn)搜索功能的封裝操作相關(guān)實現(xiàn)步驟與注意事項,需要的朋友可以參考下
    2019-04-04
  • AngularJS實用開發(fā)技巧(推薦)

    AngularJS實用開發(fā)技巧(推薦)

    Angular JS 是一組用來開發(fā)Web頁面的框架、模板以及數(shù)據(jù)綁定和豐富UI組件。接下來通過本文給大家介紹AngularJS實用開發(fā)技巧的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • Angular處理未可知異常錯誤的方法詳解

    Angular處理未可知異常錯誤的方法詳解

    這篇文章主要給大家介紹了關(guān)于Angular如何處理未可知異常錯誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • AngularJS使用ngMessages進(jìn)行表單驗證

    AngularJS使用ngMessages進(jìn)行表單驗證

    這篇文章主要介紹了AngularJS使用ngMessages進(jìn)行表單驗證的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • 詳解Angular項目中共享模塊的實現(xiàn)

    詳解Angular項目中共享模塊的實現(xiàn)

    本文主要介紹了Angular的共享模塊的實現(xiàn),對此感興趣的同學(xué),可以實驗一下
    2021-05-05
  • AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法

    AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法

    這篇文章主要介紹了AngularJS實現(xiàn)根據(jù)變量改變動態(tài)加載模板的方法,結(jié)合實例形式簡單分析了AngularJS動態(tài)加載模板的主要操作技巧與模板實現(xiàn)代碼,需要的朋友可以參考下
    2016-11-11
  • angularjs封裝bootstrap時間插件datetimepicker

    angularjs封裝bootstrap時間插件datetimepicker

    這篇文章主要介紹了angularjs封裝bootstrap時間插件datetimepicker 的相關(guān)資料,需要的朋友可以參考下
    2016-06-06
  • AngularJS中的API(接口)簡單實現(xiàn)

    AngularJS中的API(接口)簡單實現(xiàn)

    本文主要介紹AngularJS API(接口),這里對AngularJS API的知識做了詳細(xì)講解,并附簡單代碼實例,有需要的小伙伴可以參考下
    2016-07-07
  • 關(guān)于angular瀏覽器兼容性問題的解決方案

    關(guān)于angular瀏覽器兼容性問題的解決方案

    這篇文章主要給大家介紹了關(guān)于angular瀏覽器兼容性問題的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用angular具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Angular ng-class詳解及實例代碼

    Angular ng-class詳解及實例代碼

    這篇文章主要介紹了Angular ng-class的知識,并整理了相關(guān)資料,有興趣的小伙伴可以參考下
    2016-09-09

最新評論