angular中scope,controller,this繼承區別

1.scope的幾種繼承

說到scope,我們可能會想到rootScope,因爲所有的scope都是由rootScope產生出來的,我們也知道在angular裏面 scope有幾種繼承形式:
1.scope爲false,完成繼承父的scope,子scope,父scope修改值都互相影響(其實同一scope下修改的是用一個值)
2.scope爲true,子創建一個scope(注意此時和父是兩個不用scope),但是還是繼承父scope,怎麼理解呢,拿個構造函數來說吧,我實例化這個constructor,那麼實例化出來的對象應該是同時擁有constructor和prototype上的屬性和方法,假如有個屬性a在constructor和prototype都有,那麼首先肯定先取constructor.a,constructor上沒有,再取prototype.a,那麼constructor可以比作子scope,prototype可以比作父scope,當子scope沒有,再去父scope去取。
3.scope爲{},那麼此時創建一個獨立的scope,和父scope是沒有關係,兩個scope都是互不想幹的(此時有幾種父傳值給子的方式)

有了這些概念之後我們來看個例子:
html

<div ng-app="App">
    <parent-scope>
    </parent-scope>
</div>

js

angular.module("App", [])
.directive("parentScope", function () {
    return {
        restrict: "ECAM",
        template: '<input type="text" ng-model="username"><child-scope></child-scope>',
        scope: false,
        controller: ['$scope', function ($scope) {
            $scope.username = '張三'
        }]
    }

})
.directive("childScope", function () {
    return {
        restrict: "ECAM",
        template: '<input type="text" ng-model="username">',
        replace: true,
        scope: false,
    }
})

結果:子scope繼承父scope,並且互相影響!
在這裏插入圖片描述
然後把子的scope改成true,結果是當子scope無此屬性,父可以影響到子,當子scope有此屬性,父影響不到子,子也影響不到父!
在這裏插入圖片描述
最後把子的scope改成{},那就毫無疑問,兩者互不影響!

2.controller繼承

可能看到controller繼承有點懵?沒聽過controller繼承?還是拿個上面例子來說,稍微改了下:

angular.module("App", [])
.directive("parentScope", function () {
    return {
        restrict: "ECAM",
        template: '<input type="text" ng-model="ctrl.username"><child-scope></child-scope>',
        scope: false,
        controllerAs:'ctrl',
        controller: ['$scope', function ($scope) {
            var ctrl = this;
            ctrl.username = '張三'
        }]
    }

})
.directive("childScope", function () {
    return {
        restrict: "ECAM",
        template: '<input type="text" ng-model="ctrl.username">',
        replace: true,
        scope: true,
    }
})

