壹 ❀ 引html
初学angularjs的同窗对于$scope必定不会陌生,scope(做用域)是将view(视图)与model(模板)关联起来的桥梁,经过controller(控制器)对于model的数据操做,咱们能轻易实现双向绑定,这是一个简单的例子:angularjs
<body ng-controller="myCtrl"> <input type="text" ng-model="name"> <div>{{name}}</div> </body>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { $scope.name = '听风是风'; });
随着对于angularjs的深刻学习,咱们知道原来在angularjs版本1.2以后,数据除了绑定scope还能绑定this上,像这样:segmentfault
<body ng-controller="myCtrl as vm"> <input type="text" ng-model="vm.name"> <div>{{vm.name}}</div> </body>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { this.name = '你们好,我是听风是风'; });
从视觉角度来看,this好像也达到了scope的做用,那它两真的就等同吗?两者有什么区别呢?在第二个例子中,myCtrl as vm又是什么意思?本文就此展开探讨。函数
贰 ❀ controller as作了什么性能
若是只是将数据绑定在this上,ng-controller不使用ctrl as的写法,你会发现this上的数据在视图中是没法被识别的。咱们都知道控制器controller是一个构造函数,这里的controller as vm其实就是实例化了一个叫vm的实例而已,相似于这样:学习
class myCtrl { constructor() { this.name = '听风是风'; }; sayName() { console.log(this.name); } } let vm = new myCtrl(); vm.sayName() //听风是风
这也是为何非得经过vm才能访问controller控制器中this属性的缘由;另外,as vm的vm也只是一个实例名而已,随便你取什么名字都是OK的,并非硬性要求。ui
叁 ❀ $scope与this有何区别this
1.含义不一样:spa
每一个控制器controller都有一个关联的$scope对象,控制器(构造函数)负责在其关联的做用域($scope)上设置模型(model)属性和行为。而视图只能访问在此对象和父做用域对象($scope)上定义的属性方法。3d
而this就有点不一样,了解Javascript的同窗都知道,this指向实际上是一个不太肯定的东西,在你不知道this直接调用者是谁,你也没法判断this指向谁,在angular中也是如此。
在angular中当你调用控制器的构造函数时,this就会指向控制器,好比前面咱们提到ctrl as vm。而当你调用$scope上的方法时,this指向当前控制器的有效做用域。
<body ng-controller="myCtrl as vm"> <button ng-click="vm.demo1()">ctrl的this</button> <button ng-click="demo2()">scope的this</button> <button ng-click="demo3()">$scope中的this就是当前做用域</button> </body>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { this.demo1 = function () { console.log(this); }; $scope.demo2 = function () { console.log(this); }; $scope.demo3 = function () { console.log(this === $scope); }; });
上述例子中,咱们分别将方法绑定在this上与$scope上分别输出this,以及判断绑定在$scope时this是否等同于当前控制器的做用域,根据结果咱们也验证了前面的结论,this可能等于当前scope,也可能不等于。
固然通常状况下,咱们会认为this和$scope不是同一个东西,在咱们使用ctrl as vm时,其实只是在$scope中添加了一个key名为vm的对象属性:
<body ng-controller="myCtrl as vm"> </body>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { this.name = '听风是风'; this.sayName = function () { console.log(1); }; console.log($scope); });
因此虽然this可能会等于$scope,但实例vm始终不会等于当前$scope,这点须要注意。另一提的是在controller中常有使用let vm = this的作法,vm与this的关系也跟this指向有关,以下:
angular.module('myApp', []) .controller('myCtrl', function ($scope) { let vm = this vm.demo1 = function () { console.log(this === vm); // true }; $scope.demo3 = function () { console.log(this === $scope); // true console.log(vm === $scope); // false console.log(vm, this); // {demo1: ƒ} ChildScope{...} }; });
2.做用范围不一样
若是说$scope已经能解决平常开发需求,那为什么还要推出新的ctrl as vm的写法呢,其主要的一点,就是为了解决scope继承致使做用域混乱的问题。在下面的例子中,即便子做用域没有声明name属性,同样能继承来自父做用域的name:
<body ng-controller="parentCtrl"> <span>{{name}}</span> <div ng-controller="childCtrl"> <span>{{name}}</span> <span>{{age}}</span> </div> </body>
angular.module('myApp', []) .controller('parentCtrl', function ($scope) { $scope.name = '听风是风'; }) .controller('childCtrl', function ($scope) { $scope.age = 26; });
在代码结构比较复杂的状况下,你每每很难区分这个name属性来自于哪里,而ctrl as正好解决了这个问题,下面的例子相较上方是否是看着更清晰呢:
<body ng-controller="parentCtrl as parent"> <span>{{parent.name}}</span> <div ng-controller="childCtrl as child"> <span>{{parent.name}}</span> <span>{{child.age}}</span> </div> </body>
angular.module('myApp', []) .controller('parentCtrl', function ($scope) { this.name = '听风是风'; }) .controller('childCtrl', function ($scope) { this.age = 26; });
肆 ❀ 使用this与$scope的坑
在介绍完this与$scope的区别后,在平常开发中什么时候使用$scope与this也有些注意的地方,这里我列举两处你们可能会忽略的点:
1.directive中scope属性为true时$scope与this表现不一样
咱们都知道在自定义指令directive开发中,提供了一个scope属性,值分为false(不建立做用域),true与(建立做用域但不隔离)一个对象{}(建立隔离做用域)。
值为false的表现为,子会继承父做用域的属性,不管父子谁修改此属性,双方都会同步;
true的表现为,子会继承父做用域的属性,但只有修改父时子会同步,经过子修改此属性,父并不会改变。{}表示子建立隔离做用域,即子不会继承父任何属性。
上面三种状况的描述其实都是值绑定在$scope上的状况,若是值绑定在this上,scope值为false或{}时,$scope.name与this.name表现一致,惟独scope值为true时,若是你将值绑定在this上,修改子也会影响到父,直接看个例子:
<body ng-controller="myCtrl as vm"> scope: <input type="text" ng-model="name1"><br> this: <input type="text" ng-model="vm.name2"> <div echo></div> </body>
angular.module('myApp', []) .controller('myCtrl', function ($scope) { let vm = this $scope.name1 = '时间跳跃'; vm.name2 = '听风是风'; }) .directive('echo', function () { return { restrict: 'EACM', scope: true, replace: true, template: '<div>scope:<input type="text" ng-model="name1"></br>this:<input type="text" ng-model="vm.name2"></div>', } })
其实仔细一想,咱们原本就是在设置directive的scope继承方式,this不符合这个规则也是情理之中,那为何咱们还能在子做用域使用父做用域中this的值呢,在子中输出一下$scope就明白了:
在子做用域中经过$parent访问父做用域,能够看到vm对象做为父做用域中的一条属性存在,子修改父属性,相似浅拷贝的道理,让父也发生了改变。
2.directive中require只能访问controller中绑在this上的属性方法
咱们知道自定义指令的require属性能将其余指令的controller注入到自身,这样就能够直接使用其它指令controller中定义过的方法属性,但前提是这些方法属性是定义在this上,而非$scope上:
<body ng-controller="myCtrl as vm"> <div echo></div> </body>
angular.module('myApp', []) .controller('myCtrl', function ($scope) {}) .directive('echo', function () { return { restrict: 'EACM', template: '<span><echo1></echo1></span>', controller: function ($scope) { $scope.name = '听风是风'; this.sayName = function (name) { console.log('个人名字是' + name); } } } }) .directive('echo1', function () { return { restrict: 'EACM', require: '^echo', link: function (scope, ele, attr, ctrl) { console.log(ctrl); } } })
能够看到在指令echo1中link函数的第四个参数ctrl只能访问到sayName方法,致使这个状况的缘由是在angularjs源码中,require所作的操做也是实例化了一个控制器实例,非this属性都没法添加到实例上,这一点也是在自定义指令开发中须要注意的。
伍 ❀ 总
那么到这里,咱们了解了ctrl as这种写法的含义,而且知道了angualrjs中$scope与this的区别,this可能与$scope相等,当使用ctrl as vm时,vm只是成为了$scope中的一条属性,因此vm与$scope永远不相等。
咱们还了解了在自定义指令开发中,为scope与this添加值时会带来不一样的影响,若是你对于angular 自定义指令开发有兴趣,欢迎阅读博主 angularjs 一篇文章看懂自定义指令directive 这篇文章。
另外我看了一眼文章配图中标志性的摩托车,才反应过来这是电影阿基拉的同人做品,里面的两我的物分别是男主金田正太郎与男二女朋友香织(男二帽子戴好..),这辆摩托在电影头号玩家中也有做为彩蛋出现,那么到这里,本文结束。
参考
'this' vs $scope in AngularJS controllers