我把username綁到controller上,然後把子scope改成true,想下結果是什麼?很多人認爲可能和scope一樣的吧,ctrl是在scope裏面的,應該和scope繼承一樣,但是結果不是一樣,是子scope爲false結果一樣,互相影響!無論改變哪個scope值,都會一起變化!
在這裏插入圖片描述
爲什麼會是這樣的?
還記得scope是怎麼創建的和怎麼繼承的嗎?(不瞭解的可以點擊這裏
這裏我大概說下,首先創建的是rootScope(根作用域),然後創建子scope,創建子scope時候會判斷此scope是否是隔離的,如果是不是隔離就會繼承父scope,ChildScope.prototype = parent,如果是隔離的就new scope ,此時和原型繼承毫無關係了。上段源代碼:

 $new: function (isolate, parent) {
   var child;
   parent = parent || this;
   //是否是隔離scope
   if (isolate) {
   	 //此時和原型繼無關
     child = new Scope();
     child.$root = this.$root;
   } else {
   //判斷是否有
     if (!this.$$ChildScope) {
      //子構造函數的創建並繼承父
       this.$$ChildScope = createChildScopeClass(this);
     }
     //子作用域的創建
     child = new this.$$ChildScope();
   }
   //把自己的父,兄弟姐妹,兒子整明白(要不然亂套了)
   child.$parent = parent;
   // 孩子的前一個兄弟節點爲父親的最後一個孩子
   child.$$prevSibling = parent.$$childTail;
   
   if (parent.$$childHead) {
     parent.$$childTail.$$nextSibling = child;
     parent.$$childTail = child;
   } else {
     parent.$$childHead = parent.$$childTail = child;
   }
   
   if (isolate || parent !== this) child.$on('$destroy', destroyChildScope);
   return child;
 }

function createChildScopeClass(parent) {
  function ChildScope() {
    this.$$watchers = this.$$nextSibling =
      this.$$childHead = this.$$childTail = null;
    this.$$listeners = {};
    this.$$listenerCount = {};
    this.$$watchersCount = 0;
    this.$id = nextUid();
    this.$$ChildScope = null;
    this.$$suspended = false;
  }
  ChildScope.prototype = parent;
  return ChildScope;
}

上面有註釋,已經原理很清楚了,那麼再來看上面的例子,首先創建rootScope,parentScope指令創建的scope繼承rootScope,也是就用一scope了,所以id都爲1。而childScope創建的scope雖然也繼承rootScope,但是它還是個創建了一個新的scope(因爲scope=true)。
此圖爲parentScope(id爲1):
在這裏插入圖片描述
此圖爲childScope(id爲2):
在這裏插入圖片描述
因爲parentScope裏面創建了一個controller,所以你在parentScope圖中可以看到有個ctrl屬性,根據原型繼承ChildScope.prototype = parentScope,那麼ChildScope原型上必定有ctrl屬性,我們來看看ChildScope的__proto__屬性:
在這裏插入圖片描述
所以不管輸入那邊的,它們都互相都受影響!這是一種繼承方式,下面我們再來說下另外一種獲取controller方式(用的比較少,嚴格的說不能是繼承,只是拿到這個controller)
這裏我們需要用到$controller service(angualr內置服務),下面看下怎麼實現的:
html:

<div ng-app="App">
    <div ng-controller="firstController">
        <inherit-test></inherit-test>
    </div>
</div>

js:

angular.module("App", [])
.controller("firstController", [function () {
    var ctrl = this;
    ctrl.name = "張三";
    ctrl.age = 18;
    ctrl.sex = '男';
}])
.directive("inheritTest", function () {
    return {
        restrict: "ECAM",
        controllerAs: 'ctrl',
        controller: ['$controller', '$scope', function ($controller, $scope) {
            var ctrl = this;
            ctrl.test = 'inherit';
            var test = $controller('firstController', {
                $scope: $scope
            })
            angular.extend(this, test);
            console.log(test); //age: 18 name: "張三" sex: "男" test: "inherit"
        }],
    }
})

這裏就和scope沒有關係,其實大概原理是angular會把註冊的controller放到一個invokeQueue數組裏面,此時並沒有執行,等到 angular初始化時 angularInit(window.document, bootstrap),然後$ControllerProvider.register.apply($ControllerProvider,firstController);在register方法裏面把所有註冊的controller放到一個controllers對象裏面,我們看下這個register源碼(無關的代碼去掉了):

  function $ControllerProvider() {
  	//裝所有註冊的controller的對象
    var controllers = {};
    //兩個參數相當是('firstController',firstControllerConstructor)
    this.register = function (name, constructor) {
    	//判斷名稱是hasOwnProperty拋出錯誤
      assertNotHasOwnProperty(name, 'controller');
       //是對象的話就讓controllers繼承它
      if (isObject(name)) {
        extend(controllers, name);
      } else {
      //與firstController爲key,firstControllerConstructor爲value形式放到controllers裏面
        controllers[name] = constructor;
      }
    };

所以我們可以根據controller註冊名稱可以去這個controllers對象裏面找它。另外還有一種組件之間controller獲取(用的是require,如果不懂的可以點擊這裏)。

3.this的指向

Controller是一個的構造函數,必須要new(實例化後)才能進行調用,所以必定會生成一個Controller實例,此實例也必然會繼承構造函數中this綁定的所有屬性與方法,此時的this指向的是Controller實例。再看下面代碼:

angular.module("App", [])
.controller("firstController", ['$scope',function ($scope) {
   var ctrl = this;
   ctrl.name = "張三";
   ctrl.age = 18;
   ctrl.sex = '男';
   $scope.method =function(){
       console.log(this);//scope
   }
}])

從上面的代碼可以看出,它們其實沒什麼聯繫,如果非要說有的話,那麼它們都可以在同一個構造函數中互相訪問,$scope是這個函數的形參,this是這個函數的上下文,所以它們絕對不是同一個對象。Controller中的this與$scope都可以存儲數據,最好不要數據分散存儲兩個對象中。好了說到這裏都已經說的差不多了,有不正的地方請指正,不勝感激!!歡樂的時光總是過得特別快,又到時候和大家講拜拜!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章